2015-09-22 6 views
10

संदर्भ में पहचान इकाई लेखन:में "डेटा प्रकार एक ला कार्टे" Swierstra लिखते हैं कि <code>Free</code> दिया (जो उन्होंने <code>Term</code> कॉल) और <code>Zero</code> आप पहचान इकाई लागू कर सकते हैं नि: शुल्क

data Term f a = Pure a 
       | Impure (f (Term f a)) 
data Zero a 

Term Zero अब है पहचान मोनड। मैं समझता हूं कि यह क्यों है। मुद्दा यह है कि मैं परेशान Functor f => बाधा की वजह से एक इकाई के रूप में Term Zero का उपयोग कभी नहीं कर सकते हैं:

instance Functor f => Monad (Term f) where 
    return x = Pure x 
    (Pure x) >>= f = f x 
    (Impure f) >>= t = Impure (fmap (>>=f) t) 

मैं Zero एक functor कैसे करूं?

instance Functor Zero where 
    fmap f z = ??? 

लगता है कहीं कोई चाल यहाँ है की तरह: चूंकि Zero कोई कंस्ट्रक्टर्स है, Impure कभी नहीं इस्तेमाल किया जा सकता है, और इसलिए >>= की Impure मामले कभी नहीं कहा जाता है। इसका मतलब यह है fmap कभी नहीं कहा जाता है, तो एक भावना है जिसमें यह ठीक है नहीं है:

instance Functor Zero where 
    fmap f z = undefined 

समस्या है, इस धोखाधड़ी की तरह लगता है। मैं क्या खो रहा हूँ? Zero वास्तव में एक फंक्टर है? या शायद Zero एक फंक्टर नहीं है, और यह एक कमी है कि हम हास्केल में Free कैसे व्यक्त करते हैं?

+1

हाँ, '' 0' Zero' को 'Hask' से एक functor, खाली वर्ग (जो तब Hask में वापस एम्बेडेड है) है। –

उत्तर

12

यदि आप DeriveFunctor चालू करने पर आप

data Zero a deriving Functor 

लिख सकते हैं, लेकिन आपको लगता है कि धोखाधड़ी की सोच सकते हैं। आप इसे अपने आप को लिखना चाहते हैं, तो आप, EmptyCase चालू कर सकते हैं बजाय, तो फैशनेबल दिखने

instance Functor Zero where 
    fmap f z = case z of 
+0

मुझे आश्चर्य हुआ कि क्या होता है अगर हम धोखा देते हैं और इन दोनों मजेदार उदाहरणों में 'fmap f _ | _' करते हैं। जीएचसीआई 7.10.2 में, पहला उदाहरण 'अपवाद: शून्य एफएमएपी' के साथ त्रुटियों का मूल्यांकन करने की कोशिश किए बिना त्रुटियों के साथ बाहर निकलता है, जबकि दूसरा इसका मूल्यांकन करता है। मैं इसके बजाय एक गैर-थकावट त्रुटि की उम्मीद करूँगा। यह वास्तव में मायने रखता नहीं है - दोनों उदाहरण ठीक हैं, यद्यपि यदि हम एक पास करते हैं तो वे विभिन्न बोतलों का उत्पादन करते हैं। – chi

+2

@chi आपको निश्चित रूप से एक गैर-थकावट त्रुटि की उम्मीद नहीं करनी चाहिए: ये पैटर्न मिलान संपूर्ण हैं! –

+0

