Haskell:来自这种数据类型的仿函数?

时间:2016-03-28 12:09:12

标签: haskell functor

抱歉标题不好。我有一个有问题的数据类型,我试图将其定义为仿函数的实例。

所以基本上,我所拥有的是具有

的东西
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

我正在尝试甚至可能吗?如果是这样,如何更新此代码以实现此目的?

1 个答案:

答案 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的评论所说。不过,这种情况并不常见。