[英]Why do the types in `(fmap . fmap) sum Just [1, 2, 3]` work?
我正在享受我生命中的时间从最初的原则阅读精彩的Haskell编程,并且我通过以下示例来看,我只是无法拆开(Page 1286电子阅读器):
Prelude> (fmap . fmap) sum Just [1, 2, 3]
Just 6
对我来说很明显以下是如何工作的:
Prelude> fmap sum $ Just [1,2,3]
Just 6
我已经手动解构(fmap . fmap)
以了解这些类型的工作原理。 但是当把它想象为“两次提升”时,它没有意义,因为我正在解除Just和List数据构造函数。
我在ghci
键入了以下内容:
Prelude> :t (fmap . fmap)
(fmap . fmap)
:: (Functor f, Functor f1) => (a -> b) -> f1 (f a) -> f1 (f b)
Prelude> :t (fmap . fmap) sum
(fmap . fmap) sum
:: (Num b, Foldable t, Functor f, Functor f1) =>
f1 (f (t b)) -> f1 (f b)
Prelude> :t (fmap . fmap) sum Just
(fmap . fmap) sum Just :: (Num b, Foldable t) => t b -> Maybe b
我不明白如何派生最后的输出。 当(fmap . fmap) sum
Just
数据构造函数时,编译器如何知道为Maybe
替换f1
和f
? 在这里得到一个好的答案后,我怎么能自己弄明白呢?
这并没有超越Maybe
和List
(那将是(fmap . fmap) sum (Just [1,2,3])
,它有一个类型问题),但是超过了函数类型(->)
和Maybe
。
Just :: a -> Maybe a
-- ((->) a) (Maybe a)
-- f (g a) for f ~ ((->) a) and g ~ Maybe
(fmap . fmap) :: (a -> b) -> f (g a ) -> f (g b)
-- Num x => ([x] -> x) -> f (g [x]) -> f (g x)
-- Num x => ([x] -> x) -> ([x] -> Maybe [x]) -> [x] -> Maybe x
-- ^ ^ ^
-- sum Just [1,2,3]
如果您不理解特定答案的工作原理,请将您提供的参数与上一步中的类型对齐。
Prelude> :t (fmap . fmap) sum
(fmap . fmap) sum
:: (Functor f, Functor f1, Num b) => f (f1 [b]) -> f (f1 b)
所以为了这项工作, Just
要有f (f1 [b])
,然后(fmap . fmap) sum Just
必须有f (f1 b)
类型。
Just :: (Functor f, Functor f1, Num b) => f (f1 [b])
这里f
或f1
应该是什么并不明显,所以让我们试试RHS吧。 我们可以作弊并要求GHCi检查(fmap . fmap) sum Just
的实际值应该是:
Prelude> :t (fmap . fmap) sum Just
(fmap . fmap) sum Just :: Num b => [b] -> Maybe b
但这应该匹配:
(Functor f, Functor f1, Num b) => f (f1 b)
我们试图弄清楚f
和f1
在这里是什么。 所以我们必须稍微重写一下,因此它具有相同的结构(请记住->
是语法糖并且有时会妨碍):
(fmap . fmap) sum Just :: Num b => [b] -> Maybe b
-- Same as...
(fmap . fmap) sum Just :: Num b => (->) [b] (Maybe b)
-- Or...
(fmap . fmap) sum Just :: Num b => ((->) [b]) (Maybe b)
-- Functor f = ((->) [b])
-- Functor f1 = Maybe
所以我们可以弄清楚,为了匹配类型, Functor f
必须是(->) [b]
...记住函数也是函子! Functor f1
是Maybe
,这有点明显。
我们可以测试一下:
Prelude> :t (fmap . fmap) sum :: Num b => ([b] -> Maybe [b]) -> ([b] -> Maybe b)
(fmap . fmap) sum :: Num b => ([b] -> Maybe [b]) -> ([b] -> Maybe b)
:: Num b => ([b] -> Maybe [b]) -> [b] -> Maybe b
而GHCi认为它的类型检查就好了。
这里唯一容易忘记的部分就是(->) [b]
是一个有效的函子!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.