抱歉标题不好。我有一个有问题的数据类型,我试图将其定义为仿函数的实例。
所以基本上,我所拥有的是具有
的东西sample_logp :: s a -> a
并且应该使用
进行转换(a -> b)
到
sample_logp :: s b -> b
。以下代码并未完全实现此目的,仅在
中成功sample_logp :: s a -> b
data Model s a = Model {
sample_logp :: s a -> a
}
instance Functor (Model s) where
fmap f m = Model {
sample_logp = sample_logp'
} where sample_logp' x = (f . (sample_logp m)) x
我正在尝试甚至可能吗?如果是这样,如何更新此代码以实现此目的?
答案 0 :(得分:9)
这里的标准方法是添加更多类型变量。
data Model s a b = Model {
sample_logp :: s a -> b
}
拆分类型变量后,您可以访问更多工具。这里Profunctor类是合适的。 (因为我没有在这个系统上使用ghc而没有进行类型检查 - 如果我的实现已经关闭,请注释或修复它。)
instance (Functor s) => Profunctor (Model s) where
dimap f g (Model h) = Model $ g . h . fmap f
lmap f (Model h) = Model $ h . fmap f
rmap g (Model h) = Model $ g . h
现在,假设您有Model s a a
,相当于Model s a
,则可以使用Model s b b
将其转换为dimap bToA aToB
。
正如评论所说,您的原始数据类型是不变的,因为它在正面和负面位置使用相同的类型变量。这意味着您需要在每个方向上提供转换功能。通过添加额外的类型变量,您可以利用现有工具来实现这一目标,例如Profunctor
。
请注意,以上所有内容均基于您使用s
的协变类型的假设。如果s
是逆变的,那么您可以为原始类型编写直接Functor
实例,正如Chi的评论所说。不过,这种情况并不常见。