2012-03-29 14 views
21

मुझे इसे समझने में कठिन समय है। नोटेशन में लिखते समय, निम्नलिखित दो पंक्तियां कैसे भिन्न होती हैं?"<-" संकेतों में बाइंडिंग

1. let x = expression 
2. x <- expression 

मैं इसे नहीं देख सकता। कभी-कभी एक काम करता है, कुछ बार दूसरे। लेकिन शायद ही कभी दोनों। "आपको एक हैकेल जानें" कहता है कि <- बाईं तरफ के प्रतीक के दाईं तरफ बांधता है। लेकिन यह को let के साथ बस परिभाषित करने से अलग कैसे है?

उत्तर

25

<- बयान एक इकाई से मान प्राप्त होगा, और let बयान होगा नहीं।

import Data.Typeable 

readInt :: String -> IO Int 
readInt s = do 
    putStrLn $ "Enter value for " ++ s ++ ": " 
    readLn 

main = do 
    x <- readInt "x" 
    let y = readInt "y" 
    putStrLn $ "x :: " ++ show (typeOf x) 
    putStrLn $ "y :: " ++ show (typeOf y) 

जब चलाने के लिए, कार्यक्रम, एक्स का मान के लिए पूछना क्योंकि monadic कार्रवाई readInt "x"<- बयान से क्रियान्वित किया जाता होगा। यह y के मान के लिए नहीं पूछेगा, क्योंकि readInt "y" का मूल्यांकन किया जाता है लेकिन परिणामी monadic कार्रवाई निष्पादित नहीं की जाती है।

 
Enter value for x: 
123 
x :: Int 
y :: IO Int 

x :: Int के बाद से, आप इसके साथ सामान्य Int काम कर सकें।

putStrLn $ "x = " ++ show x 
putStrLn $ "x * 2 = " ++ show (x * 2) 

y :: IO Int के बाद से, आप का नाटक नहीं कर सकते हैं कि यह एक नियमित रूप से Int है।

putStrLn $ "y = " ++ show y -- ERROR 
putStrLn $ "y * 2 = " ++ show (y * 2) -- ERROR 
8

let रूप में, expression एक गैर-monadic मान है, जबकि <- का दाहिना तरफ एक monadic अभिव्यक्ति है। उदाहरण के लिए, आप दूसरे प्रकार के बाध्यकारी में केवल एक I/O ऑपरेशन (IO t टाइप करें) कर सकते हैं। विस्तार में, दो रूपों मोटे तौर पर के रूप में अनुवाद किया जा सकता है (जहां ==> अनुवाद दिखाता है):

do {let x = expression; rest} ==> let x = expression in do {rest} 

और

do {x <- operation; rest} ==> operation >>= (\ x -> do {rest}) 
13

एक let बंधन में, अभिव्यक्ति किसी भी प्रकार के हो सकते हैं, और सभी आप कर रहे हैं यह एक नाम (इसकी आंतरिक संरचना पर या पैटर्न मिलान) दे रहा है।

<- संस्करण में, अभिव्यक्ति प्रकार m a, जहां m जो कुछ इकाई do ब्लॉक में है होना आवश्यक है। तो IO इकाई में, उदाहरण के लिए, इस फार्म के बाइंडिंग प्रकार IO a के कुछ मूल्य सही पर होना आवश्यक है -हाथ की तरफ। a हिस्सा (monadic value के अंदर) बाएं हाथ की तरफ पैटर्न के लिए बाध्य है। यह आपको do ब्लॉक के सीमित दायरे में मोनैड की "सामग्री" निकालने देता है।

do अंकन के रूप में आप monadic बाध्यकारी ऑपरेटरों (>>= और >>) से अधिक पढ़ने के लिए हो सकता है, बस वाक्यात्मक चीनी, है। x <- expression डी-शर्कर्स expression >>= \x -> और expression (स्वयं द्वारा, <- के बिना) de-sugars expression >> पर। यह सिर्फ मोनैडिक कंप्यूटेशंस की लंबी श्रृंखला को परिभाषित करने के लिए एक और सुविधाजनक वाक्यविन्यास देता है, जो अन्यथा नेस्टेड लैम्ब्डा के प्रभावशाली द्रव्यमान का निर्माण करते हैं।

let बाइंडिंग वास्तव में डी-शुगर नहीं है, वास्तव में। में let के बीच एकमात्र अंतर do ब्लॉक के बाहर let ब्लॉक है कि do संस्करण को in कीवर्ड का पालन करने की आवश्यकता नहीं है; जिन नामों को बांधता है वे do ब्लॉक के बाकी हिस्सों के लिए स्पष्ट रूप से दायरे में हैं।

