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ı Concatablebir 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?
bsve csfundep'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 Intiçinde csgelir bs(ve asboş). Bunun asyerine (boş) da olabilir ve daha sonra Inttekrar ortaya çıkacaktır cs. csBilmek 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 varbsvecskarar 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?