我知道parens强制执行不同的操作顺序,但我不太了解第一个结果:
>> (fmap length Just) [1, 2, 3]
1
以下内容非常有意义 - 我们正在Just结构上提升长度函数,因此我们应该得到" Just [list of list]":
>> fmap length $ Just [1, 2, 3]
Just 3
第一种情况发生了什么?
答案 0 :(得分:10)
在第一种情况下,您将获得Functor
的函数实例,其fmap = (.)
为:{/ p>
fmap length Just [1,2,3]
=
(length . Just) [1,2,3]
=
length (Just [1,2,3])
Foldable
的{{1}}个实例表示Maybe
的长度为Nothing
,而0
的长度为Just
- - 如果您认为1
有点像Maybe a
的集合,其中最多只有一个a
,那么这是非常明智的。
答案 1 :(得分:0)
fmap
只能应用于两个参数,因此首先让我们主要关注fmap length Just
fmap
实例是(.)
即函数组合,因此表达式基本上是(length . Just) [1,2,3]
length (Just [1,2,3])
length
应用于Maybe
值,这取决于Maybe的Foldable
实例。 Foldable
是类型构造函数上的类型类,而不是类型(就像Functor
一样),因此实例根据类型构造函数所采用的参数的类型(即{{1} a
中的})。列表Maybe a
只是一个干扰,因为长度只能查询最外层,因此表达式与[1, 2, 3]
相同。length (Just ())
值只能包含0或1个值,而Maybe
只能包含1。因此答案是Just
。除了丹尼尔所说的话,我想详细解释一下我们是如何遇到的。
给定的表达式为1
,可以进一步写为fmap length Just [1,2,3]
让我们看看我们拥有的所有三个函数的类型定义
((fmap length) Just) [1,2,3]
现在让我们将类型替换为> :t fmap
fmap :: Functor f => (a -> b) -> f a -> f b
> :t length
length :: Foldable t => t a -> Int
> :t Just
Just :: a -> Maybe a
,然后看看我们得到了什么。
fmap
用ghci确认
fmap :: (a -> b) -> f a -> f b
t a Int -> f (t a) -> f Int
可以肯定地说> :t fmap length
fmap length :: (Functor f, Foldable t) => f (t a) -> f Int
也是Functions
(稍后会详细介绍)。
这意味着我们可以说上面的Functors
是f
,而 -> a
是(t a)
,这是可以的,因为Maybe a
有一个可折叠的实例定义。即
Maybe
可以写为 f (t a)
,也可以写成 (-> a) (Maybe a)
的类型, a -> Maybe a
。
类似Just
的{{1}}可以写为f Int
因此 (-> a) Int
的类型定义为
a -> Int
但这并不能完全消除我的困惑,现在我知道我们得到了一个fmap lenght Just
,但是为什么?令我担心的事。看一下上面的类型,唯一可行的方法是,如果将Just的值以某种方式输入到长度中。
Okieee!将数据输入另一个函数让我想起了什么。啊!类似于> :t fmap length Just
fmap length Just :: a -> Int
,我的意思是如果我们有类似的东西:
Int
这也许可以解释这个。但是我们为什么要在这里组成这些功能。这里有些不合要求的东西。
看起来两个函数的fmap等同于它们的组成。那有可能吗?
我们继续进行下去,消除这个疑问。我们需要问自己两个问题:
稍作挖掘后,我发现是的-函数可以是函子的实例。任何函数都可以写为Function composition
,也可以写成fmap length Just [1,2,3] == (length . Just) [1,2,3] == (length (Just [1,2,3])
,因为 a -> b
只是带有两个参数的类型构造函数。
现在我们知道 (->) a b
可以接受类型为->
的类型,但是Functors
拥有我们不能使用的类型* -> *
,但是.. (->)
有一种* -> * -> *
,我们可以用它来创建Functor的实例。
现在我们知道函数可以是Functor的实例,现在是实现它们的时候了。挖掘into the source,我确实找到了 (->) a
* -> *
让我们看看如何实现该实现:
(->)
的类型是:
instance Functor ((->) r) where
fmap = (.)
用fmap
代替fmap :: (a -> b) -> f a -> f b
,因为函数也可以是函子:
(->) a
可以简化为:
f
因此具有函子功能的fmap的最终类型定义为:
fmap :: (a -> b) -> f a -> f b
( (->) r a) -> f ( (->) r b)
啊!如果我们仔细观察,我们会看到的是fmap :: (a -> b) -> f a -> f b
( r -> a) -> ( r -> b)
的类型,其中fmap :: (a -> b) -> ( r -> a) -> (r -> b)
的输出将作为第一个参数 function composition (.)
的输入被馈送给我们结果r -> a
这意味着,我们可以放心地说
a -> b
这证明了这一点,当我们将fmap作为函子作为函数使用时,fmap的实例就是函数组合。
回想我们的问题:
(r -> b)
这可以看作是:
instance Functor ((->) r) where
fmap = (.)
答案:
((fmap length) Just) [1,2,3]
也许也许可以包含两个值fmap length Just [1,2,3] == (length . Just) [1,2,3] == (length (Just [1,2,3])
和> (length (Just [1,2,3]) == 1
,并且由于0
包含某些内容,因此我们将1
称为Just