首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >多param类型类上的Haskell DerivingVia和有趣的deps

多param类型类上的Haskell DerivingVia和有趣的deps
EN

Stack Overflow用户
提问于 2018-10-26 13:13:00
回答 1查看 527关注 0票数 5

我试图使用DerivingVia为一个具有函数依赖关系的多参数类型类削减实例定义的样板。

我有这些类型和类别:

代码语言:javascript
复制
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE DerivingVia #-}

newtype Wrapper t = Wrapper t  
newtype Wrapper2 t = Wrapper2 t

class MyEq a f | a -> f where
  eq :: a -> a -> f Bool

-- Instance for 'Wrapper2'
instance Eq t => MyEq (Wrapper2 t) Wrapper2 where
  eq (Wrapper2 t) (Wrapper2 t') = Wrapper2 (t == t')

我想使用MyEq (Wrapper Int) Wrapper派生deriving via

我的第一次尝试是使用:

代码语言:javascript
复制
deriving via Wrapper2 instance MyEq (Wrapper Int) Wrapper

正如本文第6.2节https://www.kosmikus.org/DerivingVia/deriving-via-paper.pdf中所讨论的,这是一个MyEq (Wrapper Int) Wrapper2实例,第二个参数被“更改”,但第一个参数仍然是Wrapper Int

显然,instance MyEq (Wrapper Int) Wrapper2不存在,因为我实现了instance MyEq (Wrapper2 Int) Wrapper2

我不能通过创建(将Wrapper作为第一个类型参数)来“欺骗”:

代码语言:javascript
复制
-- Instance for 'Wrapper2'
instance Eq t => MyEq (Wrapper t) Wrapper2 where
  eq (Wrapper2 t) (Wrapper2 t') = Wrapper2 (t == t')

因为在这种情况下,函数依赖关系Wrapper t -> Wrapper2不受尊重。

我可以轻松地通过重写eq :: f a -> f a -> f Bool和消除函数依赖来解决这个问题,但是我希望避免更改这个API。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-10-26 16:13:42

首先,让我们重复一遍,您希望为您派生的实例是这个实例:

代码语言:javascript
复制
instance MyEq (Wrapper Int) Wrapper where
  eq (Wrapper t) (Wrapper t') = Wrapper (t == t')

我看不出用您想要的方式派生类的方法,因为在您观察自己时,这要求您更改两个类参数,但我们目前只能通过最后一个类进行派生。

一种可能是翻转类参数,这样“重要”类参数(确定另一个类的参数)成为最后一个,然后调整您派生的包装器类型,以包含一些有用的信息,例如:

代码语言:javascript
复制
class MyEq f a | a -> f where
  aeq :: a -> a -> f Bool

函数aeq保留相同的类型,但是MyEq的类参数被翻转。现在,Wrapper2获得一个额外的参数,让我们在派生时指定f的期望值:

代码语言:javascript
复制
newtype Wrapper2 (f :: Type -> Type) t = Wrapper2 t

现在可以定义Wrapper2的实例,而无需显式地指定f

代码语言:javascript
复制
instance (Eq t, Coercible Bool (f Bool)) => MyEq f (Wrapper2 f t) where
  eq (Wrapper2 t) (Wrapper2 t') = coerce (t == t')

这里需要Wrapper2中的额外参数来满足函数依赖。

现在,我们可以导出所需的实例,如下所示:

代码语言:javascript
复制
deriving via Wrapper2 Wrapper Int instance MyEq Wrapper (Wrapper Int)

这是因为,现在,GHC正在寻找一个instance MyEq Wrapper (Wrapper2 Wrapper Int),这与我们提供的一个匹配。

您可以使用关联类型实现相同的目标:

代码语言:javascript
复制
class MyEq a where
  type Result a :: Type -> Type
  eq :: a -> a -> Result a Bool

Wrapper2的定义与额外的参数相同。实例变成

代码语言:javascript
复制
instance (Eq t, Coercible Bool (f Bool)) => MyEq (Wrapper2 f t) where
  type Result (Wrapper2 f t) = f
  eq (Wrapper2) (Wrapper2 t') = coerce (t == t')

deriving via Wrapper2 Wrapper Int instance MyEq (Wrapper Int)
票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/53009549

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档