haskell - Haskell fmap 组成误区
问题描述
如果我组成两个fmap
s
Prelude> :t (fmap.fmap)
(fmap.fmap)
:: (Functor f, Functor f1) => (a -> b) -> f1 (f a) -> f1 (f b)
我得到一个函数,它将函数应用于 2 个嵌套结构层内的值,f1
并且f
.
我可以使用它——这正如我所料:
Prelude> (fmap.fmap) (+1) [[1,2]]
[[2,3]]
正如我预期的那样推断类型(结果周围的2级结构)
Prelude> :t (fmap.fmap) (+1) [[1,2]]
(fmap.fmap) (+1) [[1,2]] :: Num b => [[b]]
以下不起作用。我也期待这一点(因为我们不能申请sum
单个号码):
Prelude> (fmap.fmap) sum [[1,2]]
<interactive>:39:2: error:
• Could not deduce (Num (t0 b))
from the context: (Num (t b), Num b, Foldable t)
bound by the inferred type for ‘it’:
(Num (t b), Num b, Foldable t) => [[b]]
at <interactive>:39:2-24
The type variable ‘t0’ is ambiguous
• In the ambiguity check for the inferred type for ‘it’
To defer the ambiguity check to use sites, enable AllowAmbiguousTypes
When checking the inferred type
it :: forall (t :: * -> *) b.
(Num (t b), Num b, Foldable t) =>
[[b]]
Prelude> :t (fmap.fmap) sum [[1,2]]
(fmap.fmap) sum [[1,2]] :: (Num (t b), Num b, Foldable t) => [[b]]
但!如果我将一级结构更改为一种Maybe
类型:
Prelude> (fmap.fmap) sum Just [1,2]
Just 3
然后它开始工作,但在我看来打破了类型签名
(fmap.fmap) :: (Functor f, Functor f1) => (a -> b) -> f1 (f a) -> f1 (f b)
(因为它将sum
函数应用到结构的第一级,而不是我预期的第二级)。
我认为在我理解函数应用程序顺序如何评估这里存在问题,因为我发现使用括号,这在具有可折叠列表值的两个结构级别内按预期工作(与第一个示例中的数字相比):
Prelude> (fmap.fmap) sum (Just [[1,2],[2,3]])
Just [3,5]
但是这里会发生什么:
Prelude> (fmap.fmap) sum Just [1,2]
Just 3
为什么跳过第一级结构?
这里函数应用的顺序是什么?
Haskell 如何推断最终类型?
Prelude> :t (fmap.fmap) sum Just [1,2] (fmap.fmap) sum Just [1,2] :: Num t => Maybe t
为什么Maybe t
而不是Maybe List t
我理解的(fmap.fmap)
必须确定f1 (f b)
两个层次的结构而不是一个?
解决方案
Int
让我们计算一下,为了简单起见,假设数字文字是s。
(fmap.fmap) sum Just [1,2]
= fmap (fmap sum) Just [1,2]
| | \ -- an additional argument applied to the result of fmap
| \ -- the value with a type of the form f a with f Functor
\ -- the function to fmap
这里,Just
是一个函数[Int] -> Maybe [Int]
,所以第一个fmap
对函子进行操作f = (->) [Int]
,我们有,fmap = (.)
因为它是这样定义的Functor ((->) [Int])
。
= (.) (fmap sum) Just [1,2]
= (fmap sum) (Just [1,2])
现在,fmap f (Just x) = Just (f x)
既然这Functor Maybe
就是定义的方式。
= Just (sum [1,2])
= Just 3
- 为什么跳过第一级结构?
它不是。第一级是(->) [Int]
。
- 这里函数应用的顺序是什么?
平常的那一个。fmap.fmap
应用于sum
。结果应用于Just
. 最终结果应用于[1,2]
.
- Haskell 如何推断最终类型?
它看到这Just
是一个“包装在(->) [Int]
函子内的值”,并使用它来实例化第一个fmap
. 第二个是在级别fmap
上使用,因为返回它。Maybe
Just