[Haskell-cafe] Re: Re: Re: implementing recursive let

Ryan Ingram ryani.spam at gmail.com
Fri Nov 27 21:31:16 EST 2009

On Fri, Nov 27, 2009 at 1:40 PM, Ben Franksen <ben.franksen at online.de> wrote:
> Thanks, you are confirming what I suspected. I just wasn't sure that I
> didn't do something stupid that could easily be fixed.

Well, lets unwrap your newtype into the actual functions:

Eval (ErrorT String (StateT Env (Writer [String])) a)

ErrorT e m a ~= m (Either e a)
StateT s m a ~= s -> m (a,s)
Writer w a ~= (a,w)

So we have

Eval a
  ~= ErrorT String (StateT Env (Writer [String])) a)
  ~= StateT Env (Writer [String])) (Either String a)
  ~= Env -> Writer [String] (Either String a, Env)
  ~= Env -> ((Either String a, Env), [String])

Also I notice you really only use Eval Value; everything else is just
minor side effects.

So this is pretty clear; we are given an environment, and we need to
return another environment, a list of strings, and either an error
message or a Value.

Now the question is, what do you want to happen when given a malformed
let expression?  I am pretty sure that you need more complicated
flow-control here in order to get the result.  I believe you are on
the right track with continuations.

Here is a question; what should these expressions do?
> let y = x; x = 1 in y
> let y = x x; x = 1 in x
> let x = x in x

The last one is quite telling; I can see three possible behaviors here:

1) Loop
2) return some simple undefined value
3) Give an error "blackhole"

I will note that behavior (1) seems very difficult to achieve with
your current monad stack; eval (Var x) terminates simply by looking up
the value in the environment.

I think you need to think hard about evaluation order and decide what
you really want to happen.  The simplest answer, if you want to stay
with strict evaluation, is probably to only allow recursive *function*
definitions.  This way you can delay fully initializing the
environment until after you've finished evaluating the functions

Also, your definition of "Function" seems to have problems with
scoping; unless you intended to make a dynamically scoped language,
(Value -> Eval Value) seems very likely to get evaluated in the
context it is called in.

  -- ryan

More information about the Haskell-Cafe mailing list