Re:Write Yourself a Scheme in 48 Hours
by tel on Friday March 27, 2015 @11:09AM
(#9276708)
Typically you want to talk about a function like
eval :: Syntax -> Semantics
In Scheme `Syntax` is some kind of tree-like Sexpr thing or possibly a more well-defined AST. So let's focus on `Semantics` instead.
Ultimately, a perfectly fine semantics is `IO ()`. As Haskell's "sin bin", `IO` circumscribes all of the effects you need. So, the entirety of this game is to capture as much effect as you can "purely" so that it is reflected intelligently in the type.
The key pure semantic component for managing changing state is to focus on "changes" instead of points in state space. This we need a notion of the initial state (the empty env) and then a series of functions
Env -> Env
If we let `Semantics = Env -> Env` then we've already captured a meaningful chunk of Scheme semantics purely. We cannot observe Scheme side effects---they would have to be faked and thrown away---but we can observe how the env evolves. To be a bit more clear, this eval "respects" the syntax properly---if `seq :: Syntax -> Syntax -> Syntax` sequences two Sexprs then
e.g. sequencing of syntax is just function composition in the "Env transformer semantics".
So that's how we avoid IORefs.
From here we just build more. Another fun thing to add would be input and output. Here we note that any given Syntactic fragment no longer merely transforms Envs but may also either attempt to print out some text or want to read it in.
data Print e = Simple e | Read (Text -> e) | Write (Text, e)
type Semantics = Env -> Print Env
Ultimately, a perfectly fine semantics is `IO ()`. As Haskell's "sin bin", `IO` circumscribes all of the effects you need. So, the entirety of this game is to capture as much effect as you can "purely" so that it is reflected intelligently in the type.
The key pure semantic component for managing changing state is to focus on "changes" instead of points in state space. This we need a notion of the initial state (the empty env) and then a series of functions
If we let `Semantics = Env -> Env` then we've already captured a meaningful chunk of Scheme semantics purely. We cannot observe Scheme side effects---they would have to be faked and thrown away---but we can observe how the env evolves. To be a bit more clear, this eval "respects" the syntax properly---if `seq :: Syntax -> Syntax -> Syntax` sequences two Sexprs then e.g. sequencing of syntax is just function composition in the "Env transformer semantics".So that's how we avoid IORefs.
From here we just build more. Another fun thing to add would be input and output. Here we note that any given Syntactic fragment no longer merely transforms Envs but may also either attempt to print out some text or want to read it in.
and now we'd expect things like