Can't you do automatic lifting with a "Runnable" class:

   class Runnable x y where
      run :: x -> y

   instance Runnable (m a) (m a) where
       run = id

   instance Runnable (s -> m a) (s -> m a) where
       run = id
instance (Monad m,Monad n,MonadT t m,Runnable (m a) (n a)) => Runnable (t m a) (n a) where
       run = run . down

instance (Monad m,MonadT t m,Monad (t m)) => Runnable (t m a) (m a) where
       run = down

Where:

   class (Monad m,Monad (t m)) => MonadT t m where
      up :: m a -> t m a
      down :: t m a -> m a

For example for StateT:

   downST :: Monad m => StateT st m a -> (st -> m a)
   downST m = \st -> do
           (_,a) <- runST m st
           return a

   downST' :: Monad m => (b -> StateT st m a) -> (st -> b -> m a)
   downST' m = \st b -> do
           (_,a) <- runST (m b) st
           return a


instance (MonadState st (StateT st m),Monad m,Monad n,Runnable (st -> m s) (st -> n s)) => Runnable (StateT st m s) (st -> n s) where
           run = run . downST

instance (MonadState st (StateT st m),Monad m) => Runnable (StateT st m s) (st -> m s) where
       run = downST

Keean.

Frederik Eaton wrote:

Hi,

Sean's comment (yeah, it was like a billion years ago, just catching
up) is something that I've often thought myself.
I want the type system to be able to do "automatic lifting" of monads,
i.e., since [] is a monad, I should be able to write the following:

[1,2]+[3,4]

and have it interpreted as "do {a<-[1,2]; b<-[3,4]; return (a+b)}".

Also, I would have

Reader (+1) + Reader (+4) == Reader (\x -> 2*x+5)

The point I want to make is that this is much more general than IO or
monads! I think we all understand intuitively what mathematicians mean
when they add two sets

{1,2}+{3,4}      (i.e. { x+y | x\in {1,2}, y\in {3,4}})

or when they add functions
(f+g)(x)         where f(x)=x+1 and g(x)=x+4

So "automatic lifting" is a feature which is very simple to describe,
but which gives both of these notations their intuitive mathematical
meaning - not to mention making monadic code much tidier (who wants to
spend their time naming variables which are only used once?). I think
it deserves more attention.

I agree that in its simplest incarnation, there is some ugliness: the
order in which the values in the arguments are extracted from their
monads could be said to be arbitrary. Personally, I do not think that
this in itself is a reason to reject the concept. Because of currying,
the order of function arguments is already important in Haskell. If
you think of the proposed operation not as lifting, but as inserting
`ap`s:

return f `ap` x1 `ap` ... `ap` xn

then the ordering problem doesn't seem like such a big deal. I mean,
what other order does one expect, than one in which the arguments are
read in the same order that 'f' is applied to them?

Although it is true that in most of the instances where this feature
would be used, the order in which arguments are read from their monads
will not matter; yet that does not change the fact that in cases where
order *does* matter it's pretty damn easy to figure out what it will
be. For instance, in

print ("a: " ++ readLn ++ "\nb: " ++ readLn)

two lines are read and then printed. Does anybody for a moment
question what order the lines should be read in?

Frederik



On Tue, Mar 23, 2004 at 12:55:56PM -0500, Sean E. Russell wrote:
On Tuesday 23 March 2004 11:36, Graham Klyne wrote:
I think you're a rather stuck with the "temporary variables" (which they're
not really), but it might be possible to hide some of the untidiness in an
auxiliary monadic function.
That seems to be the common suggestion: write my own visitors.

I'm just surprised that there isn't a more elegant mechanism for getting interoperability between monadic and non-monadic functions. The current state of affairs just seems awkward.
[Warning: quasi-rant]

Caveat: I'm not smart enough, and I don't know enough, to criticize Haskell, so please don't misconstrue my comments. To quote Einstein: "When I'm asking simple questions and I'm getting simple answers, I'm talking to God." I simply mistrust, and therefore question, systems where simple things are overly involved.

The standard explaination about why monads are so troublesome always sounds like an excuse to me. We have monads, because they allow side-effects. Ok. If programs that used side effects were uncommon, I'd be fine with them being troublesome -- but they aren't. Maybe it is just me, but my Haskell programs invariably develop a need for side effects within a few tens of lines of code, whether IO, Maybe, or whatnot. And I can't help but think that language support to make dealing with monads easier -- that is, to integrate monads with the rest of the language, so as to alleviate the need for constant lifting -- would be a Good Thing.

Hmmm.  Could I say that Haskell requires "heavy lifting"?

--
### SER ### Deutsch|Esperanto|Francaise|Linux|XML|Java|Ruby|Aikido ### http://www.germane-software.com/~ser jabber.com:ser ICQ:83578737 ### GPG: http://www.germane-software.com/~ser/Security/ser_public.gpg



_______________________________________________
Haskell mailing list
Haskell@haskell.org
http://www.haskell.org/mailman/listinfo/haskell



_______________________________________________
Haskell mailing list
Haskell@haskell.org
http://www.haskell.org/mailman/listinfo/haskell

Reply via email to