Ich habe Code, der primitive Programme auswertet. Programm ist eine Liste von Anweisungen (Ausdruck, Block, Return-Anweisung). Ergebnis der Bewertung ist der zuletzt ausgewertete Ausdruck. Auch der Bewerter sollte die Anweisung return
richtig behandeln (d. H. Die Bewertung nach dem ersten Auftreten von return
stoppen).Code mit Fortsetzungen umschreiben
Um diese Logik zu implementieren, gebe ich spezielle Callback-Funktion (NextStep
), die nächsten Auswertungsschritt nach der aktuellen Anweisung machen. Ich nenne nicht im nächsten Schritt, wenn return-Anweisung Handhabung:
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
Die Frage, wie ist, kann ich diesen Code mit Fortsetzung Monade umschreiben? Ich möchte explizit NextStep
Rückruf in evalStmt
und evalBlock
Funktionen übergeben werden. Ist es möglich?
Die Monad-Instanz für 'Cont' ist so definiert, dass sie genau so verkettet ist, dass * sollte * einfach äquivalent sein muss zu: evalBlock (st: rest) = evalStmt st >> evalBlock Rest' –
@ ØrjanJohansen Ganz richtig! – jozefg