m0m*_*eni 12 monads haskell functional-programming functor
我是函数式编程的新手(来自javascript),我很难分辨两者之间的区别,这也搞砸了我对functor与monads的理解.
仿函数:
class Functor f where
fmap :: (a -> b) -> f a -> f b
Run Code Online (Sandbox Code Playgroud)
Monad(简化):
class Monad m where
(>>=) :: m a -> (a -> m b) -> m b
Run Code Online (Sandbox Code Playgroud)
fmap 接受函数和仿函数,并返回一个仿函数.>>= 接受一个函数和一个monad,并返回一个monad.两者之间的区别在于函数参数:
fmap - (a -> b)>>= - (a -> m b)>>=获取一个返回monad的函数参数.我知道这很重要,但是我很难看到这个轻微的东西如何使monad比functor强大得多.谁能解释一下?
Mat*_*hid 14
好吧,(<$>)是一个别名fmap,与交换的参数(=<<)相同(>>=):
(<$>) :: (x -> y) -> b x -> b y
(=<<) :: (x -> b y) -> b x -> b y
Run Code Online (Sandbox Code Playgroud)
现在相当明显:使用bind函数,我们应用一个返回a b y而不是a 的函数y.那会有什么不同呢?
考虑这个小例子:
foo <$> Just 3
Run Code Online (Sandbox Code Playgroud)
请注意,这(<$>)将适用foo于3,并将结果放回到Just.换句话说,这个计算的结果不可能是Nothing.反之:
bar =<< Just 3
Run Code Online (Sandbox Code Playgroud)
这个计算可以返回Nothing.(例如,bar x = Nothing会这样做.)
我们可以用list monad做类似的事情:
foo <$> [Red, Yellow, Blue] -- Result is guaranteed to be a 3-element list.
bar =<< [Red, Yellow, Blue] -- Result can be ANY size.
Run Code Online (Sandbox Code Playgroud)
简而言之,对于(<$>)(即fmap),结果的"结构"总是与输入相同.但是对于(=<<)(即(>>=)),结果的结构可能会改变.这允许条件执行,对输入做出反应,以及一大堆其他事情.
简短的回答是,如果你能以一种有意义的方式m (m a)转变m a,那么它就是一个Monad.这对于所有Monad都是可能的,但不一定适用于Functors.
我认为最令人困惑的事情是,所有的函子的常见的例子(例如List,Maybe,IO)也单子.我们需要一个像Functor但不是Monad的例子.
我将使用假设日历程序中的示例.以下代码定义了一个Event Functor,它存储与事件一起发生的一些数据及其发生的时间.
import Data.Time.LocalTime
data Event a = MkEvent LocalTime a
instance Functor Event where
fmap f (MkEvent time a) = MkEvent time (f a)
Run Code Online (Sandbox Code Playgroud)
该Event对象存储事件发生的时间和一些可以使用的更改数据fmap.现在让我们试着让它成为Monad:
instance Monad Event where
(>>=) (MkEvent timeA a) f = let (MkEvent timeB b) = f a in
MkEvent <notSureWhatToPutHere> b
Run Code Online (Sandbox Code Playgroud)
我们发现我们不能,因为你最终会得到两个LocalTime对象.timeA从给定的Event,并timeB从Event通过的结果给出f a.我们的Event类型被定义为只有一个LocalTime(time)它出现在,所以如果不将两个LocalTimes变成一个Monad是不可能的.(在某些情况下,这样做可能有意义,所以如果你真的想这么做就可以把它变成monad).
| 归档时间: |
|
| 查看次数: |
2178 次 |
| 最近记录: |