关于返回功能和Monad的困惑

时间:2014-11-03 03:23:29

标签: haskell

抱歉,我是Haskell的新手。这个问题可能很容易......

来自Hoogle,return签名为return :: Monad m => a -> m a head签名为head :: [a] -> a

在我执行此head $ return [1,2,3]之前,我认为ghci会抛出错误,因为m [a]不是[a]。但令我惊讶的是,它返回[1,2,3]。并tail $ return [1,2,3]返回[]。为什么呢?

还有一个问题:

我写了一个函数来生成随机数:

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

当我想获得列表的头部时,我首先尝试head randList(失败),但head <$> randList工作。什么是<$>?谁能解释一下?谢谢!

2 个答案:

答案 0 :(得分:12)

  

我认为ghci会抛出错误,因为m [a][a]不同。

也许没有,但m [a][b]可以统一!例如,我们可以设置m ~ []b ~ [a],以便m [a] ~ [] [a] ~ [[a]][b] ~ [[a]]。然后,我们只需要检查[]是否为Monad。而这正是发生的事情:

> return [1,2,3] :: [[Int]]
[[1,2,3]]

然后应该清楚为什么head会返回[1,2,3]tail会返回[]

randList = mapM (const $ drawFloat 2 10) [1..n]

作为评论,尚未回答您的问题:这是更好的拼写replicateM n (drawFloat 2 10)

  

head randList(失败),但head <$> randList有效。什么是<$>

这里的问题是head仍然期待一个列表。之前,当您使用return时,monad尚未被选中,因此可以选择[];但是在这里,很明显你使用的monad是IO。所以head无法取得进展。解决方案是教head如何处理IO。有很多方法,<$>就是其中之一;它有这种类型:

> :t (<$>)
(<$>) :: Functor f => (a -> b) -> f a -> f b

阅读本文的方法是:给定一个纯函数,教它如何处理IO(或任何其他类似的效果Functor)。例如,它也有这种类型:

(<$>) :: ([a] -> a) -> IO [a] -> IO a

还有其他几种教师。两个常用的是<*>=<<

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

读取第一个:给定一个产生纯函数的有效计算,产生一个可以处理效果的函数。第二个应该理解为:给定一个在产生输出之前有一些效果的函数,产生一个可以处理效果的函数。

此时,如果这些解释没有帮助,您应该转向网络上其他地方提供的众多excellent monad tutorials之一。我个人的最爱是You Could Have Invented Monads!All About Monads

答案 1 :(得分:3)

关于你的第一个问题:

return获取一个“原始”值,并为其提供一个值为“wrapped”的monad。由于您在head上使用tailreturn [1,2,3],因此相关的monad是列表monad []。所以在这种情况下,

return [1,2,3] == [[1,2,3]]

在其上应用headtail,您将分别获得[1,2,3][]

关于第二个问题,请注意randList的类型为IO [Float]。所以它不再是一个列表,而是monad中的列表。要将任何函数应用于monad的内容,您可以使用fmap<$>是其中缀速记),其类型为:

fmap :: Functor f => (a -> b) -> f a -> f b

A monad is always a Functor。那么fmap所做的是,它需要一个普通函数,(在你的例子中是head)和一个monadic值,将函数应用于monad的“内容”,并返回一个返回 - 函数的值包含在同一个monad f中。