Birleştirme hakkında güzel bir gerçek gerçeği, denklemde herhangi bir iki değişken biliyorsanız:
a ++ b = c
Sonra üçüncüyü biliyorum.
Bu fikri kendi aklımda yakalamak istiyorum, böylece işlevsel bir bağımlılık kullanıyorum.
{-# 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
Şimdi ben heterojen liste şöyle çağrıştırın:
data HList ( as :: [ Type ] ) where
HEmpty :: HList '[]
HCons :: a -> HList as -> HList (a ': as)
Ama bunları Concatable
bir sorun olarak ilan etmeye çalıştığımda
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)
Üçüncü fonksiyonel bağımlılığımı tatmin etmiyorum. Daha doğrusu derleyici bizim yapmadığımıza inanıyor. Bunun nedeni, derleyicinin ikinci örneğimizde durumun böyle olabileceğine inanmasıdır bs ~ (a ': cs)
. Ve eğer durum böyle olabilir Concatable as (a ': cs) cs
.
Örneklerimi üç bağımlılığın da karşılanması için nasıl ayarlayabilirim?
bs
ve cs
fundep'ten yararlanmak istediğimizi, yani yeniden inşa etmek istediğimizi hayal edin as
. Bunu deterministik bir şekilde yapmak için, tek bir örnek vermeyi ve bu tarifi takip etmeyi umuyoruz. Somut olarak, varsayalım bs = (Int ': bs2)
ve cs = (Int ': cs2)
. Hangi örneği seçiyoruz? Böyle olması mümkündür Int
içinde cs
gelir bs
(ve as
boş). Bunun as
yerine (boş) da olabilir ve daha sonra Int
tekrar ortaya çıkacaktır cs
. cs
Bilmek için daha derine inmemiz gerekiyor ve GHC bunu yapmayacak.
bs cs -> as
, çünkü eksileri veya sıfır olması konusunda yerel olmayan bilgilere ihtiyacımız varbs
vecs
karar vermemiz gerekiyoras
. Bu bilgileri nasıl temsil edeceğimizi bulmamız gerekiyor; doğrudan çıkarılamadığında garanti altına almak için bir tip imzasına hangi bağlam ekleriz?