2010-03-07 23 views
5

में "चलो" द्वारा उलझन में मैंने अभी क्लोजर के साथ खेलना शुरू किया, और मैंने कुछ कार्यों को समझने में मेरी सहायता के लिए एक छोटी सी लिपि लिखी। यह इस तरह से शुरू होता है:क्लोजर

(def *exprs-to-test* [ 
    "(filter #(< % 3) '(1 2 3 4 3 2 1))" 
    "(remove #(< % 3) '(1 2 3 4 3 2 1))" 
    "(distinct '(1 2 3 4 3 2 1))" 
]) 

तो यह जाता है *exprs-to-test* के माध्यम से, उन सब का मूल्यांकन करता है, और प्रिंट इस तरह उत्पादन:

(doseq [exstr *exprs-to-test*] 
    (do 
     (println "===" (first (read-string exstr)) "=========================") 
     (println "Code: " exstr) 
     (println "Eval: " (eval (read-string exstr))) 
    ) 
) 

ऊपर कोड सभी कार्य ठीक है। इसलिए हालांकि, (read-string exstr) दोहराया है मैं let का उपयोग करें ताकि तरह पुनरावृत्ति को खत्म करने की कोशिश की:

(doseq [exstr *exprs-to-test*] 
    (let [ex (read-string exstr)] (
     (do 
      (println "===" (first ex) "=========================") 
      (println "Code: " exstr) 
      (println "Eval: " (eval ex)) 
     ) 
    )) 
) 

लेकिन इस *exprs-to-test* में पहला आइटम के लिए एक बार में काम करता है, तो एक NullPointerException साथ दुर्घटनाओं। let को दुर्घटना का कारण क्यों है?

उत्तर

7

आपके पास do फ़ॉर्म के आसपास कोष्ठक का एक अतिरिक्त सेट है। आपका कोड इस कर रही है:

((do ...)) 

यह (एक समारोह कॉल के रूप में) निष्पादित करने के लिए पूरे do प्रपत्र का मूल्य कोशिश कर रहा है, लेकिन donil लौटा रहा है, क्योंकि पिछले printlndo रूप में देता है nil

नोट, आपकी इंडेंटेशन शैली गैर-मानक है। आपको बंद करने वाले माता-पिता को अपनी लाइनों पर नहीं रखना चाहिए। और let में एक अंतर्निहित do है इसलिए आपको वहां एक की आवश्यकता नहीं है। इस प्रयास करें:

user> (doseq [exstr *exprs-to-test*] 
     (let [ex (read-string exstr)] 
      (println "===" (first ex) "=========================") 
      (println "Code: " exstr) 
      (println "Eval: " (eval ex)))) 
=== filter ========================= 
Code: (filter #(< % 3) '(1 2 3 4 3 2 1)) 
Eval: (1 2 2 1) 
=== remove ========================= 
Code: (remove #(< % 3) '(1 2 3 4 3 2 1)) 
Eval: (3 4 3) 
=== distinct ========================= 
Code: (distinct '(1 2 3 4 3 2 1)) 
Eval: (1 2 3 4) 
+0

यह तय किया गया। इंडेंटिंग स्टाइल टिप के लिए भी धन्यवाद। –

1

ब्रायन पहले से ही अपने प्रश्न का उत्तर है, इसलिए मैं केवल आपके जाने-फार्म के लिए कुछ सामान्य संकेत देना चाहता हूँ:

4

मुझे लगता है कि अन्य उत्तरों कमरे में हाथी को अनदेखा कर रहे हैं: आप यह क्यों कर रहे हैं? वहाँ है कि सीखने Clojure के माध्यम से मुझे चिंता तुम गलत रास्ते पर फोर्जिंग कर रहे हैं अपने कोड में बहुत कुछ कर रहे हैं:

  • का उपयोग करते हुए वैश्विक बाइंडिंग (exprs करने वाली परीक्षण)
  • doseq/println करने का उपयोग करना बाहर अनुक्रम
  • में कोड की कोशिश Clojure के एपीआई जानने के लिए आरईपीएल के माध्यम से है eval

सबसे अच्छा तरीका है का उपयोग करना। आपको अपना पर्यावरण स्थापित करना चाहिए, चाहे वह विम, एमाक्स, या एक आईडीई हो, जैसे कि आप पाठ फ़ाइलों में स्थिर कोड और एक इंटरैक्टिव आरईपीएल के बीच आसानी से आगे बढ़ सकते हैं। Here is a good breakdown of a number of Clojure IDEs

अब, जहां तक ​​आपका कोड जाता है, कुछ याद रखने के लिए। सबसे पहले, eval का उपयोग करने के लिए लगभग कोई अच्छा कारण नहीं है। यदि आप स्वयं ऐसा करते हैं, तो खुद से पूछें कि क्या यह वास्तव में आवश्यक है। दूसरा, याद रखें, क्लोजर एक कार्यात्मक भाषा है और आम तौर पर आपको मैक्रोज़ के "डू" सेट का उपयोग करने की आवश्यकता नहीं है।जब आप साइड इफेक्ट्स की आवश्यकता होती है तो "डू" मैक्रोज़ उपयोगी होते हैं (आपके उदाहरण में, दुष्प्रभाव * आउट * के लिए println है) अंत में, वैश्विक वर्रों का उपयोग करने से बचा जाना चाहिए। यदि आपको वार्स का उपयोग करने की आवश्यकता है, तो आपको बाइंडिंग मैक्रो का उपयोग स्थानीय स्तर पर वर्रों को अपरिवर्तनीय मूल्यों में बांधने के लिए करना चाहिए ताकि कोई समवर्ती समस्या न हो।

मैं निश्चित रूप से अनुशंसा करता हूं कि प्रोग्रामिंग क्लोजर या एलआईएसपी के लिए एक और गहरा संदर्भ लेने के लिए समय निकालें ताकि आप क्लोजर प्रभावी ढंग से लाभ उठाने के लिए प्रोग्रामिंग के बारे में सोच सकें। यहां आपका छोटा सा नमूना मुझे महसूस करता है कि आप क्लोजर में अनिवार्य कोड लिखने की कोशिश कर रहे हैं, जो बिल्कुल भी काम नहीं करेगा।

+0

मुझे पता है कि ग्लोबल इस 10 लाइन स्क्रिप्ट में नियंत्रण से बाहर हैं, और मैं अब "मैक" मैक्रोज़ का उपयोग नहीं करूँगा और उन परिस्थितियों में भी जहां वे वास्तव में आवश्यक हैं। मैं आरईपीएल के बारे में भी आपकी सलाह लेगा क्योंकि मेरे पास भाषाओं की एक निर्दोष स्मृति है जिसे मैंने केवल 10 मिनट के लिए उपयोग किया है, और मुझे बाद में संदर्भ के लिए अपना काम सहेजने की आवश्यकता नहीं है। एक अनुभवी क्लोजर पेशेवर के रूप में, आपका धार्मिक गैर-जवाब मुझे शर्म से भर देता है। मैं अगली बार कड़ी मेहनत करूँगा। –

+0

क्या एक घृणित रूप से snarky और व्यंग्यात्मक टिप्पणी। मैं मदद करने की कोशिश कर रहा था। तुम्हे शर्म आनी चाहिए। –

+0

मुझे नहीं लगता कि शुरुआती कोड सही नहीं है, इस बारे में प्रश्न और छेड़छाड़ को अनदेखा करना उचित है। मदद करने की कोशिश करने की तुलना में आप अपने खुद के तुरही उड़ रहे थे जैसे महसूस किया। –