2013-08-22 7 views
6

हास्केल में, क्या कई प्रकार की बाधाओं के साथ एक तरीका है, जैसे कि संघ संतुष्ट है यदि उनमें से कोई भी संतुष्ट है?संघ प्रकार की बाधाओं का कोई तरीका है?

उदाहरण के लिए, मैं एक GADT एक DataKind द्वारा parameterized था लगता है, और मैं केवल दिए गए प्रकार के कुछ निर्माताओं के लिए मूल्यों को वापस जाने के लिए कुछ निर्माताओं के लिए चाहते थे, छद्म हास्केल होगा:

{-# LANGUAGE GADTs #-} 
{-# LANGUAGE KindSignatures #-} 
{-# LANGUAGE DataKinds #-} 
module Temp where 

data Color = White | Red | Blue | Yellow | Green | Tawny | Purple | Black 

data Fruit (c :: Color) where 
    Banana :: (c ~ Green | c ~ Yellow | c ~ Black) => Fruit c 
    Apple :: (c ~ Red | c ~ Green)    => Fruit c 
    Grape :: (c ~ Red | c ~ Green | c ~ White)  => Fruit c 
    Orange :: (c ~ Tawny)       => Fruit c 

मैं कर सकते हैं OR का उपयोग करके typeclasses लागू करने के लिए प्रयास करें:

{-# LANGUAGE GADTs #-} 
{-# LANGUAGE KindSignatures #-} 
{-# LANGUAGE DataKinds #-} 
module Temp where 

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 BananaColor (c :: Color) 
instance BananaColor Green 
instance BananaColor Yellow 
instance BananaColor Black 

class AppleColor (c :: Color) 
instance AppleColor Red 
instance AppleColor Green 

class GrapeColor (c :: Color) 
instance GrapeColor Red 
instance GrapeColor Green 
instance GrapeColor White 

class OrangeColor (c :: Color) 
instance OrangeColor Tawny 

लेकिन न केवल यह है भी है कि मैं क्या में इरादा है कि मूल संघ बंद हो गया की तुलना में थोड़ा अलग इस वर्बोज़ है, लेकिन typeclasses सभी खुले हैं। वहाँ

instance OrangeColor Blue 

को परिभाषित करने से किसी को रोकने के लिए कुछ भी नहीं है और क्योंकि यह खुला है, वहाँ कोई रास्ता नहीं संकलक का अनुमान लगा सकते हैं कि [Apple, Grape, Banana] प्रकार [Fruit Green] का होना चाहिए जब तक बताया था।

उत्तर

4

मैं सचमुच कार्यान्वित करने के लिए या 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 cFruit की कंस्ट्रक्टर्स परिभाषित करते हैं।)

अब, क्या करता है यह आप खरीद, और क्या यह आप उसे खरीद नहीं ? प्लस तरफ, आपको अपने प्रकार को परिभाषित करने की क्षमता मिलती है जैसा आप चाहते हैं, जो निश्चित रूप से एक जीत है; और चूंकि 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 
0

नीचे समस्या को एन्कोड करने का मेरा प्रयास है। मुख्य विचार प्रकार जो इस प्रकार के वर्ग को लागू

data Color = White | Red | Blue | Yellow | Green | Tawny | Purple | Black 

class Fruit a where 
    getColor :: a -> Color 

data Banana where 
    GreenBanana :: Banana 
    YellowBanana :: Banana 
    BlackBanana :: Banana 

instance Fruit Banana where 
    getColor GreenBanana = Green 
    getColor YellowBanana = Yellow 
    getColor BlackBanana = Black 

data Apple where 
    GreenApple :: Apple 
    RedApple :: Apple 

instance Fruit Apple where 
    getColor GreenApple = Green 
    getColor RedApple = Red 

आपके प्रश्नों अंतिम पंक्ति इंगित करता है कि आप प्रकार [Fruit Green] के बारे में कुछ है जो स्पष्ट रूप से इसका मतलब है कि Fruit Green एक होना चाहिए चाहते हैं के रूप में एक प्रकार वर्ग और फल के विभिन्न प्रकार के रूप में फलों का प्रतिनिधित्व करने के लिए है टाइप करें जहां उपर्युक्त कोड में ग्रीन एक वैल्यू कन्स्ट्रक्टर है। हम एक प्रकार, कुछ की तरह नीचे दिखाया गया है Green करना है:

data Red = Red 
data Green = Green 
data Black = Black 

data Fruit c where 
    GreenBanana :: Fruit Green 
    BlackBanana :: Fruit Black 
    RedApple :: Fruit Red 
    GreenApple :: Fruit Green 


greenFruits :: [Fruit Green] 
greenFruits = [GreenBanana, GreenApple] 
+0

आप को देखा है [GHC 7.4 + की तरह प्रचार सुविधा] (http://www.haskell.org/ghc/docs/7.6। 1/html/users_guide/promotion.html)? यह प्रकारों को प्रकार के रूप में, और मानों के रूप में मानने की अनुमति देता है। '-XDataKinds' के साथ, 'ग्रीन' दयालु 'रंग' की एक पूरी तरह से मान्य प्रकार-स्तर की चीज़ है। इससे टाइप-स्तरीय प्रोग्रामिंग अधिक प्रकार-सुरक्षित हो जाती है (क्योंकि आपके पास एन्कोड किए गए चीजें हैं, 'फलों का इंट' अच्छी तरह से दयालु है), और नकली 'डेटा ग्रीन = ग्रीन' प्रकारों को परिभाषित करने की आवश्यकता को हटा देता है। –

संबंधित मुद्दे