[Haskell] Mixing monadic and non-monadic functions

Glynn Clements glynn.clements at virgin.net
Wed Mar 24 12:56:58 EST 2004


ozone at algorithm.com.au wrote:

> >> We'd all love to make the lifting implicit, but no one knows how to 
> >> do it
> >> without breaking the whole language.
> >
> > I've heard people talk about the functional "purity" of Haskell -- 
> > you'd have
> > to break this purity to add implicit lifting?
> 
> I don't think you would break the functional purity of Haskell if you 
> did such a thing, but you'd probably need some new syntax to help out 
> the type system.  Perhaps something like:
> 
>      assertBool "fail" $ length (<somefunc a>) == length (<somefunc b>)
> 
> So here, (<a>) performs the same function as the <- operator, but 
> assigns the result to an "anonymous variable" and is instantly consumed 
> by whatever function uses its value.  Please don't berate me for my 
> choice of syntax, by the way: that was just an example :).
> 
> One problem with this is that you now don't know what order those two 
> operations take place: does "somefunc a" run first, or does "somefunc 
> b" run first?  You have this same problem in other imperative languages 
> too; I'm not sure if, e.g. C defines an order for function evaluation 
> to occur.

C doesn't define the order in which function arguments are evaluated,
so:

	foo(getchar(), getchar());

could be equivalent to either:

	a = getchar();
	b = getchar();
	foo(a, b);
or:
	a = getchar();
	b = getchar();
	foo(b, a);

This isn't restricted to I/O, but affects any operation which has side
effects, e.g.

	foo(++x, ++x);

This is *why* I/O actions aren't treated as functions in pure
functional languages.

Regarding the "solution" of using liftM (liftM2 etc): these impose a
left-to-right evaluation order, e.g.:

liftM2           :: (Monad m) => (a -> b -> c) -> (m a -> m b -> m c)
liftM2 f          = \a b -> do { a' <- a; b' <- b; return (f a' b') }

One consequence of this is that, even if (==) is an equivalence
relation, "liftM2 (==)" may not be, as the order of the arguments is
significant.

More generally, lifted functions may have semantics which differ
greatly from the underlying function. Personally, I'm quite happy that
Haskell doesn't allow this to be hidden by implicit lifting.

-- 
Glynn Clements <glynn.clements at virgin.net>


More information about the Haskell mailing list