2015-09-10 3 views
5

में अनिवार्य पाश मैं हास्केल में मोनैड सिस्टम को समझने की कोशिश कर रहा हूं। मेरे पिछले प्रोग्रामिंग प्रयोग का लगभग 80% सी में है, लेकिन विडंबनात्मक रूप से हास्केल का अनिवार्य हिस्सा समझना सबसे कठिन है। सूची में हेरफेर और आलसी मूल्यांकन अधिक स्पष्ट था। वैसे भी मैं ghc इस कोड को स्वीकार करना चाहता हूँ। मुझे पता है कि कोड बिल्कुल समझ में नहीं आता है। सबसे स्पष्ट रूप से, मैं Bool पास कर रहा हूं जहां IO Bool अपेक्षित है। लेकिन यह एकमात्र समस्या नहीं है। मुझे पता है कि यह एक बेवकूफ सवाल है, लेकिन कृपया मुझे हास्केल भाषा की मेरी समझ को आगे बढ़ाने में मदद करें।हास्केल

import Control.Monad 

while :: Monad m => m Bool -> m() -> m() 
while cond action = do 
    c <- cond 
    when c $ do 
    action 
    while cond action 

main :: IO() 
main = do 
    i <- 0 
    while (i < 10) $ do 
    i <- i + 1 
    print i 

यहाँ कैसे मैं अंत में यह किया है। मुझे पता है allocaArray आवश्यक नहीं है, लेकिन इसका उपयोग करना बहुत मजेदार था। हास्केल में वास्तव में कोई सीमा नहीं है, बहुत शक्तिशाली है।

import Control.Monad 
import Data.IORef 
import Foreign.Ptr 
import Foreign.Storable 
import Foreign.Marshal.Array 

while :: Monad m => m Bool -> m() -> m() 
while cond action = do 
    c <- cond 
    if c then do 
    action 
    while cond action 
    else return() 

main :: IO() 
main = do 
    let n = 10 
    allocaArray n $ \p -> do 
    i <- newIORef 0 
    while (liftM (< n) (readIORef i)) $ do 
     i2 <- readIORef i 
     poke (advancePtr p i2) i2 
     modifyIORef i (+ 1) 
    writeIORef i 0 
    while (liftM (< n) (readIORef i)) $ do 
     i2 <- readIORef i 
     (peek $ advancePtr p i2) >>= print 
     modifyIORef i (+ 1) 
+2

चलिए स्पष्ट से शुरू करते हैं। 'i' एक परिवर्तनीय चर नहीं है, और यह केवल इसलिए नहीं बनता है क्योंकि आपके पास एक मोनैड है। 'i <- i + 1' दो अलग-अलग 'i' को संदर्भित करता है। –

+1

'जबकि' निर्माण का शायद ही कभी हास्केल में उपयोग किया जाता है, मुझे लगता है कि हास्केल में यह वास्तव में आपको अनिवार्य भाषाओं में उपयोग किए जाने वाले लोगों के लिए प्राकृतिक रूप से "चर" का उपयोग करने की अनुमति नहीं देता है। आप * एक ही चीज़ को और अधिक अजीब तरीके से कर सकते हैं, लेकिन आपको 'डेटा.आईरफ़' या 'Control.Concurrent.MVar' जैसे म्यूटेबल संदर्भों का उपयोग करना होगा। जब तक आपको वास्तव में म्यूटेबल अपडेट की आवश्यकता न हो, तब तक इसे कार्यात्मक रूप से व्यक्त करना आम तौर पर बेहतर होता है। –

+1

ध्यान दें कि इस तरह से 'आईओआरआईएफ' का उपयोग करके लूप काउंटर को "बॉक्सिंग" किया जाता है, इसलिए प्रत्येक पुनरावृत्ति पर एक नया 'Int' बॉक्स आवंटित किया जाएगा और काउंटर तक पहुंचने में सूचक संकेत शामिल है। जब आप अधिक कार्यात्मक-शैली काउंटर से निपटते हैं, तो जीएचसी आमतौर पर इसे अनबॉक्स कर सकता है, जिससे तेज़ कोड होता है। – dfeuer

उत्तर

6

