Un bel fatto vero sulla concatenazione è che se conosco due variabili nell'equazione:
a ++ b = c
Allora conosco il terzo.
Vorrei catturare questa idea nel mio concat così uso una dipendenza funzionale.
{-# 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
Ora evoco un elenco eterogeneo in questo modo:
data HList ( as :: [ Type ] ) where
HEmpty :: HList '[]
HCons :: a -> HList as -> HList (a ': as)
Ma quando provo a dichiararli perché Concatableho un problema
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)
Non soddisfo la mia terza dipendenza funzionale. O meglio, il compilatore ritiene che non lo facciamo. Questo perché il compilatore ritiene che nella nostra seconda istanza potrebbe essere così bs ~ (a ': cs). E potrebbe essere il caso se Concatable as (a ': cs) cs.
Come posso adattare le mie istanze in modo che tutte e tre le dipendenze siano soddisfatte?
bse cs, e vogliamo sfruttare il fondo, cioè vogliamo ricostruire as. Per farlo in modo deterministico, ci aspettiamo di essere in grado di impegnarci in una singola istanza e seguire quella ricetta. Concretamente, assumere bs = (Int ': bs2)e cs = (Int ': cs2). Quale istanza scegliamo? È possibile che tale Intnel csproviene bs(ed asè vuoto). È anche possibile che provenga da (non vuoto) ase che Intapparirà di nuovo in csseguito. Dobbiamo scavare più a fondo csper sapere e GHC non lo farà.
bs cs -> as, perché abbiamo bisogno di informazioni non locali subsecsper decidere seasdovrebbe essere un contro o uno zero. Dobbiamo scoprire come rappresentare queste informazioni; quale contesto aggiungeremmo a una firma di tipo per garantirlo quando non può essere dedotto direttamente?