I've unsuccessfully looked everywhere for a definition/description of this. While I was Haskell Programming from First Principles , in the monads intro chapter (pg. 763), it showed this example of a nested case statement:
mkSphericalCow :: String -> Int -> Int -> Maybe Cow
mkSphericalCow name' age' weight' =
case noEmpty name' of
Nothing -> Nothing
Just nammy ->
case noNegative age' of
Nothing -> Nothing
Just agey ->
case noNegative weight' of
Nothing -> Nothing
Just weighty ->
weightCheck
(Cow nammy agey weighty)
It said that it could be replaced by:
mkSphericalCow' :: String -> Int -> Int -> Maybe Cow
mkSphericalCow' name' age' weight' = do
nammy <- noEmpty name'
agey <- noNegative age'
weighty <- noNegative weight'
weightCheck (Cow nammy agey weighty)
How in the world does this work!? What is this called? The closest I could find is this answer , which describes it as "monadic notation".
A do
expression is desugared to a chain of >>=
functions. The Haskell report describes how to desugar do
expressions. In your case, it means the expression is desugared to:
mkSphericalCow' :: String -> Int -> Int -> Maybe Cow
mkSphericalCow' name' age' weight' = noEmpty name' >>= (\nammy -> noNegative age' >>= (\agey -> nonNegative weight' >>= (\weighty -> weightCheck (Cow nammy agey weighty))))
For Maybe
the instance of Monad
is implemented as [src] :
instance Monad Maybe where (Just x) >>= k = kx Nothing >>= _ = Nothing
A Maybe
can be seen as the result of a computation that can fail. The Nothing
is the result of a computation that failed, and Just …
as the result of the computation wrapped in a Just
data constructor.
The instance of Monad
enabes one to "chain" such computations. This means it will only return a Just …
if all computations are successful (return a Just …
). So in your expression:
mkSphericalCow' :: String -> Int -> Int -> Maybe Cow
mkSphericalCow' name' age' weight' = do
nammy <- noEmpty name'
agey <- noNegative age'
weighty <- noNegative weight'
weightCheck (Cow nammy agey weighty)
So if one or more of the functions nonEmpty name'
, nonNegative age'
, nonNegative weight'
and weightCheck (Cow nammy agey weighty)
returns Nothing
, the entire do
block will evaluate to Nothing
. The left side of the <-
arrow is the result of the computation where the Just
is unwrapped. This unwrapping is done on the instance of the Monad
where we see (Just x) >>= k = …
, where the Just
data constructor is thus unwrapped, and x
is used as parameter to the k
function.
You can here make it more convenient by writing it as:
mkSphericalCow' :: String -> Int -> Int -> Maybe Cow
mkSphericalCow' name' age' weight' = () >>= weightCheck
Here we make use of the Functor
and Applicative
instance of Maybe
where we thus will generate a Maybe Cow
, that is a Just (Cow abc)
given Just a = noEmpty name'
, Just b = noNegative age'
, Just c = noNegative weight'
. Then we thus make use of the >>=
function to unwrap the Just
data constructor and pass the value wrapped in the Just
to the weightCheck
.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.