我刚刚意识到,函数有Monad、函子和应用程序的实例。
通常,当我看到一些没有类型的实例时,我所做的就是编写一些类型良好的表达式,并查看它返回了什么:
有人能解释一下这些例子吗?您通常会听说List和可能的实例,到目前为止,这对我来说是很自然的,但是我不明白函数怎么可能是函子,甚至是Monad。
编辑:好的,这是一个有效的类型良好的表达式,不编译:
fmap (+) (+) 1 (+1) 1发布于 2017-04-12 21:57:59
函数的fmap作用于函数产生的结果:
GHCi> :set -XTypeApplications
GHCi> :t fmap @((->) _)
fmap @((->) _) :: (a -> b) -> (t -> a) -> t -> b通过一个a函数修改t -> a函数的a -> b结果。如果这听起来很像函数组合,那是因为它确实是:
GHCi> fmap (3 *) (1 +) 4
15
GHCi> ((3 *) <$> (1 +)) 4
15
GHCi> ((3 *) . (1 +)) 4
15(<*>)有点棘手:
GHCi> :t (<*>) @((->) _)
(<*>) @((->) _) :: (t -> a -> b) -> (t -> a) -> t -> bApplicative f => f (a -> b)参数变成t -> (a -> b)。(<*>)通过使用辅助函数(类型为t -> a)从第一个参数生成第二个参数,将两个参数的函数(类型为t -> a -> b)转换为一个参数的函数(t -> b类型):
GHCi> :t \k f -> \x -> k x (f x)
\k f -> \x -> k x (f x) :: (t2 -> t -> t1) -> (t2 -> t) -> t2 -> t1下面是一个用应用程序风格编写的示例,使用函数的Functor和Applicative实例:
GHCi> ((&&) <$> (> 0) <*> (< 4)) 2
True其中一种读取方法是“将2添加到(> 0)和(< 4),并将结果与(&&)结合起来”。它可以用来自Control.Applicative的Control.Applicative的更简洁的方式编写,但是我相信(<$>)/(<*>)的拼写更有意图--揭示。
Applicative的另一种方法,pure.
GHCi> :t pure @((->) _)
pure @((->) _) :: a -> t -> a..。将t -> a函数从a中提取出来,而不是其他任何东西。常量函数是实现这一目的的唯一途径:
GHCi> pure 2 "foo"
2
GHCi> pure 2 42
2请注意,在上面的每个示例中,pure 2都有不同的类型。
鉴于以上所述,Monad实例令人惊讶地毫无意义。为了更清晰起见,让我们看一下(=<<)而不是(>>=)
GHCi> :t (=<<) @((->) _)
(=<<) @((->) _) :: (a -> t -> b) -> (t -> a) -> t -> b如果将这种类型与(<*>)的类型进行比较,您将看到它们是相同的,只是第一个参数已被翻转。函数实例是一个例外情况,在这种情况下,Applicative和Monad做的事情本质上是相同的。
值得一提的是,来自join的Control.Monad可以使用一个值作为两个参数函数的两个参数:
GHCi> :t join @((->) _)
join @((->) _) :: (t -> t -> a) -> t -> a
GHCi> join (*) 5
25https://stackoverflow.com/questions/43379364
复制相似问题