Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell DerivingVia在多参数类型类上的应用_Haskell_Deriving - Fatal编程技术网

Haskell DerivingVia在多参数类型类上的应用

Haskell DerivingVia在多参数类型类上的应用,haskell,deriving,Haskell,Deriving,我正试图使用derivigvia为具有函数依赖关系的多参数类型类的实例定义切割样板文件 我有以下类型和类别: {-# LANGUAGE FunctionalDependencies #-} {-# LANGUAGE StandaloneDeriving #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE DerivingVia #-} newtype Wrapper

我正试图使用
derivigvia
为具有函数依赖关系的多参数类型类的实例定义切割样板文件

我有以下类型和类别:

{-# 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 Wrapper2 instance MyEq (Wrapper Int) Wrapper
正如本文第6.2节所讨论的,这将查找
MyEq(Wrapper Int)Wrapper2
实例,第二个参数已“更改”,但第一个参数仍然是
Wrapper Int

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

我不能通过创建(请参见
包装器
作为第一个类型参数)来“欺骗”:

因为在这种情况下,函数依赖项
Wrapper t->Wrapper 2
不受尊重


通过重写
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正在寻找 一个
实例MyEq包装器(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)

第二种解决方案似乎需要
不可判定的实例
。它们不是都需要吗?不可判定的实例是无害的,所以我不担心它。
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)