मैंने किसी भी तरह से पी 1 -> ई 1 के मामले ई के बीच व्यावहारिक समकक्ष की उम्मीद की; ..; पीएन -> एन' और 'केस ई ...; पीएन -> एन; _ -> त्रुटि "गैर संपूर्ण" '। यह "अंडर-द-हूड" समतुल्य केवल n = 0 के लिए टूट जाता है (यदि हम "अलग" बोतलों की पहचान नहीं करते हैं)। थकावट के बारे में ... मैं आगाडा/कोक या किसी अन्य कुल प्रोग्रामिंग भाषा में अधिक आश्वस्त होगा। हास्केल में, आप सही हैं, लेकिन बोतलें अजीब जानवर हैं, और मुझे इस बारे में कोई स्पष्ट जानकारी नहीं है कि 'केस _ | _ :: शून्य {} 'को तर्क का मूल्यांकन करना चाहिए या नहीं, परिचालन रूप से बोलना चाहिए। – chi

7

एक तरह से इस बारे में जाने के लिए लिखना एक खाली data घोषणा के बजाय Data.Void उपयोग करने के लिए, इस तरह है:

import Data.Void 

-- `Zero a` is isomorphic to `Void` 
newtype Zero a = Zero Void 

instance Functor Zero where 
    -- You can promise anything if the precondition is that 
    -- somebody's gotta give you an `x :: Void`. 
    fmap f (Zero x) = absurd x 

क्या Void के लिए उपयोगी है में से कुछ वास्तव में महान स्पष्टीकरण के लिए this question देखें। लेकिन मुख्य विचार यह है कि absurd :: Void -> a फ़ंक्शन आपको उस प्रकार से जाने देता है जो कभी भी नहीं हो सकता है x :: Void किसी भी प्रकार की बाध्यकारी में बाध्यकारी हो सकता है।

7

Zero a को परिभाषित करने का एक चाल तरीका निम्नलिखित है।

newtype Zero a = Zero (Zero a) 

दूसरे शब्दों में, यह मूर्खतापूर्ण, थोड़ा अस्पष्ट बयान की तरह वास्तव में एक तरह से Zero a के एक मूल्य प्राप्त करने के लिए है कि वहाँ encodes: आप पहले से ही एक होना चाहिए!

इस परिभाषा के साथ

, absurd :: Zero a -> b कुछ अर्थों क्योंकि वे का कहना है वास्तव में कैसे वे का दृष्टांत के लिए संभव नहीं हैं इन परिभाषाओं सभी कानूनी हैं

absurd :: Zero a -> b 
absurd (Zero z) = absurd z 

एक "प्राकृतिक" रास्ते में definable है। Zero a का कोई भी मूल्य तब तक नहीं बनाया जा सकता जब तक कि कोई और "धोखा देता है"।

instance Functor Zero where 
    fmap f = absurd 
+0

यह इंगित करने लायक है कि यह 'डेटा.वॉइड' मॉड्यूल लागू किया गया है या नहीं। –

+0

हां, हाँ, यह सच है! –

+1

'डेटा.वॉइड 'ऐसा करने के लिए प्रयोग किया जाता था,' एम्प्टीकेस 'बाहर आने से पहले (यह' शून्य 'से' आधार' 'में स्थानांतरित होने पर बदला गया था)। मुझे नहीं पता कि यह स्पष्टता, दक्षता, या त्रुटि रिपोर्टिंग कारणों के लिए बदल गया है या नहीं। क्या आप? – dfeuer

3

लुइस कैसिलस के answer पर एक और स्पिन शेयर हिस्सों से पूरी तरह से अपने प्रकार का निर्माण करना है: (

type Id = Free (Const Void) 

अपनी इच्छानुसार Const x के लिए Functor उदाहरण काम करेंगे अपनी fmap कुछ नहीं करता है, जो ठीक है), और आप केवल जब खोल देखभाल करने के लिए की आवश्यकता होगी:, की

runId (Pure x) = x 
runId (Free (Const ab)) = absurd ab 

ये सभी बातें पाठ्यक्रम, केवल 0 नैतिक रूप से Identity के बराबर हैं, क्योंकि वे सभी अतिरिक्त मूल्य पेश करते हैं। विशेष रूप से, हम भेद कर सकते हैं के बीच

bottom 
Pure bottom 
Free bottom 
संबंधित मुद्दे

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