Reputation: 2229
Sorry, I am a newbie to Haskell. This questions may be very easy...
From Hoogle, return
signature is return :: Monad m => a -> m a
and head
signature is head :: [a] -> a
Before I did this head $ return [1,2,3]
, I thought that ghci would throw errors because m [a]
is not the same [a]
. But to my surprise, it returned [1,2,3]
. And tail $ return [1,2,3]
returned []
. Why?
One more question:
I wrote a function to generate random number:
drawFloat :: Float -> Float -> IO Float
drawFloat x y = getStdRandom (randomR (x,y))
randList = mapM (const $ drawFloat 2 10) [1..10] -- generate a list of random numbers
When I want to get the head of the list, I first tried head randList
(failed) but head <$> randList
worked. What is <$>
? Can someone explain? Thanks!
Upvotes: 3
Views: 195
Reputation: 152847
I thought that ghci would throw errors because
m [a]
is not the same as[a]
.
Maybe not, but m [a]
and [b]
can unify! For example, we can set m ~ []
and b ~ [a]
so that m [a] ~ [] [a] ~ [[a]]
and [b] ~ [[a]]
. Then we just need to check that []
is a Monad
, which it is. And this is just what's happening:
> return [1,2,3] :: [[Int]]
[[1,2,3]]
Then it should be clear why head
returns [1,2,3]
and tail
returns []
.
randList = mapM (const $ drawFloat 2 10) [1..n]
As a comment, not answering your question yet: this is better spelled replicateM n (drawFloat 2 10)
.
head randList
(failed) buthead <$> randList
worked. What is<$>
?
The problem here is that head
is still expecting a list. Before, when you were using return
, the monad hadn't been chosen yet, and so it could be chosen to be []
; but here, it's clear that the monad you're using is IO
. So head
can't make progress. The solution is to teach head
how to handle IO
. There are many ways, and <$>
is one of them; it has this type:
> :t (<$>)
(<$>) :: Functor f => (a -> b) -> f a -> f b
The way to read this is: given a pure function, teach it how to handle IO
(or any other kind of effect that qualifies as a Functor
). For example, it also has this type:
(<$>) :: ([a] -> a) -> IO [a] -> IO a
There are several other kinds of teachers. Two commonly used ones are <*>
and =<<
:
Prelude Control.Applicative> :t (<*>)
(<*>) :: Applicative f => f (a -> b) -> f a -> f b
Prelude Control.Applicative> :t (=<<)
(=<<) :: Monad m => (a -> m b) -> m a -> m b
Read the first as: given an effectful computation that produces a pure function, produce a function that can handle effects. The second should be read as: given a function which has some effects before it produces its output, produce a function which can handle effects.
At this point, if these explanations aren't helpful, you should turn to one of the many excellent monad tutorials available elsewhere on the web. My personal favorites are You Could Have Invented Monads! and All About Monads.
Upvotes: 12
Reputation: 22500
Regarding your first question:
return
takes a "raw" value and gives you a monad with the value "wrapped" in it. Since you are using head
and tail
on return [1,2,3]
, the monad in question is the list monad []
. So in this context,
return [1,2,3] == [[1,2,3]]
apply head
and tail
on it, you will get [1,2,3]
and []
, respectively.
On the second question, note that the type of randList
is IO [Float]
. So it's not a list any more, but a list inside a monad. To apply any function to the content of the monad, you can use fmap
(<$>
is its infix shorthand), which has the type:
fmap :: Functor f => (a -> b) -> f a -> f b
A monad is always a Functor. So what fmap
does, is that it takes an ordinary function, (head
in your example), and a monadic value, applies the function to the "content" of the monad, and returns a return-value of the function wrapped in the same monad f
.
Upvotes: 3