So what's so special about the return keyword?
Firstly, return
is not a keyword in Haskell. It is an overloaded function.
Its type is given by:
class Monad m where
-- | Sequentially compose two actions, passing any value produced
-- by the first as an argument to the second.
(>>=) :: m a -> (a -> m b) -> m b
-- | Inject a value into the monadic type.
return :: a -> m a
So you see that return
is a function that given a value of type a
, returns a new value of type m a
, where m
is some type that is an instance of Monad
. Such types include:
- Monad
[]
- Monad
I0
- Monad
Maybe
- Monad
STM
- Monad
((->) r)
- Monad
(Either e)
- Monad
(ST s)
and many more besides. Instances of 'Monad' should satisfy the following laws:
> return a >>= k == k a
> m >>= return == m
> m >>= (x -> k x >>= h) == (m >>= k) >>= h
The implementation of a function a -> m a
is pretty easy to guess. Here's the definition for the most common monads:
Lists:
return x = [x]
Maybe
return x = Just x
So you see that the return
is an overloaded function that "lifts" a value into a monadic wrapper. You can thus use it anywhere you can use its definition. E.g.
Prelude> 1 : return 2
[1,2]
or in the do
notion (useful when chaining expressions).
> do v <- return 7 ; return v :: Maybe Int
Just 7
The real reason to use a monadic return
is when composing multiple values in some monad:
Prelude> do x <- return 1 ; y <- return 2 ; return (x + y) :: Maybe Int
Just 3
Prelude> do x <- Nothing ; y <- return 2 ; return y
Nothing
In the last statement you see how the chain short-circuited once it hit a zero value for the given monad. In this case Nothing
.
Summary: return
is an overloaded function that lifts a value into a monadic wrapper. You use it when you need to lift values. It is not a control-flow keyword, as it is in imperative languages.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…