Derek Elkins wrote: > On Wed, Nov 25, 2009 at 3:48 PM, Ben Franksen <ben.frank...@online.de> >> What am I missing? > > The problem is the liftM2 in the Let branch of eval. You are > executing the body while making the bindings, so you are trying to > look up x while you are still trying to bind it. One solution is to > move the execution of the body after the binding as in: > > eval (Let decls body) = mdo > let (names,exprs) = unzip decls > updateEnv env = foldr (uncurry M.insert) env $ zip names values > values <- local updateEnv $ mapM eval exprs > local updateEnv $ eval body
I already tried that :( It works for non-recursive expressions like 'example', but not for recursive ones; not even non-recursive ones that merely use a variable before it is defined like this one > example2 = Let [("y", Var "x"),("x", Const 1)] (Var "y") which again makes eval loop. However, if I use your lazy version > eval (Var x) = gets (fromJust . M.lookup x) _or_ remove the ErrorT from the monad stack (see my other message) eval does not loop, even with mutually recursive definitions. *some time later* Ok, it seems I have a version that does what I want. It is not very elegant, I have to manually wrap/unwrap the ErrorT stuff just for the Val case, but at least it seems to work. Here it goes: > eval (Var x) = Eval $ ErrorT $ do > env <- get > v <- case M.lookup x env of > Just v -> return v > Nothing -> do > warning ("reference to undefined variable " ++ show x) > let v = Data "" > modify (M.insert x v) > return v > return (Right v) > > warning s = tell $ ["Warning: " ++ s] I suspect what is needed to avoid this is a combinator that convinces ErrorT that a computation is really going to succeed, no matter what. Hmm, now that I think about it this should be possible using catchError. I will investigate. Cheers Ben _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe