Ho un codice che valuta i programmi primitivi. Il programma è una lista di istruzioni (espressione, blocco, dichiarazione di ritorno). Il risultato della valutazione è l'espressione valutata per ultima. Anche il valutatore dovrebbe trattare correttamente la dichiarazione return
(vale a dire interrompere la valutazione dopo la prima occorrenza di return
).Riscrivente con continuazioni
Per implementare questa logica, passano la funzione di richiamata speciale (NextStep
) che effettua il successivo passaggio di valutazione dopo l'istruzione corrente. Io non chiamo prossimo passo durante la manipolazione istruzione 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
La domanda è: come posso riscrivere questo codice con prosecuzione monade? Voglio eliminare la richiamata esplicita NextStep
nelle funzioni evalStmt
e evalBlock
. È possibile?
L'istanza monad per 'Cont' è definita per concatenare esattamente in questo modo, in modo che * dovrebbe * essere semplicemente equivalente a' evalBlock (st: rest) = evalStmt st >> evalBlock resto' –
@ ØrjanJohansen Giusto! – jozefg