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 Concatable
j'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?
bs
et 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 Int
entrée cs
vienne de bs
(et as
soit vide). Il est également possible que cela vienne de (non vide) à la as
place, et cela Int
réapparaîtra plus cs
tard. Nous devons approfondir cs
pour savoir et GHC ne le fera pas.
bs cs -> as
, car nous avons besoin d'informations non locales surbs
etcs
pour décider si celaas
devrait ê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?