Un buen hecho verdadero sobre la concatenación es que si conozco dos variables en la ecuación:
a ++ b = c
Entonces sé el tercero.
Me gustaría capturar esta idea en mi propia concat, así que uso una dependencia funcional.
{-# 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
Ahora conjuro una lista heterogénea así:
data HList ( as :: [ Type ] ) where
HEmpty :: HList '[]
HCons :: a -> HList as -> HList (a ': as)
Pero cuando trato de declarar esto ya Concatableque tengo 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)
No satisfago mi tercera dependencia funcional. O más bien, el compilador cree que nosotros no. Esto se debe a que el compilador cree que en nuestra segunda instancia podría ser el caso bs ~ (a ': cs). Y podría ser el caso si Concatable as (a ': cs) cs.
¿Cómo puedo ajustar mis instancias para que se satisfagan las tres dependencias?
bsy csqueremos explotar el fundep, es decir, queremos reconstruir as. Para hacerlo de una manera determinista, esperamos poder comprometernos con una sola instancia y seguir esa receta. Concretamente, asumir bs = (Int ': bs2)y cs = (Int ': cs2). ¿Qué instancia elegimos? Es posible que tal Inten csproviene de bs(y asestá vacía). También es posible que provenga de (no vacío) asy que Intvuelva a aparecer más csadelante. Necesitamos profundizar cspara saber y GHC no lo hará.
bs cs -> as, porque necesitamos información no local sobrebsycsdecidir siasdebería ser una desventaja o no. Necesitamos descubrir cómo representar esta información; ¿Qué contexto agregaríamos a una firma de tipo para garantizarla cuando no se puede deducir directamente?