A monad with a "real" return function

A common beginner's mistake is to see return and think that it's a language keyword that exits the current function with a return value. Of course, we know that isn't what it does at all. But I wonder... could we actually make such a function? Purely for argument's sake, at this point.

It seems we're looking for some monad Foo which possesses a function

exit :: x -> Foo x

which will abort the rest of the computation and immediately return x .

Is such a thing constructable? If it could be constructed, would it be useful? Is this even a sane thing to attempt to do?


Yes, it is possible in the Cont monad. The Cont is defined as follows:

newtype Cont r a = Cont {runCont :: (a -> r) -> r}

instance Monad (Cont r) where
    return a = Cont ($ a)
    m >>= k = Cont $ c -> runCont m $ a -> runCont (k a) c

Now we can create exit as follows:

exit = Cont . const

In fact you can do it in almost any monad (for example you could do it in the Either monad but not in the State monad). However the Cont monad is the mother of all monads: http://blog.sigfpe.com/2008/12/mother-of-all-monads.html


Of course it's doable. It's even already in the standard libraries. You just need a slightly saner type signature.

import Control.Monad

exit :: a -> Either a b
exit = Left

main = print $ do
    x <- Right 5
    exit "foo"
    error "this is a good place to crash"

The important thing to note is that the type given when bailing out isn't free - it has to match the type of the Either.


It appears you can just about implement this:

data Foo e x =
  Next x |
  Done e

instance Monad (Foo e) where
  return = Next

  (Next x) >>= f = f x
  (Done e) >>= f = Done e

exit :: e -> Foo e x
exit = Done

run :: Foo x x -> x
run (Next x) = x
run (Done x) = x

Notice how the monad has an extra type parameter; I don't think it's possible to avoid this. Basically Foo ex produces an x and will "ultimately" produce an e . Note that the run function requires both types to match; you could equally demand that run only works if exit gets called somewhere, or one of a few other possibilities...

So, yes you can construct this, and no, it's not especially useful AFAIK.

链接地址: http://www.djcxy.com/p/43364.html

上一篇: Haskell中Monad和Applicative的区别

下一篇: 具有“真实”返回功能的monad