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!

+3


source to share


2 answers


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) but head <$> 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 .

+12


source


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

.

+3


source







All Articles