【发布时间】:2015-03-03 06:21:41
【问题描述】:
我试图了解fmap fmap 如何应用于像(*3) 这样的函数。
fmap fmap的类型:
(fmap fmap):: (Functor f1, Functor f) => f (a -> b) -> f (f1 a -> f1 b)
(*3) 的类型:
(*3) :: Num a => a -> a
也就是说签名a -> a对应f (a -> b),对吧?
Prelude> :t (fmap fmap (*3))
(fmap fmap (*3)):: (Num (a -> b), Functor f) => (a -> b) -> f a -> f b
我尝试过创建一个简单的测试:
test :: (Functor f) => f (a -> b) -> Bool
test f = True
然后将(*3) 输入其中,但我明白了:
*Main> :t (test (*3))
<interactive>:1:8:
No instance for (Num (a0 -> b0)) arising from a use of ‘*’
In the first argument of ‘test’, namely ‘(* 3)’
In the expression: (test (* 3))
为什么会这样?
【问题讨论】:
-
Num a => a -> a和f (x -> y)没有很好地对齐,你最终会得到f ~ (->) a和a ~ x -> y,因此是Num (x -> y)。一个更有趣的可能是fmap ($ [1, 2, 3]) $ fmap fmap $ fmap (+) $ Just 10,它返回Just [11,12,13]。一个更有用的Functor组合子可能是fmap fmap fmap,它允许您通过两个不同的Functors 列出一个函数:(.:) = fmap fmap fmap;(10*) .: [Just 1, Nothing, Just 3] == [Just 10, Nothing, Just 30] -
请注意
fmap fmap fmap等价于fmap . fmap,因为外部函子被强制为(->) (a -> b)(这就是为什么要求fmap fmap fmap的类型只在其约束中指定两个函子) . -
但为什么
(fmap fmap (*3))会进行类型检查?我想我只是在处理具有相同类型参数的两个函数((fmap fmap (*3))和test (*3))方面与 ghci 不同 -
fmap fmap fmap看起来很奇怪 -
test (*3)产生类型错误,因为类型变量a和b在输出类型中不存在。由于有Num (a -> b)约束,所以这个约束在应用这个函数的时候必须要解决(因为后面无法解决)。由于不存在这样的实例,你会在那个时候得到一个类型错误。将其更改为test :: (Functor f) => f (a -> b) -> (a,b),您将获得test (*3) :: Num (a -> b) => (a, b)。
标签: function haskell types functor function-composition