gpt4 book ai didi

haskell - 为什么使用 QuantifiedConstraints 指定类型类的子类还需要子类的实例?

转载 作者:行者123 更新时间:2023-12-03 06:51:18 26 4
gpt4 key购买 nike

我正在尝试 Free 的多种无标记编码

{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE TypeSynonymInstances #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE Rank2Types #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE QuantifiedConstraints #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE TypeOperators #-}
module Free where
import GHC.Types

type (a :: k) ~> (b :: k) = Morphism k a b

newtype Natural (f :: j -> k) (g :: j -> k) =
Natural { getNatural :: forall (x :: j). f x ~> g x }

type family Morphism k :: k -> k -> Type where
Morphism Type = (->)
Morphism (j -> k) = Natural

class DataKind k where
data Free :: (k -> Constraint) -> k -> k
interpret :: forall (cls :: k -> Constraint) (u :: k) (v :: k).
cls v => (u ~> v) -> (Free cls u ~> v)
call :: forall (cls :: k -> Constraint) (u :: k).
u ~> Free cls u

instance DataKind Type where
newtype Free cls u = Free0
{ runFree0 :: forall v. cls v => (u ~> v) -> v }
interpret f = \(Free0 g) -> g f
call = \u -> Free0 $ \f -> f u

我可以写Semigroup Free Semigroup 的实例和Free Monoid没有问题:

instance Semigroup (Free Semigroup u) where
Free0 g <> Free0 g' = Free0 $ \f -> g f <> g' f

instance Semigroup (Free Monoid u) where
Free0 g <> Free0 g' = Free0 $ \f -> g f <> g' f

这些实例是相同的,并且适用于Semigroup的任何其他子类。 。

我想使用QuantifiedConstraints所以我可以为 Semigroup 的所有子类编写一个实例:

instance (forall v. cls v => Semigroup v) => Semigroup (Free cls u) where
Free0 g <> Free0 g' = Free0 $ \f -> g f <> g' f

但是编译器 (GHC-8.6.3) 提示它无法推导出 cls (Free cls u) :

Free.hs:57:10: error:
• Could not deduce: cls (Free cls u)
arising from a use of ‘GHC.Base.$dmsconcat’
from the context: forall v. cls v => Semigroup v
bound by the instance declaration at Free.hs:57:10-67
• In the expression: GHC.Base.$dmsconcat @(Free cls u)
In an equation for ‘GHC.Base.sconcat’:
GHC.Base.sconcat = GHC.Base.$dmsconcat @(Free cls u)
In the instance declaration for ‘Semigroup (Free cls u)’
• Relevant bindings include
sconcat :: GHC.Base.NonEmpty (Free cls u) -> Free cls u
(bound at Free.hs:57:10)
|
57 | instance (forall v. cls v => Semigroup v) => Semigroup (Free cls u) where
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Free.hs:57:10: error:
• Could not deduce: cls (Free cls u)
arising from a use of ‘GHC.Base.$dmstimes’
from the context: forall v. cls v => Semigroup v
bound by the instance declaration at Free.hs:57:10-67
or from: Integral b
bound by the type signature for:
GHC.Base.stimes :: forall b.
Integral b =>
b -> Free cls u -> Free cls u
at Free.hs:57:10-67
• In the expression: GHC.Base.$dmstimes @(Free cls u)
In an equation for ‘GHC.Base.stimes’:
GHC.Base.stimes = GHC.Base.$dmstimes @(Free cls u)
In the instance declaration for ‘Semigroup (Free cls u)’
• Relevant bindings include
stimes :: b -> Free cls u -> Free cls u (bound at Free.hs:57:10)
|
57 | instance (forall v. cls v => Semigroup v) => Semigroup (Free cls u) where
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

当我将其添加为实例的上下文时,它可以正常编译:

instance (cls (Free cls u), forall v. cls v => Semigroup v) => Semigroup (Free cls u) where
Free0 g <> Free0 g' = Free0 $ \f -> g f <> g' f

添加的上下文有点冗长,但由于 Free 的全部要点是cls (Free cls u)总是真实的,并不繁琐。

我不明白的是为什么 GHC 需要能够得出结论 cls (Free cls u)对于 Semigroup 的子类对于Semigroup要编译的实例。我尝试替换 (<>) 的定义与 undefined并得到了同样的错误,所以我认为问题不在于实现本身,而在于实例的声明;可能是由于 QuantifiedConstraints 的某些方面我不明白。

最佳答案

错误消息指出这些错误来自 sconcat 的默认定义和stimes 。量化上下文的行为类似于 instance s:在您的instance Semigroup (Free cls v)内,就好像有一个instance cls v => Semigroup v在适用范围。 instance s 通过匹配来选择。 sconcatstimes想要Semigroup (Free cls v) ,因此它们与上下文 instance forall z. cls z => Semigroup z 相匹配。 ,成功 z ~ Free cls v ,并进一步通缉cls (Free cls v) 。即使我们也有递归instance _etc => Semigroup (Free cls v),也会发生这种情况大约。请记住,我们假设类型类实例是一致的;无论是使用量化上下文还是使用当前定义的实例,都应该没有区别,因此 GHC 只是选择它想要使用的实例。

然而,这并不是一个好的情况。量化的上下文与我们的实例重叠(实际上,它与每个Semigroup实例重叠),这是令人震惊的。如果您尝试类似 (<>) = const (Free0 _etc) ([1, 2] <> [3, 4]) ,您会得到类似的错误,因为量化的上下文掩盖了真实的 instance Semigroup [a]在图书馆。我认为包括来自 issue 14877 的一些想法可以让这不那么不舒服:

class (a => b) => Implies a b
instance (a => b) => Implies a b
instance (forall v. cls v `Implies` Semigroup v) => Semigroup (Free cls u) where
Free0 g <> Free0 g' = Free0 $ \f -> g f <> g' f

使用Implies这里意味着量化的上下文不再符合 Semigroup (Free cls v) 的需求。而是通过递归来释放。但是,约束背后的要求不会改变。本质上,我们为用户保留量化约束的需求片段,即 Semigroup v应该由 cls v 暗示,同时在放电片段上施加安全性以进行实现,因此它不会扰乱我们的约束解析。 Implies约束仍然可以而且必须用来证明 Semigroup v (<>) 中的约束,但它被认为是显式 Semigroup 之后的最后手段实例已耗尽。

关于haskell - 为什么使用 QuantifiedConstraints 指定类型类的子类还需要子类的实例?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56573436/

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