ความจริงที่ดีเกี่ยวกับการต่อเรียงคือถ้าฉันรู้ว่ามีสองตัวแปรในสมการ:
a ++ b = c
จากนั้นฉันก็รู้สาม
ฉันต้องการที่จะจับภาพความคิดนี้ใน concat ของตัวเองดังนั้นฉันจึงใช้การพึ่งพาการทำงาน
{-# 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
และเราต้องการที่จะใช้ประโยชน์จาก fundep as
คือเราต้องการที่จะสร้างใหม่ หากต้องการดำเนินการในลักษณะที่กำหนดขึ้นมาเราคาดว่าจะสามารถส่งมอบอินสแตนซ์เดียวและทำตามสูตรนั้นได้ รูปธรรมสมมติและbs = (Int ': bs2)
cs = (Int ': cs2)
เราเลือกอินสแตนซ์ใด มันเป็นไปได้ที่ดังกล่าวInt
ในcs
มาจากbs
(และas
เป็นที่ว่างเปล่า) นอกจากนี้ยังเป็นไปได้ที่มาจาก (ไม่ว่างเปล่า) as
และInt
จะปรากฏขึ้นอีกครั้งในcs
ภายหลัง เราต้องเจาะลึกลงcs
ไปเพื่อรู้และ GHC จะไม่ทำเช่นนั้น
bs cs -> as
เพราะเราต้องการข้อมูลที่ไม่ใช่ท้องถิ่นเกี่ยวกับbs
และcs
ตัดสินใจว่าas
ควรจะเป็นข้อเสียหรือศูนย์ เราจำเป็นต้องค้นหาวิธีการนำเสนอข้อมูลนี้ เราจะเพิ่มบริบทใดลงในลายเซ็นประเภทเพื่อรับประกันเมื่อไม่สามารถอนุมานได้โดยตรง