功能组合的简单定义是:
newtype Compose f g a =
Compose { getCompose :: f (g a) }
deriving (Eq, Show)
instance (Functor f, Functor g) => Functor (Compose f g) where
fmap f (Compose fga) = Compose $ (fmap . fmap) f fga
或
fmap
现在我有以下示例:
instance (Functor f, Functor g) => Functor (Compose f g) where
fmap f (Compose fga) = Compose $ fmap f (fmap f fga)
然后我尝试在没有合成运算符的情况下编写* Couldn't match type `b' with `g b'
`b' is a rigid type variable bound by
the type signature for:
fmap :: forall a b. (a -> b) -> Compose f g a -> Compose f g b
at D:\haskell\chapter25\src\Twinplicative.hs:11:5
Expected type: f (g b)
Actual type: f b
* In the second argument of `($)', namely `fmap f (fmap f fga)'
In the expression: Compose $ fmap f (fmap f fga)
In an equation for `fmap':
fmap f (Compose fga) = Compose $ fmap f (fmap f fga)
* Relevant bindings include
fga :: f (g a)
(bound at D:\haskell\chapter25\src\Twinplicative.hs:11:21)
f :: a -> b
(bound at D:\haskell\chapter25\src\Twinplicative.hs:11:10)
fmap :: (a -> b) -> Compose f g a -> Compose f g b
(bound at D:\haskell\chapter25\src\Twinplicative.hs:11:5)
:
fmap
并且编译器抱怨:
{{1}}
如何在没有合成运算符的情况下撰写{{1}}以上?
答案 0 :(得分:3)
当您提供类型为fmap
的{{1}}时,您向g a -> g b
最左侧应用程序提供的功能应为f
。您可以使用a -> b
即a -> b
将功能g a -> g b
提升为fmap
。外部fmap f
的第二个参数应为fmap
类型f (g a)
:
fga
答案 1 :(得分:2)
我喜欢Lee的回答,它清楚地说明了如何从头开始为Functor
实现Compose
实例。但是,我还认为值得回答一个密切相关的问题,即:如何从现有实例开始并机械地重写它以避免(.)
函数组合?因此,我在这个答案中解决了这个问题。
由于(f . g) x = f (g x)
是(.)
的定义等式,我们得出结论(fmap . fmap) f = fmap (fmap f)
。将等式的两边应用于fga
,我们得到:
(fmap . fmap) f fga = fmap (fmap f) fga