我在玩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我可以为Free Semigroup和Free Monoid编写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的某些方面我不明白。
发布于 2019-06-13 05:25:08
错误消息声明这些错误来自于sconcat和stimes的默认定义。量化的上下文就像instance:在您的instance Semigroup (Free cls v)中,就好像在作用域中有一个instance cls v => Semigroup v。通过匹配选择instances。sconcat和stimes想要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]要暗。我认为,加入第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实例耗尽之后,它被认为是最后的手段。
https://stackoverflow.com/questions/56573436
复制相似问题