プリミティブ プログラムを評価するコードがいくつかあります。プログラムは、ステートメント (式、ブロック、return ステートメント) のリストです。評価の結果は、最後に評価された式です。return
また、評価者はステートメントを適切に処理する必要があります(つまり、最初に が発生した後に評価を停止しreturn
ます)。
このロジックを実装するためNextStep
に、現在のステートメントの後に次の評価ステップを作成する特別なコールバック関数 ( ) を渡します。returnステートメントを処理するときに次のステップを呼び出しません:
data Statement =
Expr Int
| Block [Statement]
| Return Int
deriving (Show, Eq)
data Value =
Undefined
| Value Int
deriving (Show, Eq)
type NextStep = Value -> Value
evalStmt :: Statement -> NextStep -> Value
evalStmt (Expr val) next =
let res = Value val
in next res
evalStmt (Block stmts) next = evalBlock stmts next
evalStmt (Return val) next = Value val
evalBlock :: [Statement] -> NextStep -> Value
evalBlock [] next = next Undefined
evalBlock [st] next = evalStmt st next
evalBlock (st:rest) next = evalStmt st $ \ _ -> evalBlock rest next
evalProgram stmts = evalBlock stmts id
prog1 = [Expr 1, Block [Return 3, Expr 2], Expr 4]
evalProg1 = evalProgram prog1 -- result will be Value 3
問題は、このコードを継続モナドでどのように書き直すことができるかということです。および関数で明示的に渡されたNextStep
コールバックを取り除きたいです。出来ますか?evalStmt
evalBlock