वहाँ दो चीजें हैं जो typechecking से अपने कोड रखने हैं:

  1. आपका while समारोह एक IO Bool उम्मीद लेकिन आप इसे i < 10 किस प्रकार Bool की अभिव्यक्ति है दे। Bool को IO Bool में बदलने के लिए, बस return का उपयोग करें।

  2. जब आप i <- 0 लिखते हैं तो आप शाब्दिक शून्य को एक monadic मान के रूप में उपयोग करने का प्रयास करते हैं, जो यह नहीं है। याद रखें कि

    main = do 
        i <- 0 
        ... 
    

    main = 0 >>= \i -> do ... 
    

के बराबर है इसे ठीक करने के, आप भी return के माध्यम से 0 को बढ़ावा देने के कर सकते हैं।

इसलिए, आप

main :: IO() 
main = do 
    i <- return 0 
    while (return (i < 10)) $ do 
     i <- return (i + 1) 
     print i 

अंत बहरहाल, यह अभी तुम क्या करने का इरादा क्या काम नहीं चलेगा: कारण यह है कि पहले (वाम-पंथी) ii <- return (i + 1) में अलग से i है i <- return 0 में। आप वैडिंग कर रहे हैं, एक ही वैरिएबल के साथ एक नया वैरिएबल बनाते हैं, जिसे आप प्रिंट करते हैं। तो आप वास्तव में किसी भी काउंटर पर टक्कर नहीं डालते हैं।

मैं मजेदार खराब नहीं करना चाहता, लेकिन यदि आप वास्तव में अटक जाते हैं: monad-loops पैकेज है जो whileM फ़ंक्शन समेत कुछ उपयोगी मोनैडिक लूप फ़ंक्शंस का खुलासा करता है।

+0

के बारे में बहुत अच्छा लेख है ओपी में 'while' उस पैकेज के 'whileM_' (थोड़ा कम सामान्य प्रकार लेकिन महत्वपूर्ण रूप से नहीं) के बराबर है; मुझे नहीं लगता कि समस्या है जहां समस्या है। –

+0

आसपास के कुछ अन्य लूप पुस्तकालय हैं, जैसे कि ['loops'] (https://hackage.haskell.org/package/loops) और [' control-monad-loop'] (https: //hackage.haskell। संगठन/पैकेज/नियंत्रण-मोनैड-लूप), जो ओपी की इच्छाओं के साथ बेहतर ढंग से गठबंधन की सुविधा प्रदान करता है। 'मोनैड-लूप्स' में कुछ शांत समवर्ती उपकरण हैं, लेकिन अन्यथा यह कम सामान्य लगता है। – dfeuer

9

इस दृष्टिकोण के साथ समस्या यह है कि i एक परिवर्तनीय चर नहीं है। आप IORef का उपयोग कर सकते हैं, हालांकि प्रत्येक पुनरावृत्ति के माध्यम से वर्तमान स्थिति को पारित करने के लिए एक और अधिक कार्यात्मक दृष्टिकोण होगा।के रूप में वैश्विक करने का विरोध किया

whileM :: Monad m => (a -> Bool) -> (a -> m a) -> a -> m() 
whileM test act init = 
    when (test init) $ (act init) >>= whileM test act 

तो आप

whileM (< 10) (\i -> print i >> return (i + 1)) 0 
3

स्थानीय राज्य (राज्य और संबद्ध इकाई ट्रांसफार्मर) के साथ एक समाधान कर सकते हैं,: आप अपने whileM शरीर और शर्तों को फिर से लिखने सकता है वर्तमान मान लेने के लिए राज्य (IORef और दोस्तों):

import Control.Monad 
import Control.Monad.State 

while :: Monad m => m Bool -> m() -> m() 
while cond action = do 
    c <- cond 
    when c $ do 
    action 
    while cond action 

main :: IO() 
main = do 
    runStateT (while cond body) 1 
    return() 

body :: StateT Integer IO() 
body = do 
    x <- get 
    liftIO $ print x 
    put (x + 1) 
    return() 

cond :: StateT Integer IO Bool 
cond = do 
    x <- get 
    return (x < 10) 

लूप शरीर और लूप हालत स्पष्ट और स्पष्टता के लिए नामित कर रहे हैं; लिखना संभव है उदा। while (liftM (< 10) get) body