We next look at evaluating statements,
assuming that we have Expr as before by minus the Let expression.
We will do so be examining the evaluation of the small statement language we created when introducing intrinsically-typed statements.
data Stmt : (he : HowEnds)
-> (ctxt : SnocList Ty)
-> (type : Ty)
-> Type
where
Stop : Stmt STOP ctxt type
Return : (expr : Expr ctxt type)
-> Stmt RETURN ctxt type
Let : (expr : Expr ctxt typeV)
-> (kont : Stmt he (ctxt :< typeV) typeK)
-> Stmt he ctxt typeK
If : (expr : Expr ctxt BOOL)
-> (tt : Stmt a ctxt type)
-> (ff : Stmt b ctxt type)
-> (kont : Stmt c ctxt type)
-> Stmt c ctxt type
I overload function names quite a bit in Idris programs,
and use namespace disambiguation to make things look nice.
You will see all operations for expressions and statements having the same name.
Dealing with (Potentially Early) Returns and Stoppages
A difference between executing statements and expressions is that statements may return early. We cannot write an evaluation function that just returns values, they may return nothing.
So our statement’s evaluation function will return Maybe (Value type):
eval : (env : Env ctxt)
-> (stmt : Stmt he ctxt type)
-> Maybe (Value type)
We know that statements either stop or return a value,
and indexing the type of statements with HowEnds ensures that a statement will return some thing.
However,
not all computation flows through the continuation,
branches for conditionals (or while loops) may return early.
We can calculate statically, when sub-branches may return early or stop computing. We cannot know statically which branch will be taken, it is a runtime decision. Which means we cannot use the static information to know what is being returned when executing statements. This will impact how we execute methods, which we will explore later.
Evaluating Statements
As with our expression language, our statements may produce a value.
Given Stmt as defined above,
let us walk through its evaluation.
We repeat the type signature to save scrolling.
eval : (env : Env ctxt)
-> (stmt : Stmt he ctxt type)
-> Maybe (Value type)
Leaf Terms
For each branch in our statement we need to follow them to either a Stop,
returning Nothing,
or evaluated the (early) return which is Just a value.
eval env Stop
= Nothing
eval env (Return expr)
= let v = Expr.eval env expr
in Just v
Let-Bindings
Let-bindings are the same as we saw with expressions.
eval env (Let expr kont)
= let v = evalE env expr
in eval (env :< v) kont
Conditionals
Conditional statements, generally any statement with branches, are ones we must take care to inspect the result of evaluation.
After evaluating the condition, we need to determine if the results was true or not. If the result was true, we can then execute the true branch. If the true branch stops, we can then evaluate the continuation. Otherwise we return early. The false branch is the same.
eval env (If expr tt ff kont)
= case Expr.eval env expr of
(VB True)
=> case eval env tt of
Nothing => eval env kont
(Just v) => Just v
(VB False)
=> case eval env ff of
Nothing => eval env kont
(Just v) => Just v
Our realisation of the dynamics for conditionals differs from the formal description. The reason is that we have an inductive syntax and we are coalescing the rules for sequencing and conditionals.
The exercises from
intrinsic statements
asked you to extend Stmt with while-loops and single branch conditional.
Use that version of Stmt to extend evaluation of statements.