Confusion about callback and Monad
Sorry I'm new to Haskell. These questions can be very easy ...
From Hoogle, return
signature return :: Monad m => a -> m a
and head
-head :: [a] -> a
Before I did this head $ return [1,2,3]
, I thought that ghci would generate errors because it is m [a]
not the same thing [a]
. But to my surprise, he returned [1,2,3]
. And tail $ return [1,2,3]
he returned []
. Why?
One more question:
I wrote a function to generate a 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 title of the list I tried head randList
(failed) at first , but it head <$> randList
worked. What is it <$>
? Can someone please explain? Thank!
source to share
I thought ghci would generate errors because it
m [a]
doesn't match[a]
.
Perhaps not, but m [a]
they [b]
can also combine! For example, we can set m ~ []
and b ~ [a]
so that m [a] ~ [] [a] ~ [[a]]
and [b] ~ [[a]]
. Then we just need to check what []
is Monad
, what is. And this is exactly what happens:
> 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, without answering your question: this is better written replicateM n (drawFloat 2 10)
.
head randList
(failed) buthead <$> randList
worked. What is it<$>
?
The problem is the head
list is still waiting. Previously, when you used return
, the monad was not yet selected, so it can be selected as []
; but it is clear here that the monad you are using is IO
. Therefore, head
it cannot make progress. The solution is to teach how head
to handle IO
. There are many ways, and this <$>
is one of them; it is of this type:
> :t (<$>)
(<$>) :: Functor f => (a -> b) -> f a -> f b
The way of reading: set a pure function, teach it to handle IO
(or any other kind of effect that qualifies as Functor
). For example, it also has this type:
(<$>) :: ([a] -> a) -> IO [a] -> IO a
There are several other types of teachers. The two commonly used 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 how: assuming an efficient computation that produces a pure function, create a function that can handle the effects. The second should be read as: with a function that has some effects before it outputs its output, create a function that can handle the effects.
At this point, if these explanations do not help, you should refer to one of the many excellent monad tutorials available elsewhere on the Internet. My personal favorites You could think of Monads! and All about Monads .
source to share
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
in return [1,2,3]
, the monad in question is a list monad []
. So in this context
return [1,2,3] == [[1,2,3]]
apply to it head
and tail
, you get [1,2,3]
and []
accordingly.
In the second question, notice that the type randList
is IO [Float]
. So this is no longer a list, but a list within a monad. To apply any function to the contents of a monad, you can use fmap
( <$>
is its short name), which is of type:
fmap :: Functor f => (a -> b) -> f a -> f b
A monad is always a Functor . So what it does fmap
is that it takes a normal function, ( head
in your example) and a monadic value, applies that function to the "content" of the monad, and returns the return value of the function wrapped in the same monad f
.
source to share