Я играю с многожильным кодированием без тегов 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
я не понимаю.