
Ryan Ingram wrote:
The problem is that ErrorT makes any argument to mdo *much* more strict, and therefore much more likely to loop.
This is because each action needs to know whether the previous action was successful before it can continue.
Thanks, you are confirming what I suspected. I just wasn't sure that I didn't do something stupid that could easily be fixed.
Notice that when you got it to work, you *always* return "Right v"; that is, you never actually have an error.
Yes, exactly. It helps in the simplest cases, but with function definitions even this is not enough.
If you want to avoid introducing bottoms into your code, I would avoid using fix/mdo except in cases where you can prove that the code is non-strict. You keep running into cases where your code is more strict than you would like which is introducing the bottoms.
To understand this better, consider the following function:
fixEither :: (a -> Either e a) -> Either e a fixEither f = x where x = f a (Right a) = x
Here, f *cannot* attempt to do anything with its argument until it is absolutely known that f is returning a "Right" value.
Interesting. I'll have to think about this one.
Perhaps there is a different way to write this interpreter that avoids needing to tie the knot so tightly? Can you split recursive-let into two stages, one where you construct the environment with dummy variables and a second where you populate them with the results of their evaluations? You might need some sort of mutable thunk that you can store in the environment, which makes sense to me; in GHC Core, "let" means "allocate a thunk on the heap".
Yea, this is how I would do it in an imperative language. I thought I could avoid mtuable cells by exploiting lazyness. I am not yet ready to give up, however. One thing I want to try is whether I can come up with a variation of ErrorT that is less strict. Another idea I just had is that maybe continuations might help, as they provide a possibility to 'jump' out of a calculation. Chers Ben