[Haskell] Mixing monadic and non-monadic functions
Duncan Coutts
duncan at coutts.uklinux.net
Tue Mar 23 23:57:55 EST 2004
On Tue, 2004-03-23 at 15:29, Sean E. Russell wrote:
> Here's my base case:
>
> someFunc :: String -> IO [a]
> ...
> ax <- someFunc a
> bx <- someFunc b
> assertBool "fail" $ length ax == length bx
>
> I don't like the assignments; the typing is redundant, if I have a lot of
> asserts like this, and the "variables" are temporary. What I'd much rather
> have is:
>
> ...
> assertBool "fail" $ (length $ someFunc a) == (length $ someFunc b)
>
> which is more readable, to my eye.
>
> The only solution which has been suggested that may work is liberal use of the
> liftM variants, but this gets *really* tedious and obtuse.
>
> Is there an elegant way to do what I want to do, or am I stuck with
> procedural-style assignments and bunches of temp vars?
For a project I did which involved a lot of monadic code I used some
combinators which allow you to write in a more applicative/functional
style but still thread the monad state through everything.
Basically instead of writing:
do
a' <- foo a
b' <- foo b
c' <- foo c
return $ f a' b' c'
you write:
f $> foo a <$> foo b <$> foo c
Unfortunately it doesn't work so well with infix operators, you'd have
to say (==) $> firstThing <$> secondThing
which is not quite so appealing.
Your example would look like so:
assertBool "fail" <$$> (==) $> (length $> someFunc a) <$> (length $> someFunc b)
Here's the little combinator library, it's really just a matter of using
infix versions of standard monad functions and playing with their
left/right associativity and precedence.
import Monad (liftM, ap)
infixl 1 $>, <$> --same as liftM & ap, but left associative infix
infixr 0 <$$> --same as =<<, but different precedence
($>) :: Monad m => (a -> b) -> (m a -> m b)
($>) = liftM
(<$>) :: Monad m => m (a -> b) -> (m a -> m b)
(<$>) = ap
(<$$>) :: Monad m => (a -> m b) -> (m a -> m b)
(<$$>) = (=<<)
--
Duncan
More information about the Haskell
mailing list