मैं सचमुच कार्यान्वित करने के लिए या Constraint
एस के लिए नहीं सोच सकता, दुर्भाग्य से, लेकिन यदि हम आपके उदाहरण में समानता के समान हैं या नहीं, तो हम आपके प्रकार के वर्ग दृष्टिकोण को मसाला कर सकते हैं और इसे बना सकते हैं प्रकार परिवारों और उठाए गए बूलियन के साथ बंद कर दिया। यह केवल जीएचसी 7.6 और ऊपर काम करेगा; अंत में, मैं दोनों का उल्लेख करता हूं कि यह जीएचसी 7.8 में कैसे अच्छा होगा और इसे जीएचसी 7.4 में कैसे बैकपोर्ट करना है।
विचार यह है: बस के रूप में हम एक मूल्य के स्तर के समारोह isBananaColor :: Color -> Bool
घोषित कर सकता है, तो भी हम एक प्रकार स्तरीय समारोह IsBananaColor :: Color -> Bool
घोषणा कर सकते हैं:
type family IsBananaColor (c :: Color) :: Bool
type instance IsBananaColor Green = True
type instance IsBananaColor Yellow = True
type instance IsBananaColor Black = True
type instance IsBananaColor White = False
type instance IsBananaColor Red = False
type instance IsBananaColor Blue = False
type instance IsBananaColor Tawny = False
type instance IsBananaColor Purple = False
अगर हम चाहते हैं, तो हम भी
जोड़ सकते हैं
type BananaColor c = IsBananaColor c ~ True
हम तो यह हर फल रंग के लिए दोहराएँ, और अपने दूसरे उदाहरण में दिखाया Fruit
को परिभाषित:
{-# LANGUAGE GADTs #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE TypeFamilies #-}
data Color = White | Red | Blue | Yellow | Green | Tawny | Purple | Black
data Fruit (c :: Color) where
Banana :: BananaColor c => Fruit c
Apple :: AppleColor c => Fruit c
Grape :: GrapeColor c => Fruit c
Orange :: OrangeColor c => Fruit c
type family IsBananaColor (c :: Color) :: Bool
type instance IsBananaColor Green = True
type instance IsBananaColor Yellow = True
type instance IsBananaColor Black = True
type instance IsBananaColor White = False
type instance IsBananaColor Red = False
type instance IsBananaColor Blue = False
type instance IsBananaColor Tawny = False
type instance IsBananaColor Purple = False
type BananaColor c = IsBananaColor c ~ True
type family IsAppleColor (c :: Color) :: Bool
type instance IsAppleColor Red = True
type instance IsAppleColor Green = True
type instance IsAppleColor White = False
type instance IsAppleColor Blue = False
type instance IsAppleColor Yellow = False
type instance IsAppleColor Tawny = False
type instance IsAppleColor Purple = False
type instance IsAppleColor Black = False
type AppleColor c = IsAppleColor c ~ True
type family IsGrapeColor (c :: Color) :: Bool
type instance IsGrapeColor Red = True
type instance IsGrapeColor Green = True
type instance IsGrapeColor White = True
type instance IsGrapeColor Blue = False
type instance IsGrapeColor Yellow = False
type instance IsGrapeColor Tawny = False
type instance IsGrapeColor Purple = False
type instance IsGrapeColor Black = False
type GrapeColor c = IsGrapeColor c ~ True
-- For consistency
type family IsOrangeColor (c :: Color) :: Bool
type instance IsOrangeColor Tawny = True
type instance IsOrangeColor White = False
type instance IsOrangeColor Red = False
type instance IsOrangeColor Blue = False
type instance IsOrangeColor Yellow = False
type instance IsOrangeColor Green = False
type instance IsOrangeColor Purple = False
type instance IsOrangeColor Black = False
type OrangeColor c = IsOrangeColor c ~ True
(यदि आप चाहते हैं, तो आप -XConstraintKinds
से छुटकारा प्राप्त कर सकते हैं और type XYZColor c = IsXYZColor c ~ True
प्रकार, और बस के रूप में XYZ :: IsXYZColor c ~ True => Fruit c
Fruit
की कंस्ट्रक्टर्स परिभाषित करते हैं।)
अब, क्या करता है यह आप खरीद, और क्या यह आप उसे खरीद नहीं ? प्लस तरफ, आपको अपने प्रकार को परिभाषित करने की क्षमता मिलती है जैसा आप चाहते हैं, जो निश्चित रूप से एक जीत है; और चूंकि Color
बंद है, कोई भी परिवार के उदाहरणों को और अधिक प्रकार जोड़ सकता है और इसे तोड़ सकता है।
हालांकि, डाउनसाइड्स हैं। आपको वह अनुमान नहीं मिलता है जिसे आप स्वचालित रूप से बता रहे थे कि [Apple, Grape, Banana]
Fruit Green
प्रकार का है; इससे भी बदतर यह है कि [Apple, Grape, Banana]
में पूरी तरह वैध प्रकार (AppleColor c, GrapeColor c, BananaColor c) => [Fruit c]
है। हां, इसका मोनोमोर्फिज़ करने का कोई तरीका नहीं है, लेकिन जीएचसी इसे समझ नहीं सकता है। पूरी तरह ईमानदार होने के लिए, मैं आपको इन गुणों को देने वाले किसी भी समाधान की कल्पना नहीं कर सकता, हालांकि मैं हमेशा आश्चर्यचकित होने के लिए तैयार हूं। इस समाधान के साथ अन्य स्पष्ट समस्या यह है कि कैसे लंबे यह है- आपको प्रत्येक IsXYZColor
प्रकार परिवार के लिए सभी आठ रंगों के मामलों को परिभाषित करने की आवश्यकता है! (प्रत्येक के लिए एक नया प्रकार परिवार के इस्तेमाल को भी परेशान है, लेकिन इस फार्म के समाधान के साथ अपरिहार्य है।)
मुझे लगता है कि GHC 7 ऊपर उल्लेख किया है।8 यह अच्छा बनाने वाला है; यह प्रत्येक एकल IsXYZColor
कक्षा के लिए प्रत्येक मामले को सूचीबद्ध करने की आवश्यकता को रोक कर ऐसा करेगा। कैसे? खैर, रिचर्ड ईसेनबर्ग एट अल। ने पेश किया जीएचसी हेड में बंद ओवरलैपिंग प्रकार परिवारों को बंद कर दिया, और यह 7.8 में उपलब्ध होगा। इस विषय पर a paper in sumbission to POPL 2014 (और extended version) है, और रिचर्ड ने an introductory blog post भी लिखा है (जो पुराना वाक्यविन्यास प्रतीत होता है)।
विचार परिवार के उदाहरणों को सामान्य कार्यों की तरह घोषित करने की अनुमति देना है: समीकरणों को सभी को एक ही स्थान पर घोषित किया जाना चाहिए (खुली दुनिया धारणा को हटा देना) और क्रम में प्रयास किया जाता है, जो ओवरलैप की अनुमति देता है। जैसे
type family IsBananaColor (c :: Color) :: Bool
type instance IsBananaColor Green = True
type instance IsBananaColor Yellow = True
type instance IsBananaColor Black = True
type instance IsBananaColor c = False
कुछ, अस्पष्ट है क्योंकि IsBananaColor Green
मैचों दोनों पहली और आखिरी समीकरण; लेकिन एक सामान्य समारोह में, यह ठीक काम करेगा। इसलिए नए वाक्य रचना है: type family ... where { ... }
ब्लॉक प्रकार परिवार जिस तरह से आप यह निर्धारित करना चाहते हैं को परिभाषित करता है
type family IsBananaColor (c :: Color) :: Bool where
IsBananaColor Green = True
IsBananaColor Yellow = True
IsBananaColor Black = True
IsBananaColor c = False
कि; यह संकेत देता है कि ऊपर वर्णित अनुसार इस प्रकार का परिवार बंद, आदेशित और ओवरलैपिंग है।
{-# LANGUAGE GADTs #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeFamilies #-}
data Color = White | Red | Blue | Yellow | Green | Tawny | Purple | Black
data Fruit (c :: Color) where
Banana :: IsBananaColor c ~ True => Fruit c
Apple :: IsAppleColor c ~ True => Fruit c
Grape :: IsGrapeColor c ~ True => Fruit c
Orange :: IsOrangeColor c ~ True => Fruit c
type family IsBananaColor (c :: Color) :: Bool where
IsBananaColor Green = True
IsBananaColor Yellow = True
IsBananaColor Black = True
IsBananaColor c = False
type family IsAppleColor (c :: Color) :: Bool where
IsAppleColor Red = True
IsAppleColor Green = True
IsAppleColor c = False
type IsGrapeColor (c :: Color) :: Bool where
IsGrapeColor Red = True
IsGrapeColor Green = True
IsGrapeColor White = True
IsGrapeColor c = False
type family IsOrangeColor (c :: Color) :: Bool where
IsOrangeColor Tawny = True
IsOrangeColor c = False
हुर्रे, हम बोरियत से सोते बिना इस पढ़ सकते हैं: इस प्रकार, कोड GHC 7.8 में निम्नलिखित (अपरीक्षित, जैसा कि मैंने नहीं किया है यह मेरे मशीन पर स्थापित करते हैं) की तरह कुछ हो जाएगा! वास्तव में, आप देखेंगे कि मैंने इस कोड के लिए स्पष्ट IsXYZColor c ~ True
संस्करण पर स्विच किया है; मैंने ऐसा इसलिए किया क्योंकि अतिरिक्त चार प्रकार के समानार्थी शब्द के लिए बॉयलरप्लेट इन छोटी परिभाषाओं के साथ बहुत अधिक स्पष्ट और परेशान हो गया!
हालांकि, चलिए विपरीत दिशा में जाएं और इस कोड को उलझन में रखें। क्यूं कर? खैर, जीएचसी 7.4 (जो, हां, मेरे पास अभी भी मेरी मशीन पर है) गैर-*
परिणाम प्रकार वाले परिवारों का समर्थन नहीं करता है। इसके बजाय हम क्या कर सकते हैं? हम नकली के लिए प्रकार कक्षाओं और कार्यात्मक निर्भरताओं का उपयोग कर सकते हैं। विचार यह है कि IsBananaColor :: Color -> Bool
के बजाय, हमारे पास एक प्रकार का वर्ग IsBananaColor :: Color -> Bool -> Constraint
है, और हम रंग से बूलियन तक एक कार्यात्मक निर्भरता जोड़ते हैं। फिर IsBananaColor c b
संतोषजनक है अगर केवल IsBananaColor c ~ b
अच्छे संस्करण में; क्योंकि Color
बंद है और हमारे पास इसकी कार्यात्मक निर्भरता है, यह अभी भी हमें वही गुण देता है, यह केवल उलझन में है (हालांकि ज्यादातर अवधारणात्मक रूप से)। आगे के बिना, पूरा कोड:
{-# LANGUAGE GADTs #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE FlexibleContexts #-}
data Color = White | Red | Blue | Yellow | Green | Tawny | Purple | Black
data Fruit (c :: Color) where
Banana :: BananaColor c => Fruit c
Apple :: AppleColor c => Fruit c
Grape :: GrapeColor c => Fruit c
Orange :: OrangeColor c => Fruit c
class IsBananaColor (c :: Color) (b :: Bool) | c -> b
instance IsBananaColor Green True
instance IsBananaColor Yellow True
instance IsBananaColor Black True
instance IsBananaColor White False
instance IsBananaColor Red False
instance IsBananaColor Blue False
instance IsBananaColor Tawny False
instance IsBananaColor Purple False
type BananaColor c = IsBananaColor c True
class IsAppleColor (c :: Color) (b :: Bool) | c -> b
instance IsAppleColor Red True
instance IsAppleColor Green True
instance IsAppleColor White False
instance IsAppleColor Blue False
instance IsAppleColor Yellow False
instance IsAppleColor Tawny False
instance IsAppleColor Purple False
instance IsAppleColor Black False
type AppleColor c = IsAppleColor c True
class IsGrapeColor (c :: Color) (b :: Bool) | c -> b
instance IsGrapeColor Red True
instance IsGrapeColor Green True
instance IsGrapeColor White True
instance IsGrapeColor Blue False
instance IsGrapeColor Yellow False
instance IsGrapeColor Tawny False
instance IsGrapeColor Purple False
instance IsGrapeColor Black False
type GrapeColor c = IsGrapeColor c True
class IsOrangeColor (c :: Color) (b :: Bool) | c -> b
instance IsOrangeColor Tawny True
instance IsOrangeColor White False
instance IsOrangeColor Red False
instance IsOrangeColor Blue False
instance IsOrangeColor Yellow False
instance IsOrangeColor Green False
instance IsOrangeColor Purple False
instance IsOrangeColor Black False
type OrangeColor c = IsOrangeColor c True
आप को देखा है [GHC 7.4 + की तरह प्रचार सुविधा] (http://www.haskell.org/ghc/docs/7.6। 1/html/users_guide/promotion.html)? यह प्रकारों को प्रकार के रूप में, और मानों के रूप में मानने की अनुमति देता है। '-XDataKinds' के साथ, 'ग्रीन' दयालु 'रंग' की एक पूरी तरह से मान्य प्रकार-स्तर की चीज़ है। इससे टाइप-स्तरीय प्रोग्रामिंग अधिक प्रकार-सुरक्षित हो जाती है (क्योंकि आपके पास एन्कोड किए गए चीजें हैं, 'फलों का इंट' अच्छी तरह से दयालु है), और नकली 'डेटा ग्रीन = ग्रीन' प्रकारों को परिभाषित करने की आवश्यकता को हटा देता है। –