
G'day all. On Tue, May 20, 2003 at 10:10:24AM -0700, Iavor Diatchki wrote:
actually i disagree with this quite strongly :-) ideally i want no lifts in my program. things like: lift $ lift $ lift $ raise "error" are, well, annoying.
Of course you want no lifts in your program. What you should have written instead is something like this: myLiftToError = lift . lift . lift myRaise = myLiftToError . raise I agree that client code which uses your particular stack of monad transformers shouldn't have to know what order the transformers are stacked in, but even more so, they shouldn't have to even know what the transformers _are_. If it's that complex, it should be abstract.
now all the lifts need to be changed.
If the lift operations were abstract, you would only need to change at most N of them, where N is the number of stacked transformers, and even then it would only be in one place.
and besides if one has 1 of each transformer the whole "lift" thing is pointless as there is no ambiguity as to what you mean (i.e. put clearly refers to the state transformer wherevr it is).
Not if there's an RWS transformer somewhere else on the stack. I understood that the main reason for the typeclasses was that there may be more than one reasonable implementation of a given interface.
when there is more than one copy of a transformer things are different. then some sort of addressing is necessary, which is what motivated adding the "indexes" to my library. they work quite well, but i still think there must be a better way to achieve the same effect...
I'm curious how these indexes work. There are many situations where I need a little extra state/nondeterminism/whatever for a small part of my code, and for that, stacking on an extra transformer can do the trick nicely. Does this upset the scheme that you use for indexing?
unfortunatelly i can't quite capture this commonality with a single instance. perhaps (as bellow) overlapping instances (in some form) could help.
Overlapping instances may help reduce the quadratic complexity, and if it could be done right (i.e. if the Haskell implementation can be trusted to pick the correct instance), I might be happy with that as a compromise. That way I can just do this: instance (MonadNondet m, MonadTrans t) => MonadNondet (t m) where msolutions = lift . msolutions mcommit = lift . mcommit and trust that the highest MonadNondet instance is picked.
actually the library can be generalized there. in my library i have a class:
class (Monad m, Monad n) => HasBase m n | m -> n where inBase :: n a -> m a
That's an excellent idea. As a random thought, there may be an argument for incorporating stToIO and/or ioToST in here too. Cheers, Andrew Bromage