2

हास्केल फॉर्म IO a के प्रकार के साथ अनिवार्य कार्यों का प्रतिनिधित्व करके शुद्ध कार्यात्मक प्रोग्रामिंग के साथ साइड-प्रभावशाली अनिवार्य प्रोग्रामिंग को दोबारा शुरू करता है: एक अनिवार्य कार्रवाई का प्रकार जो a प्रकार का परिणाम उत्पन्न करता है।

इस का एक परिणाम यह है कि एक अभिव्यक्ति के मूल्य के एक चर बाध्यकारी और एक कार्य को क्रियान्वित करने के परिणाम के लिए यह बाध्यकारी दो अलग बातें हैं:

x <- action  -- execute action and bind x to the result; may cause effect 
let x = expression -- bind x to the value of the expression; no side effects 

तो getLine :: IO String एक कार्य, है जो इसे इस तरह इस्तेमाल किया जाना चाहिए मतलब है:

do line <- getLine -- side effect: read from stdin 
    -- ...do stuff with line 

line1 ++ line2 :: String जबकि एक शुद्ध अभिव्यक्ति है, और let साथ इस्तेमाल किया जाना चाहिए:

do line1 <- getLine   -- executes an action 
    line2 <- getLine   -- executes an action 
    let joined = line1 ++ line2 -- pure calculation; no action is executed 
    return joined 
2

यहां एक साधारण उदाहरण है जो आपको अंतर दिखा रहा है। दो निम्नलिखित सरल भाव पर विचार करें:

letExpression = 2 
bindExpression = Just 2 

जानकारी आप प्राप्त करने का प्रयास कर रहे हैं संख्या 2 है। यहाँ तुम कैसे करते है:

let x = letExpression 
x <- bindExpression 

let सीधे मूल्य 2 डालता x में। <-Just से 2 मान निकालता है और इसे x में रखता है।

आपको लगता है कि उदाहरण के लिए, क्यों इन दो अंकन परस्पर विनिमय नहीं कर रहे हैं के साथ देख सकते हैं:

let x = bindExpression सीधे x में मूल्य Just 2 जाते थे। x <- letExpression को x में निकालने और रखने के लिए कुछ भी नहीं होगा।

3

let केवल मनमाने ढंग से मूल्यों पर एक नाम या पैटर्न मैचों को असाइन करता है।

<- के लिए, हमें पहले (वास्तव में नहीं) रहस्यमय IO इकाई से दूर जाएं, लेकिन monads कि एक "कंटेनर" की एक धारणा है, एक सूची या Maybe तरह विचार करते हैं। फिर <- उस कंटेनर के तत्वों को "अनपॅकिंग" से अधिक नहीं करता है। "इसे वापस डालने" का विपरीत संचालन return है। ,

add m1 m2 = do 
    v1 <- m1 
    v2 <- m2 
    return (v1 + v2) 

यह "unpacks" दो कंटेनरों के तत्वों मानों को एक साथ जोड़ने के लिए, और एक ही इकाई में फिर से लपेटता: इस कोड पर विचार करें।यह सूची के साथ काम करता है, तत्वों के सभी संभव संयोजनों लेने:

main = print $ add [1, 2, 3] [40, 50] 
--[41,51,42,52,43,53] 

वास्तव में सूचियों के मामले में आप के रूप में अच्छी add m1 m2 = [v1 + v2 | v1 <- m1, v2 <- m2] लिख सकते हैं। लेकिन हमारे संस्करण, भी Maybe के साथ काम करता है:

main = print $ add (Just 3) (Just 12) 
--Just 15 
main = print $ add (Just 3) Nothing 
--Nothing 

अब IO बिल्कुल कि अलग नहीं है। यह एक मूल्य के लिए एक कंटेनर है, लेकिन यह वायरस की तरह एक "खतरनाक" अशुद्ध मूल्य है, जिसे हमें सीधे स्पर्श नहीं करना चाहिए। do -ब्लॉक यहां हमारे ग्लास की रोकथाम है, और <- अंतर्निहित चीजों में हेरफेर करने के लिए अंतर्निहित "दस्ताने" हैं। return के साथ हम तैयार होने पर, पूर्ण, बरकरार कंटेनर (और न केवल खतरनाक सामग्री) प्रदान करते हैं। वैसे, add फ़ंक्शन IO मानों (जो हमें फ़ाइल या कमांड लाइन या यादृच्छिक जनरेटर ... से मिला है) के साथ काम करता है।

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