2016-12-02 11 views
10

पर स्कैला प्रकार का उदाहरण अनुवाद करें मुझे स्कैला आलेख में वास्तव में एक दिलचस्प उदाहरण मिला और मैं सोच रहा हूं कि इसे हास्केल में कैसे एन्कोड किया जा सकता है।हास्केल

trait Status 
trait Open extends Status 
trait Closed extends Status 

trait Door[S <: Status] 
object Door { 
    def apply[S <: Status] = new Door[S] {} 

    def open[S <: Closed](d: Door[S]) = Door[Open] 
    def close[S <: Open](d: Door[S]) = Door[Closed] 
} 

val closedDoor = Door[Closed] 
val openDoor = Door.open(closedDoor) 
val closedAgainDoor = Door.close(openDoor) 

//val closedClosedDoor = Door.close(closedDoor) // fails to compile 
//val openOpenDoor = Door.open(openDoor) // fails to compile 

यह नमूना प्रकार स्तर है कि आप केवल एक बंद Door खोल सकते हैं, और केवल एक खुला Door बंद पर एन्कोड करता है। मेरा पहला प्रयास सिर्फ सरल डेटा प्रकार उपयोग कर रहा था, लेकिन उद्देश्य के अनुसार कार्य नहीं करता है:

data Status = Open | Closed deriving (Show) 
data Door = Door Status deriving (Show) 

open :: Door -> Door 
open (Door Closed) = Door Open 

close :: Door -> Door 
close (Door Open) = Door Closed 

main = do 
    let closedDoor = (Door Closed) 
    let openDoor = open closedDoor 
    let closedAgainDoor = close openDoor 
    let closeClosedDoor = close closedDoor 
    let openOpenedDoor = open openDoor 
    print closedAgainDoor 

यह वास्तव में संकलित (जब तक मैं closeClosedDoor या openOpenedDoor जो तब खुला समारोह में गैर संपूर्ण पैटर्न के बारे में शिकायत है, जो प्रिंट करने का प्रयास स्पष्ट)

तो मैं यह पता लगाने की कोशिश कर रहा हूं कि हमारे प्रकार के परिवार जीएडीटी इस कार्य को पूरा कर सकते हैं, लेकिन मैं अभी तक समझने में सक्षम नहीं हूं।

कोई विचार?

उत्तर

18

bheklilr के जवाब देने के लिए इसके अलावा, आप कुछ प्रकार एक्सटेंशन का उपयोग भी स्काला उदाहरण के करीब हो और

Door String 

DataKinds का उपयोग करते हुए की तरह गैर sensical प्रकार से इनकार करने के लिए कर सकता है, तो आप को प्रभावी ढंग से से प्रेत प्रकार की अनुमति नहीं देने सकता है Status पर कुछ भी होने के नाते।

{-# LANGUAGE DataKinds #-} 

data Door (status :: Status) = Door 
data Status = Open | Closed 

open :: Door Closed -> Door Open 
open _ = Door 

close :: Door Open -> Door Closed 
close _ = Door 

फिर, प्रकार परिवारों के साथ, हम भी निर्धारित कर सकते हैं क्या यह "टॉगल" एक दरवाजा करने के लिए इसका मतलब है

{-# LANGUAGE TypeFamilies #-} 

type family Toggle (s :: Status) where 
    Toggle Open = Closed 
    Toggle Closed = Open 

toggle :: Door s -> Door (Toggle s) 
toggle Door = Door 

के रूप में एक बंद सोचा, इसके लिए एक GADT उपयोग करने के लिए अच्छे हो सकता है Door - बस आपके पास दो अलग-अलग कन्स्ट्रक्टर नाम हैं। मुझे व्यक्तिगत रूप से लगता है कि यह बेहतर

{-# LANGUAGE GADTs, DataKinds, TypeFamilies #-} 

data Door (status :: Status) where 
    OpenDoor :: Door Open 
    ClosedDoor :: Door Closed 

open :: Door Closed -> Door Open 
open _ = OpenDoor 

close :: Door Open -> Door Closed 
close _ = ClosedDoor 

toggle :: Door s -> Door (Toggle s) 
toggle OpenDoor = ClosedDoor 
toggle ClosedDoor = OpenDoor 
+1

आपने मुझे 'डेटाकिंड्स' उत्तर में हराया। मैं पहले इसे संकलित किए बिना इसे पोस्ट नहीं करना चाहता था, लेकिन मुझे पहले 'स्टैक सेटअप' चलाने के लिए, और धीमे नेटवर्क पर कुछ समय लगता है, लॉल। मुझे 'टाइपफमिलियों' के साथ 'टॉगल' विचार पसंद है, हालांकि, उस बारे में सोचा नहीं था। – bheklilr

+0

अच्छा, मुझे नहीं लगता कि मैं इस बात पर आ सकता हूं, फिर भी भाषा की उन्नत विशेषताओं को सीख रहा हूं। –

+0

बेहतर अनुमान के लिए, 'टॉगल :: (एस ~ टॉगल टी, टी ~ टॉगल एस) => दरवाजा एस -> दरवाजा टी'। या 'वर्ग Toggled एस टी | एस -> टी, टी -> एस जहां टॉगल :: दरवाजा एस -> दरवाजा टी'। आप शायद जीएचसी 8 के लिए एक इंजेक्शन प्रकार परिवार का उपयोग कर सकते हैं, लेकिन मैं अभी तक उनको नहीं खरीदता हूं। अनुमान के लिए – dfeuer

10

मैं अब किसी भी मामले पर विचार करने के राज्य में ही, प्रकार में एन्कोड किया गया है स्काला उदाहरण के साथ के रूप में नहीं कर रहे हैं, जैसे

data Open = Open deriving (Show) 
data Closed = Closed deriving (Show) 
data Door door_state = Door deriving (Show) 

open :: Door Closed -> Door Open 
open _ = Door 

close :: Door Open -> Door Closed 
close _ = Door 

कुछ करना होगा।