Un beau fait vrai sur la concaténation est que si je connais deux variables dans l'équation:
a ++ b = c
Alors je connais le troisième.
Je voudrais capturer cette idée dans mon propre concat donc j'utilise une dépendance fonctionnelle.
{-# Language DataKinds, GADTs, FlexibleContexts, FlexibleInstances, FunctionalDependencies, KindSignatures, PolyKinds, TypeOperators, UndecidableInstances #-}
import Data.Kind (Type)
class Concatable
(m :: k -> Type)
(as :: k)
(bs :: k)
(cs :: k)
| as bs -> cs
, as cs -> bs
, bs cs -> as
where
concat' :: m as -> m bs -> m cs
Maintenant, j'évoque une liste hétérogène comme ceci:
data HList ( as :: [ Type ] ) where
HEmpty :: HList '[]
HCons :: a -> HList as -> HList (a ': as)
Mais quand j'essaye de les déclarer car Concatablej'ai un problème
instance Concatable HList '[] bs bs where
concat' HEmpty bs = bs
instance
( Concatable HList as bs cs
)
=> Concatable HList (a ': as) bs (a ': cs)
where
concat' (HCons head tail) bs = HCons head (concat' tail bs)
Je ne satisfait pas ma troisième dépendance fonctionnelle. Ou plutôt le compilateur pense que non. C'est parce que le compilateur pense que dans notre deuxième cas, cela pourrait être le cas bs ~ (a ': cs). Et cela pourrait être le cas si Concatable as (a ': cs) cs.
Comment puis-je ajuster mes instances afin que les trois dépendances soient satisfaites?
bset cs, et nous voulons exploiter le fundep, c'est-à-dire que nous voulons reconstruire as. Pour le faire de manière déterministe, nous nous attendons à pouvoir nous engager sur une seule instance et suivre cette recette. Concrètement, supposez bs = (Int ': bs2)et cs = (Int ': cs2). Quelle instance choisissons-nous? Il est possible qu'une telle Intentrée csvienne de bs(et assoit vide). Il est également possible que cela vienne de (non vide) à la asplace, et cela Intréapparaîtra plus cstard. Nous devons approfondir cspour savoir et GHC ne le fera pas.
bs cs -> as, car nous avons besoin d'informations non locales surbsetcspour décider si celaasdevrait être un contre ou un zéro. Nous devons découvrir comment représenter ces informations; quel contexte ajouter à une signature de type pour la garantir lorsqu'elle ne peut pas être directement déduite?