ฉันไม่เห็น syntactic รุ่นที่ตีพิมพ์ใด ๆ ที่มีลายเซ็นสำหรับsugarSym
ใช้ชื่อประเภทที่แน่นอนเหล่านั้นดังนั้นฉันจะใช้สาขาการพัฒนาที่ commit 8cfd02 ^เวอร์ชันสุดท้ายที่ยังคงใช้ชื่อเหล่านั้น
แล้วทำไม GHC ถึงบ่นเกี่ยวกับfi
ลายเซ็นในแบบของคุณ แต่ไม่ใช่แบบนั้นsugarSym
? เอกสารที่คุณเชื่อมโยงเพื่ออธิบายว่าประเภทนั้นคลุมเครือหากไม่ปรากฏทางด้านขวาของข้อ จำกัด เว้นแต่ข้อ จำกัด นั้นใช้การพึ่งพาการทำงานเพื่ออนุมานชนิดที่ไม่ชัดเจนจากประเภทที่ไม่ชัดเจนอื่น ๆ ลองเปรียบเทียบบริบทของทั้งสองฟังก์ชั่นและค้นหาการพึ่งพาการทำงาน
class ApplySym sig f sym | sig sym -> f, f -> sig sym
class SyntacticN f internal | f -> internal
sugarSym :: ( sub :<: AST sup
, ApplySym sig fi sup
, SyntacticN f fi
)
=> sub sig -> f
share :: ( Let :<: sup
, sup ~ Domain b
, sup ~ Domain a
, Syntactic a
, Syntactic b
, Syntactic (a -> b)
, SyntacticN (a -> (a -> b) -> b) fi
)
=> a -> (a -> b) -> b
ดังนั้นสำหรับsugarSym
ประเภทที่ไม่ใช่คลุมเครืออยู่sub
, sig
และf
และจากคนที่เราควรจะสามารถที่จะปฏิบัติตามการอ้างอิงในการทำงานเพื่อให้กระจ่างทุกประเภทที่อื่น ๆ ที่ใช้ในบริบทคือและsup
fi
และแท้จริงแล้วการf -> internal
พึ่งพาฟังก์ชั่นในการSyntacticN
ใช้งานของเราในการf
ทำให้กระจ่างของเราfi
และหลังจากนั้นการf -> sig sym
พึ่งพาการทำงานในการApplySym
ใช้งานของเราใหม่ disambiguated fi
เพื่อ disambiguate sup
(และsig
ซึ่งก็ไม่ชัดเจน) เพื่ออธิบายว่าทำไมsugarSym
ไม่ต้องการAllowAmbiguousTypes
ส่วนขยาย
sugar
ตอนนี้ขอให้ดูที่ สิ่งแรกที่ฉันสังเกตได้คือคอมไพเลอร์ไม่ได้บ่นเกี่ยวกับประเภทที่คลุมเครือ แต่เกี่ยวกับอินสแตนซ์ที่ทับซ้อนกัน:
Overlapping instances for SyntacticN b fi
arising from the ambiguity check for ‘share’
Matching givens (or their superclasses):
(SyntacticN (a -> (a -> b) -> b) fi1)
Matching instances:
instance [overlap ok] (Syntactic f, Domain f ~ sym,
fi ~ AST sym (Full (Internal f))) =>
SyntacticN f fi
-- Defined in ‘Data.Syntactic.Sugar’
instance [overlap ok] (Syntactic a, Domain a ~ sym,
ia ~ Internal a, SyntacticN f fi) =>
SyntacticN (a -> f) (AST sym (Full ia) -> fi)
-- Defined in ‘Data.Syntactic.Sugar’
(The choice depends on the instantiation of ‘b, fi’)
To defer the ambiguity check to use sites, enable AllowAmbiguousTypes
ดังนั้นหากฉันกำลังอ่านสิ่งนี้ถูกต้องไม่ใช่ GHC คิดว่าประเภทของคุณไม่ชัดเจน แต่แทนที่จะตรวจสอบว่าประเภทของคุณไม่ชัดเจนหรือไม่ GHC พบปัญหาแยกต่างหาก จากนั้นจะบอกคุณว่าหากคุณบอกให้ GHC ไม่ทำการตรวจสอบความกำกวมก็จะไม่พบปัญหาแยกต่างหาก สิ่งนี้อธิบายว่าทำไมการเปิดใช้งาน AllowAmbiguousTypes ทำให้โค้ดของคุณรวบรวม
อย่างไรก็ตามปัญหาของอินสแตนซ์ที่ทับซ้อนกันยังคงอยู่ อินสแตนซ์สองรายการที่ระบุโดย GHC ( SyntacticN f fi
และSyntacticN (a -> f) ...
) ทำทับซ้อนกัน น่าแปลกที่ดูเหมือนว่าครั้งแรกของสิ่งเหล่านี้จะทับซ้อนกับอินสแตนซ์อื่น ๆ ที่น่าสงสัย และ[overlap ok]
หมายความว่าอย่างไร
ฉันสงสัยว่า Syntactic ถูกคอมไพล์ด้วย OverlappingInstance และดูที่รหัสแน่นอนมันทำ
จากการทดลองเล็กน้อยดูเหมือนว่า GHC นั้นโอเคกับอินสแตนซ์ที่ทับซ้อนกันเมื่อเห็นได้ชัดว่า GHC นั้นมีความทั่วไปที่เข้มงวดกว่าอีกอันหนึ่ง:
{-# LANGUAGE FlexibleInstances, OverlappingInstances #-}
class Foo a where
whichOne :: a -> String
instance Foo a where
whichOne _ = "a"
instance Foo [a] where
whichOne _ = "[a]"
-- |
-- >>> main
-- [a]
main :: IO ()
main = putStrLn $ whichOne (undefined :: [Int])
แต่ GHC นั้นไม่เป็นไรกับอินสแตนซ์ที่ทับซ้อนกันเมื่อไม่เหมาะสมอย่างชัดเจนกว่าแบบอื่น:
{-# LANGUAGE FlexibleInstances, OverlappingInstances #-}
class Foo a where
whichOne :: a -> String
instance Foo (f Int) where -- this is the line which changed
whichOne _ = "f Int"
instance Foo [a] where
whichOne _ = "[a]"
-- |
-- >>> main
-- Error: Overlapping instances for Foo [Int]
main :: IO ()
main = putStrLn $ whichOne (undefined :: [Int])
การใช้ลายเซ็นของคุณชนิดSyntacticN (a -> (a -> b) -> b) fi
และค่าSyntacticN f fi
มิได้SyntacticN (a -> f) (AST sym (Full ia) -> fi)
เป็นแบบที่ดีขึ้นกว่าที่อื่น ๆ หากฉันเปลี่ยนส่วนหนึ่งของประเภทลายเซ็นของคุณเป็นSyntacticN a fi
หรือSyntacticN (a -> (a -> b) -> b) (AST sym (Full ia) -> fi)
GHC จะไม่บ่นเกี่ยวกับการทับซ้อนอีกต่อไป
หากฉันเป็นคุณฉันจะดูคำจำกัดความของอินสแตนซ์ที่เป็นไปได้ทั้งสองนั้นและพิจารณาว่าการใช้งานหนึ่งในสองอย่างนั้นเป็นสิ่งที่คุณต้องการหรือไม่
sugarSym Let
ซึ่งเป็น(SyntacticN f (ASTF sup a -> ASTF sup (a -> b) -> ASTF sup b), Let :<: sup) => f
และไม่เกี่ยวข้องกับตัวแปรประเภทที่ไม่ชัดเจน?