
I'm implementing an interpreter for the lambda calculus augmented with mutable variables. I'm having problems doing the mutable state stuff in Haskell. Here's what I have so far: type Expr = ... terms in the language ... type Value = ... values in the language ... type Ident = String type VarId = String type Env = Map Ident Target data Target = TValue Value | TVar VarId -- idents might refer to values or vars in the store. type Store = Map VarId (Maybe Value) -- Using "Maybe" because vars start out uninitialized. eval :: (Env, Store, Expr) -> (Store, Value) -- The Store is threaded through the evaluator. One problem is that the link between an identifier and it's entry in the store is via VarIds, which are just strings. For example, if I see the identifier "x", I first look it up in the Env, and if it is a "TVar", I then look it up in the store. I'd like to get something stronger (in Java, I would use a pointer). Another problem is that entries in my Store never get garbage collected. Again, if I were using pointers in Java, this wouldn't be an issue. There's also the issue of finding a more elegant way of threading the Store through my evaluator, but I'm not concerned too much about that at this point. I can probably define a state-carrying monad like Parsec. My real concerns are the first two issues. Thanks. - Kannan

On Sun, 2007-12-02 at 03:11 +0000, Kannan Goundan wrote:
I'm implementing an interpreter for the lambda calculus augmented with mutable variables. I'm having problems doing the mutable state stuff in Haskell. Here's what I have so far:
type Expr = ... terms in the language ... type Value = ... values in the language ... type Ident = String type VarId = String
type Env = Map Ident Target data Target = TValue Value | TVar VarId -- idents might refer to values or vars in the store.
type Store = Map VarId (Maybe Value) -- Using "Maybe" because vars start out uninitialized.
eval :: (Env, Store, Expr) -> (Store, Value) -- The Store is threaded through the evaluator.
One problem is that the link between an identifier and it's entry in the store is via VarIds, which are just strings. For example, if I see the identifier "x", I first look it up in the Env, and if it is a "TVar", I then look it up in the store. I'd like to get something stronger (in Java, I would use a pointer).
Another problem is that entries in my Store never get garbage collected. Again, if I were using pointers in Java, this wouldn't be an issue.
There's also the issue of finding a more elegant way of threading the Store through my evaluator, but I'm not concerned too much about that at this point. I can probably define a state-carrying monad like Parsec. My real concerns are the first two issues.
Use ST. First-class state isn't too great unless you specifically want that.

On Sat, 01 Dec 2007 21:22:53 -0600
Derek Elkins
There's also the issue of finding a more elegant way of threading the Store through my evaluator, but I'm not concerned too much about that at this point. I can probably define a state-carrying monad like Parsec. My real concerns are the first two issues.
Use ST. First-class state isn't too great unless you specifically want that.
Or use IO - that way you can use a Hashtable for looking up identifiers. Although, better still is to convert variable references into Ints, instead of using a Hashtable. -- Robin

On Sun, 2007-12-02 at 03:29 +0000, Robin Green wrote:
On Sat, 01 Dec 2007 21:22:53 -0600 Derek Elkins
wrote: There's also the issue of finding a more elegant way of threading the Store through my evaluator, but I'm not concerned too much about that at this point. I can probably define a state-carrying monad like Parsec. My real concerns are the first two issues.
Use ST. First-class state isn't too great unless you specifically want that.
Or use IO - that way you can use a Hashtable for looking up identifiers. Although, better still is to convert variable references into Ints, instead of using a Hashtable.
From what I hear, Data.HashTable is impressively inefficient to the extent that you're better off using Data.Map solely for performance (not to mention it being pure.)

On Sat, 01 Dec 2007 21:22:53 -0600, Derek Elkins wrote:
Use ST. First-class state isn't too great unless you specifically want that.
I did try using ST but ran into a problem because its type variable (s) ended up invading all of my types. -- Target needs 's' because of the STRef data Target s = TValue Value | TVar (STRef s (Maybe Value)) -- Env needs 's' because Target needs 's' type Env s = Map Ident (Target s) -- Value needs 's' because closures are values and closures -- have an Env. data Value s = VUnit | VClosure (Env s) Ident Expr The main thing I didn't like was that 'Value' had a type parameter. I didn't follow the ST option much past this point. But maybe there's a better way to use ST? Will existential types help me? - Kannan

On Sun, Dec 02, 2007 at 03:54:05AM +0000, Kannan Goundan wrote:
On Sat, 01 Dec 2007 21:22:53 -0600, Derek Elkins wrote:
Use ST. First-class state isn't too great unless you specifically want that.
I did try using ST but ran into a problem because its type variable (s) ended up invading all of my types.
That's just ST ugliness, the price you have to pay for a pure runST. If you're doing almost everything in ST, it can be cleaner just to use IORefs. Stefan
participants (4)
-
Derek Elkins
-
Kannan Goundan
-
Robin Green
-
Stefan O'Rear