[Haskell-cafe] Monad vs ArrowChoice

Ronald Guida oddron at gmail.com
Wed May 14 18:37:38 EDT 2008


I have read that Monad is stronger than Idiom because Monad lets me
use the results of a computation to choose between the side effects of
alternative future computations, while Idiom does not have this
feature.  Arrow does not have this feature either.

ArrowChoice has the feature that the sum type, Either, can be used to
choose between alternative computations, including their side effects.
 I know that Monad is supposed to be stronger than ArrowChoice, but I
have to ask, what exactly can Monad do that ArrowChoice can't do?

Let me set up an example to illustrate where I'm coming from.

> import Control.Monad.Writer
> import Control.Applicative
> import Control.Arrow hiding (pure)

The missileControl function accepts a flag to determine whether
missiles actually get launched, and it returns the number of
casualties.

> missileControl :: Bool -> IO Integer
> missileControl b = do
>  showFlag b
>  casualties <- if b
>                  then launchMissiles
>                  else doNotLaunch
>  return casualties

> showFlag :: Bool -> IO Bool
> showFlag b = (putStrLn $ "Launch flag = " ++ show b) >> return b

> launchMissiles :: IO Integer
> launchMissiles = do
>   putStrLn "Missiles have been launched."
>   putStrLn "Casualties = 6,700,000,000."
>   return 6700000000

> doNotLaunch :: IO Integer
> doNotLaunch = putStrLn "Missiles not launched." >> return 0

If I try to use an Idiom, or even an Arrow, instead of a Monad, then I
don't get to choose between the alternative side effects, and the
results will be similar to this:

> missileControl' :: Bool -> IO Integer
> missileControl' b = do
>   showFlag b
>   casualties <- launchMissiles
>   casualties' <- doNotLaunch
>   if b
>     then return casualties
>     else return casualties'

If I use ArrowChoice, then I can do this:

> missileControl2 :: Bool -> IO Integer
> missileControl2 b = runKleisli a b
>     where a = (Kleisli $ showFlag) >>> (arr boolToEither) >>>
>               ((Kleisli $ const launchMissiles) |||
>                (Kleisli $ const doNotLaunch))

> boolToEither :: Bool -> Either () ()
> boolToEither True = Left ()
> boolToEither False = Right ()

GHCi> missileControl2 True
Launch flag = True
Missiles have been launched.
Casualties = 6,700,000,000.
6700000000

GHCi> missileControl2 False
Launch flag = False
Missiles not launched.
0


More information about the Haskell-Cafe mailing list