Reputation: 46103
From the document:
when :: (Monad m) => Bool -> m () -> m ()
when p s = if p then s else return ()
The when
function takes a boolean argument and a monadic computation with unit ()
type and performs the computation only when the boolean argument is True
.
===
As a Haskell newbie, my problem is that for me m ()
is some "void" data, but here the document mentions it as computation. Is it because of the laziness of Haskell?
Upvotes: 2
Views: 118
Reputation: 52290
Laziness has no part in it.
The m
/Monad part is often called computation.
The best example might be m = IO
:
Look at putStrLn "Hello" :: IO ()
- This is a computation that, when run, will print "Hello"
to your screen.
This computation has no result - so the return type is ()
Now when you write
hello :: Bool -> IO ()
hello sayIt =
when sayIt (putStrLn "Hello")
then hello True
is a computation that, when run, will print "Hello"
; while hello False
is a computation that when run will do nothing at all.
Now compare it to getLine :: IO String
- this is a computation that, when run, will prompt you for an input and will return the input as a String
- that's why the return type is String
.
Does this help?
Upvotes: 6
Reputation: 30237
Monads are notably abstract and mathematical, so intuitive statements about them are often made in language that is rather vague. So values of a monadic type are often informally labeled as "computations," "actions" or (less often) "commands" because it's an analogy that sometimes help us reason about them. But when you dig deeper, these turn out to be empty words when used this way; ultimately what they mean is "some value of a type that provides the Monad
interface."
I like the word "action" better for this, so let me go with that. The intuition for the use for that word in Haskell is this: the language makes a distinction between functions and actions:
a -> b
.IO a
.
IO ()
produces an uninteresting result value, and therefore it's either a no-op (return ()
) or an action that is only interesting because of its side effects.Monad
then is the interface that allows you to glue actions together into complex actions.
This is all very intuitive, but it's an analogy that becomes rather stretched when you try to apply it to many monads other than the IO
type. For example, lists are a monad:
instance Monad [] where
return a = [a]
as >>= f = concatMap f as
The "actions" or "computations" of the list monad are... lists. How is a list an "action" or a "computation"? The analogy is rather weak in this case, isn't it?
So I'd say that this is the best advice:
Monad
laws and the definitions of the various functions that work with Monad
.Upvotes: 2
Reputation: 39390
for me "m ()" is some "void" data
And that kinda makes sense, in that a computation is a special kind of data. It has nothing to do with laziness - it's associated with context.
Let's take State
as an example. A function of type, say, s -> ()
in Haskell can only produce one value. However, a function of type s -> ((), s)
is a regular function doing some transformation on s
. The problem you're having is that you're only looking at the ()
part, while the s -> s
part stays hidden. That's the point of State
- to hide the state passing.
Hence State s ()
is trivially convertible to s -> ((), s)
and back, and it still is a Monad
(a computation) that produces a value of... ()
.
If we look at practical use, now:
(flip runState 10) $ do
modify (+1)
This expression produces a tuple of ((), Int)
; the Int
part is hidden
It will modify the state, adding 1 to it. It produces the intermediate value of ()
, though, which fits your when
:
when (5 > 3) $ modify (+1)
Upvotes: 2