我正在开发一个代表键/值映射的类,我有一个基本上像alterF
的函数:
class C t where
...
alterF :: Functor f =>
(Maybe (Value t) -> f (Maybe (Value t))) -> Key t -> t -> f t
不幸的是,这会打破GeneralisedNewtypeDeriving
。在某些情况下,这是合理的,因为我理解的GeneralisedNewtypeDeriving
基本上使用Coercible和函数coerce
。 Coercible
表示代表性相等的类型,即它们在运行时具有相同的表示,因此我们可以在它们之间免费转换。例如,给定:
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
?
答案 0 :(得分:6)
如果f
是Functor
,您可以为其制作“代表性包装”
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
。