Say I've written the following amazin piece of code:
func = do
a <- Just 5
return a
It's pretty pointless, I know. Here, a is 5, and func returns Just 5.
Now I rewrite my awesome (yet pointless) function:
func' = do
a <- Nothing
return a
This function returns Nothing, but what the heck is a? There's nothing to extract from a Nothing value, yet the program doesn't whine when I do something like this:
func'' = do
a <- Nothing
b <- Just 5
return $ a+b
I just have a hard time seeing what actually happens. What is a? In other words: What does <- actually do? Saying it "extracts the value from right-side and binds it to the left-side" is obviously over-simplifying it. What is it I'm not getting?
Thanks :)
Let's try and desugar the do-notation of that last example.
func'' = Nothing >>= (\a -> Just 5 >>= (\b -> return $ a+b))
Now, let's see how >>= is defined for Maybe. It's in the Prelude:
instance Monad Maybe where
(Just x) >>= k = k x
Nothing >>= k = Nothing
return = Just
fail s = Nothing
So Nothing >>= foo is simply Nothing
The answer lies in the definition of the Monad instance of Maybe:
instance Monad Maybe where
(Just x) >>= k = k x
Nothing >>= _ = Nothing
(Just _) >> k = k
Nothing >> _ = Nothing
return = Just
Your func'' translates to:
Nothing >>= (\a -> (Just 5 >>= (\b -> return (a+b))))
From the definition of (>>=) you can see that the first Nothing is just threaded through to the result.
Let's look at the definition of Maybe monad.
instance Monad Maybe where
return = Just
Just a >>= f = f a
Nothing >>= _ = Nothing
And desugar the do-notation in your function:
func' =
Nothing >>= \a ->
return a
The first argument to >>= is Nothing and from the definition above we can see that >>= just ignores the second argument. So we get:
func' = Nothing
Since the function \a -> ... is never called, a never gets assigned. So the answer is: a is not even reached.
As for desugaring do-notation, here's a quick sketch of how it's done (there's one simplification I've made - handling of fail, i.e. patterns that do not match):
do {a; rest} → a >> do rest
Note that >> is usually implemented in terms of >>= as a >>= \_ -> do rest (i.e. the second function just ignores the argument).
do {p <- a; rest} → a >>= \p -> do rest
do {let x = a; rest} → let x = a in do rest
And finally:
do {a} = a
Here's an example:
main = do
name <- getLine
let msg = "Hello " ++ name
putStrLn msg
putStrLn "Good bye!"
desugars to:
main =
getLine >>= \name ->
let msg = "Hello " ++ name in
putStrLn msg >>
putStrLn "Good bye!"
And to make it complete for those who are curious, here's the "right" translation of do {p <- a; rest} (taken directly from Haskell report):
do {pattern <- a; rest} → let ok pattern = do rest
ok _ = fail "error message"
in a >>= ok
Nothing isn't really "nothing", it's actually a possible value of something in the Maybe monad:
data Maybe t = Nothing | Just t
That is, if you have something of type Maybe t for some type t, it can have the value Just x (where x is anything of type t) or Nothing; in this sense Maybe just extends t to have one more possible value, Nothing. (It has other properties because it's a monad, but that doesn't really concern us here, except for the syntactic sugar of do and <-.)
Let's take your example:
func = do
a <- Just 5
return a
Just like in other programming languages you can break this into two pieces correspond to "what's been done up to now" and "what's is yet to be done". For example we can make the break between Just 5 and
a <- ...
return a
In many popular programming languages you expect the Just 5 to be stuffed into the variable a and the code would continue.
Haskell does something different. The "rest of the code" can be thought of as a function describing what you would do with a if you had a value to put in it. This function is then applied to Just 5. But it's not applied directly. It's applied using whatever definition of >>= applies, depending on the type of your expression. For Maybe, >>= is defined so that when dealing with Just X, the "rest of the code" function is applied to X. But it's also defined so that when dealing with Nothing the "rest of the code" function is simply ignored and Nothing is returned.
We can now interpret your other example
func'' = do
a <- Nothing
b <- Just 5
return $ a+b
Break it into Nothing and:
a <- ...
b <- Just 5
return $ a+b
As I say above, this block of code can be thought of a function applied to a possible value of a. But it's being used with Nothing and in this case >>= is defined to ignore the "rest of the code" and just return Nothing. And that's the result you got.
Related
I think I understand how to cascade Monad of the same type. I would like to combine two Monads together to perform an operation based on them :
I think the code below resume the problem : suppose we have a function that validates that a String contains "Jo" and append "Bob" to it if it's the case, and another one that validates that the String length is > 8
The hello function would apply the first , then the second on the result of the first and return "Hello" to all that in case of success or 'Nothing' (I don't know what is this 'Nothing' btw , Left or Nothing) in case of error.
I believe that it's around Monad transformer what I need but I could not find a concise example that would help me to start.
I precise that this is nothing theoratical as there is around Haskell package that works with Either and others that works with Maybe
validateContainsJoAndAppendBob :: String -> Maybe String
validateContainsJoAndAppendBob l =
case isInfixOf "Jo" l of
False -> Nothing
True -> Just $ l ++ "Bob"
validateLengthFunction :: Foldable t => t a -> Either String (t a)
validateLengthFunction l =
case (length l > 8) of
False -> Left "to short"
True -> Right l
-- hello l = do
-- v <- validateContainsJoAndAppendBob l
-- r <- validateLengthFunction v
-- return $ "Hello " ++ r
Use a function to convert Maybe to Either
note :: Maybe a -> e -> Either e a
note Nothing e = Left e
note (Just a) _ = Right a
hello l = do
v <- validateContainsJoAndAppendBob l `note` "Does not contain \"Jo\""
r <- validateLengthFunction v
return $ "Hello " ++ r
In addition to the practical answer given by Li-yao Xia, there's other alternatives. Here's two.
Maybe-Either isomorphism
Maybe a is isomorphic to Either () a, which means that there's a lossless translation between the two:
eitherFromMaybe :: Maybe a -> Either () a
eitherFromMaybe (Just x) = Right x
eitherFromMaybe Nothing = Left ()
maybeFromEither :: Either () a -> Maybe a
maybeFromEither (Right x) = Just x
maybeFromEither (Left ()) = Nothing
You can use one of these to translate to the other. Since validateLengthFunction returns an error text on failure, it would be a lossy translation to turn its return value into a Maybe String value, so it's better to use eitherFromMaybe.
The problem with that, though, is that this will only give you an Either () String value, and you need an Either String String. You can solve this by taking advantage of Either being a Bifunctor instance. First,
import Data.Bifunctor
and then you can write hello as:
hello :: String -> Either String String
hello l = do
v <-
first (const "Doesn't contain 'Jo'.") $
eitherFromMaybe $
validateContainsJoAndAppendBob l
r <- validateLengthFunction v
return $ "Hello " ++ r
This essentially does the same as Li-yao Xia's answer - a little less practical, but also a little less ad-hoc.
The first function maps the first (left-most) case of an Either value. In this case, if the return value from validateContainsJoAndAppendBob is a Left value, it's always going to be Left (), so you can use const to ignore the () input and return a String value.
This gets the job done:
*Q49816908> hello "Job, "
Left "to short"
*Q49816908> hello "Cool job, "
Left "Doesn't contain 'Jo'."
*Q49816908> hello "Cool Job, "
Right "Hello Cool Job, Bob"
This alternative I prefer to the next one, but just for completeness' sake:
Monad transformers
Another option is using Monad transformers. You can either wrap the Maybe in an EitherT, or conversely wrap an Either in MaybeT. The following example does the latter.
import Control.Monad.Trans (lift)
import Control.Monad.Trans.Maybe (MaybeT(..))
helloT :: String -> MaybeT (Either String) String
helloT l = do
v <- MaybeT $ return $ validateContainsJoAndAppendBob l
r <- lift $ validateLengthFunction v
return $ "Hello " ++ r
This also works, but here you still have to deal with the various combinations of Just, Nothing, Left, and Right:
*Q49816908> helloT "Job, "
MaybeT (Left "to short")
*Q49816908> helloT "Cool job, "
MaybeT (Right Nothing)
*Q49816908> helloT "Cool Job, "
MaybeT (Right (Just "Hello Cool Job, Bob"))
If you want to peel off the MaybeT wrapper, you can use runMaybeT:
*Q49816908> runMaybeT $ helloT "Cool Job, "
Right (Just "Hello Cool Job, Bob")
In most cases, I'd probably go with the first option...
What you want is (in the categorical sense) a natural transformation from Maybe to Either String, which the maybe function can provide.
maybeToEither :: e -> Maybe a -> Either e a
maybeToEither e = maybe (Left e) Right
hello l = do
v <- maybeToEither "No Jo" (validateContainsJoAndAppendBob l)
r <- validateLengthFunction v
return $ "Hello " ++ r
You can use <=< from Control.Monad to compose the two validators.
hello l = do
r <- validateLengthFunction <=< maybeToEither "No Jo" . validateContainsJoAndAppendBob $ l
return $ "Hello " ++ r
You can also use >=> and return to turn the whole thing into a single monstrous point-free definition.
hello = maybeToEither "No Jo" . validateContainsJoAndAppendBob
>=> validateLengthFunction
>=> return . ("Hello " ++)
I'm learning do expression and Monad using LEARN YOU A HASKELL FOR GREAT GOOD. There's a gcd implementation using tell function makes me confused.
gcd :: Int -> Int -> Writer [String] Int
gcd a b
| b == 0 = tell ["Finished with " ++ show a ] >>= (\_ -> return a)
| otherwise = tell [show a ++ " mod " ++ show b ++ " = " ++ show (a `mod` b)] >>= (\_ -> gcd b (a `mod` b))
gcdResult = gcd 8 3
-- result: WriterT (Identity (1,["8 mod 3 = 2","3 mod 2 = 1","2 mod 1 = 0","Finished with 1"]))
But I am confused by the tell function. When using >>= (\_ -> ...) or >>, the result before will be ignored, so why does the result of tell can be passed to the final result? As my thought, the tell result may be ignored, and the final result will be WriterT (Identity (1,[])).
You're confusing the result with the context. You are correct that, when applying >> or >>= \_ ->, the result of the left-hand-side is ignored. However, if the entire value was ignored, it would be completely pointless; the monadic context can be passed forward.
a >> b
This means "take the context from a and combine it with the context of b, keeping the result value of b". In the case of Writer, the monadic context is that there is some write-only data being passed about.
tell :: Monoid w => w -> Writer w ()
This is the (somewhat simplified) type of tell. It takes a value to write and returns a Writer instance whose result value is insignificant (()) but whose context is that there is a write-only value containing the w argument. When you apply >>, the result value is ignored (which is irrelevant because tell returns nothing of value through its result) but the context is kept.
The do notation allows us to express monadic code without overwhelming nestings, so that
main = getLine >>= \ a ->
getLine >>= \ b ->
putStrLn (a ++ b)
can be expressed as
main = do
a <- getLine
b <- getLine
putStrLn (a ++ b)
Suppose, though, the syntax allows ... #expression ... to stand for do { x <- expression; return (... x ...) }. For example, foo = f a #(b 1) c would be desugared as: foo = do { x <- b 1; return (f a x c) }. The code above could, then, be expressed as:
main = let a = #getLine in
let b = #getLine in
putStrLn (a ++ b)
Which would be desugared as:
main = do
x <- getLine
let a = x in
return (do
x' <- getLine
let b = x' in
return (putStrLn (a ++ b)))
That is equivalent. This syntax is appealing to me because it seems to offer the same functionality as the do-notation, while also allowing some shorter expressions such as:
main = putStrLn (#(getLine) ++ #(getLine))
So, I wonder if there is anything defective with this proposed syntax, or if it is indeed complete and equivalent to the do-notation.
putStrLn is already String -> IO (), so your desugaring ... return (... return (putStrLn (a ++ b))) ends up having type IO (IO (IO ())), which is likely not what you wanted: running this program won't print anything!
Speaking more generally, your notation can't express any do-block which doesn't end in return. [See Derek Elkins' comment.]
I don't believe your notation can express join, which can be expressed with do without any additional functions:
join :: Monad m => m (m a) -> m a
join mx = do { x <- mx; x }
However, you can express fmap constrained to Monad:
fmap' :: Monad m => (a -> b) -> m a -> m b
fmap' f mx = f #mx
and >>= (and thus everything else) can be expressed using fmap' and join. So adding join would make your notation complete, but still not convenient in many cases, because you end up needing a lot of joins.
However, if you drop return from the translation, you get something quite similar to Idris' bang notation:
In many cases, using do-notation can make programs unnecessarily verbose, particularly in cases such as m_add above where the value bound is used once, immediately. In these cases, we can use a shorthand version, as follows:
m_add : Maybe Int -> Maybe Int -> Maybe Int
m_add x y = pure (!x + !y)
The notation !expr means that the expression expr should be evaluated and then implicitly bound. Conceptually, we can think of ! as being a prefix function with the following type:
(!) : m a -> a
Note, however, that it is not really a function, merely syntax! In practice, a subexpression !expr will lift expr as high as possible within its current scope, bind it to a fresh name x, and replace !expr with x. Expressions are lifted depth first, left to right. In practice, !-notation allows us to program in a more direct style, while still giving a notational clue as to which expressions are monadic.
For example, the expression:
let y = 42 in f !(g !(print y) !x)
is lifted to:
let y = 42 in do y' <- print y
x' <- x
g' <- g y' x'
f g'
Adding it to GHC was discussed, but rejected (so far). Unfortunately, I can't find the threads discussing it.
How about this:
do a <- something
b <- somethingElse a
somethingFinal a b
A simple question:
given the definitions, (From Haskell SOE)
do x — el; el\ ...; en
=> el »= \x — do e2\ ...; en
and:
do let decllist; el\...; en
=> let decllist in do e2\ ...; en
it seems that these two constructs are the same:
do let x = e1
e2
and
do x <- e1
e2
both evaluate e1, bind it to e2, and then evaluate e2.
Yes?
Let's do a simple example in the Maybe monad:
foo = do
let x = Just 1
return x
and
bar = do
x <- Just 1
return x
Desugaring both, we get
foo = let x = Just 1 in return x -- do notation desugaring
= return (Just 1) -- let
= Just (Just 1) -- definition of return for the Maybe monad
bar = let ok x = return x in Just 1 >>= ok -- do notation desugaring
= let ok x = return x in ok 1 -- definition of >>= for the Maybe monad
= return 1 -- definiton of ok
= Just 1 -- definition of return for the Maybe monad
For reference, I am using the translation from section 3.14 of the Haskell 2010 Report.
No, they are not the same. For example,
do let x = getLine
print x
translates to
let x = getLine in print x
this is a type error, as x will have the type IO String. We're asking to print the computation itself, not its result.
do x <- getLine
print x
translates to
getLine >>= \x -> print x
Here x is bound as the result of the computation and its type is String, so this type checks.
In do-notation, let just binds values to names like it always does, while <- is used to perform monadic binding, which is binding a name to the result of a computation.
Assuming e1 is a computation of type Monad m => m a, then let x = e1 and x <- e1 mean somewhat different things.
In the let-version, when you use x within a do-expression, you are dealing with a value of type Monad m => m a.
In the other version, when you use x within a do expression, you are dealing with a value of type a (since do-notation implicitly handles mapping over the monad).
For example:
e :: IO Int
f :: Int -> Int
-- the following will result in a type error, since f operates on `Int`, not `IO Int`:
g = do let x = e
return $ f x
-- the following will work:
g' = do x <- e
return $ f x
No. x <- e1 translates to e1 >>= \x ->, an incomplete expression; the let expression is just a normal let. Or are you asking if let and (>>=) are the same thing? They very much aren't: (>>=) exposes the thing wrapped by a monad to a function, which must produce something wrapped in the monad. In other words, with x <- e1, e1's type must be IO a for some a, but with let x = e1 e1's type is just a; in both cases the type of x will be a.
HLint suggests that I use forM_ rather than forM. Why? I see they have different type signatures but haven't found a good reason to use one over the other.
forM :: (Traversable t, Monad m) => t a -> (a -> m b) -> m (t b)
forM_ :: (Foldable t, Monad m) => t a -> (a -> m b) -> m ()
The forM_ function is more efficient because it does not save the results of the operations. That is all. (This only makes sense when working with monads because a pure function of type a -> () is not particularly useful.)
Ok,
forM is mapM with its arguments flipped.
forM_ is mapM_ with its arguments flipped.
Let's see in mapM and mapM_ :
mapM :: Monad m => (a -> m b) -> [a] -> m [b]
mapM mf xs takes a monadic function mf (having type Monad m => (a -> m b)) and applies it to each element in list xs; the result is a list inside a monad.
The difference between mapM and mapM_ is, that mapM returns a list of the results, while mapM_ returns an empty result. The result of each action in mapM_ is not stored.
To understand the difference between (A): forM xs f and (B): forM_ xs f, it might help to compare the difference between the following:
-- Equivalent to (A)
do
r1 <- f x1
r2 <- f x2
...
rn <- f xn
return [r1, r2, ..., rn]
-- Equivalent to (B)
do
_ <- f x1
_ <- f x2
...
_ <- f xn
return ()
The crucial difference being that forM_ ignores the results r1, ... rn and just returns an empty result via return (). Think of the underscore as meaning "don't care" ... forM_ doesn't care about the results. forM however, does care about the results and returns them in as a list via return [r1, r2, ... rn].
Example 1
The code below asks for your name three times and prints the results of the forM.
import Control.Monad (forM, forM_)
main = do
let askName i = do
putStrLn $ "What's your name (" ++ (show i) ++ ")"
name <- getLine
return name
results <- forM [1,2,3] askName
putStrLn $ "Results = " ++ show results
An example execution with forM:
What's your name? (1)
> James
What's your name? (2)
> Susan
What's your name? (3)
> Alex
Results = ["James", "Susan", "Alex"]
But if we change the forM to a forM_, then we would have instead:
What's your name? (1)
> James
What's your name? (2)
> Susan
What's your name? (3)
> Alex
Results = ()
In your case, the linter is telling you that you're not using the return values of your forM (you don't have foo <- forM xs f, you probably have forM xs f by itself on a line) and so should use forM_ instead. This happens, for
example, when you are using a monadic action like putStrLn.
Example 2 The code below asks for your name and then says "Hello" – repeating three times.
import Control.Monad (forM, forM_)
main = do
let askThenGreet i = do
putStrLn $ "What's your name (" ++ (show i) ++ ")"
name <- getLine
putStrLn $ "Hello! " ++ name
forM [1,2,3] askThenGreet
An example execution with forM:
What's your name? (1)
> Sarah
Hello! Sarah
What's your name? (2)
> Dick
Hello! Dick
What's your name? (3)
> Peter
Hello! Peter
[(), (), ()]
The overall result of main comes from the result of the forM: [(), (), ()]. It's pretty useless and annoyingly, it appears in the console. But if we change the forM to a forM_, then we would have instead:
What's your name? (1)
> Sarah
Hello! Sarah
What's your name? (2)
> Dick
Hello! Dick
What's your name? (3)
> Peter
Hello! Peter
With that change, the overall result comes from the mapM_ and is now (). This doesn't show up in the console (a quirk of the IO monad)! Great!
Also, by using mapM_ here, it's clearer to other readers of your code – you're indirectly explaining / self-documenting that you don't care about the results [r1, ..., rn] = [(), (), ()] – and rightly so as they're useless here.