gpt4 book ai didi

haskell - 通过 DeriveAnyClass 派生的行为与 emply 实例声明不同

转载 作者:行者123 更新时间:2023-12-02 02:53:52 24 4
gpt4 key购买 nike

我有以下代码

{-# LANGUAGE PolyKinds, DefaultSignatures, FlexibleContexts, DeriveAnyClass, DeriveGeneric #-}
{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, UndecidableInstances #-}
module DeriveTest where

import GHC.Generics

class GenericClass a m where
instance GenericClass f m => GenericClass (M1 i c f) m
instance Condition a m => GenericClass (K1 i a) m

class Condition (a :: k) (m :: * -> *) where
instance (Condition a m, Condition b m) => Condition (a b) m
instance {-# OVERLAPPABLE #-} Condition (a :: k) m

class Class (e :: (* -> *) -> *) where
classF :: e m -> ()
default classF :: GenericClass (Rep (e m)) m => e m -> ()
classF = undefined

它定义了类型的类 Class,这些类型具有更高种类的类型作为参数。它还定义了派生该类实例的通用方法。现在,如果我像这样声明一个新的数据类型,并尝试派生 Class

的实例
data T a m = T
{ field :: a }
deriving (Generic, Class)

我收到以下错误:

    * Overlapping instances for Condition a m
arising from the 'deriving' clause of a data type declaration
Matching instances:
instance [overlappable] forall k (a :: k) (m :: * -> *).
Condition a m
instance forall k1 k2 (a :: k1 -> k2) (m :: * -> *) (b :: k1).
(Condition a m, Condition b m) =>
Condition (a b) m
(The choice depends on the instantiation of `a, m'
To pick the first instance above, use IncoherentInstances
when compiling the other instance declarations)
* When deriving the instance for (Class (T a))
|
22 | deriving (Generic, Class)
| ^^^^^

这个错误是有道理的,因为我猜。该实例确实依赖于 a 的实例化。但是,如果我只是像这样写一个空实例:

data T a m = T
{ field :: a }
deriving (Generic)
instance Class (T a) -- works

它有效。为什么?我怎样才能使它的行为与派生语句相同?

这是使用 GHC 8.2.2

最佳答案

我不认为 DeriveAnyClass 是罪魁祸首。我相信真正的罪魁祸首是 GHC 围绕重叠实例的不可预测的行为。为了明白我的意思,让我们将 classF 的默认实现分解到它自己的函数中:

class Class (e :: (* -> *) -> *) where
classF :: e m -> ()
default classF :: GenericClass (Rep (e m)) m => e m -> ()
classF = classFDefault

classFDefault :: forall (e :: (* -> *) -> *) (m :: * -> *).
GenericClass (Rep (e m)) m => e m -> ()
classFDefault = undefined

现在,根据您对 T 的定义:

data T a m = T
{ field :: a }
deriving (Generic)

观察这个类型检查:

instance Class (T a) where
classF = classFDefault

但这不是!

classFT :: forall a (m :: * -> *).
T a m -> ()
classFT = classFDefault

后者失败并出现与您尝试使用 deriving 子句派生 Class 时相同的错误。不幸的是,我不知道为什么 GHC 接受前者而拒绝后者,所以我只能猜测 GHC 在类型检查时对如何使用重叠实例相当挑剔,而 GHC 在试图解决一个问题时恰好心情不好Condition a m 以某种方式约束。

可能值得在 GHC issue tracker 上提交错误关于这个。

关于haskell - 通过 DeriveAnyClass 派生的行为与 emply 实例声明不同,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50557019/

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