gpt4 book ai didi

Haskell DerivingVia 在多参数类型类上的乐趣 deps

转载 作者:行者123 更新时间:2023-12-05 00:46:56 27 4
gpt4 key购买 nike

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

我有这些类型和类:

{-# 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 .

我的第一次尝试是使用:
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 作为第一个类型参数):
-- 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。

最佳答案

所以首先,让我们重复一遍,你想为你派生的实例是这个:

instance MyEq (Wrapper Int) Wrapper where
eq (Wrapper t) (Wrapper t') = Wrapper (t == t')

我看不到完全按照您想要的方式派生类的方法,因为当您观察自己时,这需要您更改两个类参数,但我们目前只能通过最后一个派生。

一种可能性是翻转类参数,以便“重要”类参数(决定另一个的)成为最后一个,然后调整您派生的包装器类型以包含一些有用的信息,如下所示:
class MyEq f a | a -> f where
aeq :: a -> a -> f Bool

功能 aeq保留相同的类型,但 MyEq 的类参数被翻转。
现在 Wrapper2获取一个额外的参数让我们指定所需的值 f推导时:
newtype Wrapper2 (f :: Type -> Type) t = Wrapper2 t

现在是 Wrapper2 的实例无需明确指定即可定义 f :
instance (Eq t, Coercible Bool (f Bool)) => MyEq f (Wrapper2 f t) where
eq (Wrapper2 t) (Wrapper2 t') = coerce (t == t')
Wrapper2 中的额外参数这里需要满足函数依赖。

现在我们可以按如下方式导出所需的实例:
deriving via Wrapper2 Wrapper Int instance MyEq Wrapper (Wrapper Int)

这是有效的,因为现在,GHC 正在寻找 instance MyEq Wrapper (Wrapper2 Wrapper Int) ,这与我们拥有的相匹配
假如。

您可以使用关联类型实现相同的目的:
class MyEq a where
type Result a :: Type -> Type
eq :: a -> a -> Result a Bool

相同定义 Wrapper2带有额外的参数。实例变成
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)

关于Haskell DerivingVia 在多参数类型类上的乐趣 deps,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53009549/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com