【发布时间】:2019-08-29 01:08:20
【问题描述】:
我正在尝试实现
的 Functor 实例data ComplicatedA a b
= Con1 a b
| Con2 [Maybe (a -> b)]
对于 Con2,我的想法是 fmap 需要类似于
fmap f (Con2 xs) = Con2 (map f' xs)
那么我需要一个列表映射函数 f' 像
Maybe (a -> x) -> Maybe (a -> y)
由于Maybe是一个Functor,我可以写成f'这样的
fmap ((a->x) -> (a->y))
为了得到((a->x) -> (a->y)),我以为我可以做到
fmap (x->y) 与(fmap f) 相同
所以我的建议是
instance Functor (ComplicatedA a) where
fmap f (Con1 x y) = Con1 x (f y)
fmap f (Con2 xs) = Con2 (map (fmap (fmap f)) xs)
然而真正的解决方案是使用(f .) 而不是(fmap f) 从x -> y 获取((a->x) -> (a->y)),它看起来像这样
instance Functor (ComplicatedA a) where
fmap f (Con1 a b) = Con1 a (f b)
fmap f (Con2 l) = Con2 (map (fmap (f .)) l)
我只是想知道我的思考过程和解决方案有什么问题。如果 f 是 a->b 类型的函数, (fmap f) 是否与 (f .) 相同?
提前谢谢你。
【问题讨论】:
-
fmap f确实与(f .)相同,如果所讨论的函子是函数(通常表示为(->) r)。 -
@RobinZigmond 谢谢。那么我的解决方案也正确吗?
-
我相信是的。 (但我不是专家,现在没有时间详细检查。)
-
...您甚至可以将
map替换为fmap,使其阅读起来更有趣。fmap f (Con2 l) = Con2 (fmap (fmap (fmap f)) l)。然后决定用更多fmaps 会更有趣,fmap (fmap (fmap f))是fmap . fmap . fmap $ f,(.)是fmap,所以Con2 (fmap fmap (fmap fmap fmap) f l)。 -
@klabe 在我看来,您的解决方案不仅是正确的,而且比另一个更具可读性。你基本上需要通过两个函子
a ->和Maybe“提升”f :: b->b',所以使用两个fmaps 对我来说感觉很自然。我也想要fmap (fmap (fmap f)),因为[]是第三个函子。 (当然,最简单的就是写deriving Functor,让GHC为我们做,但是手工写functor实例对于学习functor是如何工作的很有用)