带有函子的类函数的广义新类型 [英] Generalised newtype deriving on class functions with Functors
问题描述
I'm developing a class representing key/value mappings, and I've got a function which is basically like alterF
:
class C t where
...
alterF :: Functor f =>
(Maybe (Value t) -> f (Maybe (Value t))) -> Key t -> t -> f t
不幸的是,这破坏了强制和函数 coerce
. Coercible
表示类型上相等的类型,即它们在运行时具有相同的表示形式,因此我们可以免费在它们之间进行转换.例如,给定:
Unfortunately, this breaks GeneralisedNewtypeDeriving
. In some cases, this is reasonable, as GeneralisedNewtypeDeriving
from what I understand essentially uses Coercible and the function coerce
. Coercible
represents types which are representationally equal, i.e. they have the same representation at run time, so we can convert between them for free. For example, given:
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
值都起作用.例如:
For example, GADTs violate this representational equality. But there are lots of values of f
that do work. For example:
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)
我还想到可以编写此实例:
It also occurs to me that this instance could be written:
Functor f => Coercible (f a) (f (T a))
Functor f => Coercible (f (T a)) (f a)
只需使用fmap
.与通常的coerce
不同,它在运行时不是免费的,但可以使用.
Just using fmap
. Unlike the usual coerce
, this wouldn't be free at runtime, but it will work.
所以我有一个包含10个函数的类,其中9个在GeneralisedNewtypeDeriving
下可以正常工作.只有最后一个没有,可以使用fmap
机械地解决.我是否必须为我所有的类函数编写自定义包装/展开实现,还是有一种方法要么要求我仅为问题函数编写实现,要么哄骗GHC将fmap
用作其GeneralisedNewtypeDeriving
的一部分?
So I've got a class with 10 functions, 9 of which work fine with GeneralisedNewtypeDeriving
. There's just this final one which doesn't, which could be resolved mechanically using fmap
. Do I have to write custom wrapping/unwrapping implementations for all my class functions, or is there a way to either require me to write the implementation for just the problem function or alternatively coax GHC into using fmap
as part of it's GeneralisedNewtypeDeriving
?
推荐答案
如果f
是Functor
,则可以为其创建代表性包装器"
If f
is a Functor
, you can make a "representational wrapper" for it
data Rep f a where
Rep :: (b -> a) -> f b -> Rep f a
与f
同构,除了它在a
中具有代表性之外,通过f
可能具有的任何名义方差的本质上存在的量化来表示.我认为这种结构碰巧有一些花哨的类别理论名称,但我不记得它是什么.要使f a
从Rep f a
中退出,您需要使用f
的Functor
遮光罩.
which is isomorphic to f
except that it is representational in a
, by what is essentially existential quantification over any nominal variance f
might have. I think this construction happens to have some fancy category theory name but I don't remember what it is. To get the f a
back out of a Rep f a
, you need to use f
's Functor
hood.
您可以在方法中使用此包装器,以确保您的类具有代表性.
You can use this wrapper in your method, ensuring that your class varies representationally.
alterFRep :: (Functor f)
=> (Maybe (Value t) -> Rep f (Maybe (Value t))) -> Key t -> t -> Rep f t
然后通过使用Rep f
同构使真正的方法"成为常规函数.您还可以为实例作者提供一种便捷的方法:
And then make the real "method" just a regular function in terms of it by using the isomorphism with Rep f
. You can also make a convenience method for instance authors:
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
并在其上使用toAlterFRep
.
so they don't have to worry about what the heck Rep
is, they just implement alterF
normally and use toAlterFRep
on it.
这篇关于带有函子的类函数的广义新类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!