带有函子的类函数的广义新类型 [英] Generalised newtype deriving on class functions with Functors

查看:91
本文介绍了带有函子的类函数的广义新类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发一个表示键/值映射的类,并且我有一个基本上像

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?

推荐答案

如果fFunctor,则可以为其创建代表性包装器"

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 aRep f a中退出,您需要使用fFunctor遮光罩.

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 Functorhood.

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

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