使用Functors在类函数上派生的广义newtype

时间:2018-02-18 04:50:43

标签: haskell

我正在开发一个代表键/值映射的类,我有一个基本上像alterF的函数:

class C t where
  ...
  alterF :: Functor f => 
    (Maybe (Value t) -> f (Maybe (Value t))) -> Key t -> t -> f t

不幸的是,这会打破GeneralisedNewtypeDeriving。在某些情况下,这是合理的,因为我理解的GeneralisedNewtypeDeriving基本上使用Coercible和函数coerceCoercible表示代表性相等的类型,即它们在运行时具有相同的表示,因此我们可以在它们之间免费转换。例如,给定:

newtype T a = T a

我们有:

Coercible a (T a)
Coercible (T a) a

但我们没有(一般):

Coercible (f a) (f (T a))
Coercible (f (T a)) (f a)

例如,GADT违反了这种代表性的平等。但是f有很多值可行。例如:

Coercible (Maybe a) (Maybe (T a))
Coercible (Maybe (T a)) (Maybe a)
Coercible [a] [T a]
Coercible [T a] [a]
Coercible (Identity a) (Identity (T a))
Coercible (Identity (T a)) (Identity a)

我也想到这个实例可以写成:

Functor f => Coercible (f a) (f (T a))
Functor f => Coercible (f (T a)) (f a)

只需使用fmap。与通常的coerce不同,这在运行时不会自由,但它会起作用。

所以我有一个包含10个函数的类,其中9个与GeneralisedNewtypeDeriving一起正常工作。这是最后一个没有的,可以使用fmap进行机械解决。我是否必须为我的所有类函数编写自定义包装/展开实现,或者是否有办法要求我只为问题函数编写实现,或者让GHC使用fmap作为其中的一部分&# 39; s GeneralisedNewtypeDeriving

1 个答案:

答案 0 :(得分:6)

如果fFunctor,您可以为其制作“代表性包装”

data Rep f a where
    Rep :: (b -> a) -> f b -> Rep f a

f同构,除了它在a中具有代表性,基本上是对任何名义方差f的存在量化。我认为这种结构碰巧有一些奇特的类别理论名称,但我不记得它是什么。要让f a退出Rep f a,您需要使用f的{​​{1}}封面。

您可以在方法中使用此包装器,确保您的类具有代表性。

Functor

然后通过使用alterFRep :: (Functor f) => (Maybe (Value t) -> Rep f (Maybe (Value t))) -> Key t -> t -> Rep f t 的同构,使真正的“方法”成为常规函数。您还可以为实例作者提供便利方法:

Rep f

所以他们不必担心toAlterFRep :: (forall f t. (Functor f) => (Maybe (Value t) -> f (Maybe (Value t))) -> Key t -> t -> f t) -> (forall f t. (Functor f) => (Maybe (Value t) -> Rep f (Maybe (Value t))) -> Key t -> t -> Rep f t) 是什么,他们只是正常实施Rep并在其上使用alterF