Приємний справжній факт конкатенації полягає в тому, що якщо я знаю будь-які дві змінні рівняння:
a ++ b = c
Тоді я знаю третє.
Я хотів би зафіксувати цю ідею у власному стислі, тому я використовую функціональну залежність.
{-# 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
Тепер я розглядаю неоднорідний список так:
data HList ( as :: [ Type ] ) where
HEmpty :: HList '[]
HCons :: a -> HList as -> HList (a ': as)
Але коли я намагаюся заявити про це, коли у Concatable
мене є питання
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)
Я не задовольняю свою третю функціональну залежність. А точніше, компілятор вважає, що ми цього не робимо. Це тому, що компілятор вважає, що в нашому другому випадку це може бути саме так bs ~ (a ': cs)
. І це може бути так, якби Concatable as (a ': cs) cs
.
Як я можу налаштувати свої випадки так, щоб усі три залежності були задоволені?
bs
і cs
, і ми хочемо використовувати фундамент, тобто ми хочемо реконструювати as
. Щоб зробити це детермінованим способом, ми очікуємо, що зможемо взяти на себе окремий екземпляр і дотримуватись цього рецепта. Конкретно, припустимо bs = (Int ': bs2)
і cs = (Int ': cs2)
. Який екземпляр ми обираємо? Можливо, що таке Int
в cs
приходить від bs
(і as
порожнє). Можливо також, що as
натомість походить із (непустого) , а потім Int
з’явиться знову cs
. Нам потрібно пірнути глибше, cs
щоб знати, і GHC цього не зробить.
bs cs -> as
тому, що нам потрібна не місцева інформація проbs
таcs
вирішити, чиas
має бути мінус чи нуль. Нам потрібно з'ясувати, як представити цю інформацію; який контекст ми б додали до підпису типу, щоб гарантувати його, коли його неможливо безпосередньо вивести?