2012-04-24 21 views
9

में मैंने हाल ही में क्लोजर सीखना शुरू कर दिया। आम तौर पर यह दिलचस्प लग रहा है, लेकिन मैं कुछ वाक्य रचनात्मक असुविधाओं (पिछले रूबी/सी # अनुभव की तुलना में) में उपयोग नहीं कर सकता।इंफिक्स से उपसर्ग नोटेशन

नेस्टेड अभिव्यक्तियों के लिए उपसर्ग नोटेशन। रुबी में मुझे चेनिंग/पाइपिंग के साथ जटिल अभिव्यक्तियों को लिखने के लिए उपयोग किया जाता है: some_object.map { some_expression }.select { another_expression }। यह वास्तव में सुविधाजनक है क्योंकि आप इनपुट मान से चरण-दर-चरण परिणाम में जाते हैं, आप एक ही परिवर्तन पर ध्यान केंद्रित कर सकते हैं और आपको टाइप करते समय कर्सर को स्थानांतरित करने की आवश्यकता नहीं है। इसके विपरीत जब मैं क्लोजर में नेस्टेड अभिव्यक्ति लिखता हूं, तो मैं आंतरिक अभिव्यक्ति से कोड को बाहरी में लिखता हूं और मुझे लगातार कर्सर को स्थानांतरित करना होता है। यह धीमा और परेशान करता है। मुझे -> और ->> मैक्रोज़ के बारे में पता है, लेकिन मैंने देखा कि यह एक मूर्खतापूर्ण नहीं है। जब आपने क्लोजर/हास्केल इत्यादि में कोडिंग शुरू की थी तो क्या आपको वही समस्या थी? आपने इसे कैसे ठीक किया?

+0

मुझे लगता है कि यह केवल मूर्खतापूर्ण है क्योंकि इसका उपयोग आप करते हैं। उपसर्ग नोटिक्स इंफिक्स से कहीं अधिक संगत है और इसलिए इसे उपयोग करने के बाद इसे पढ़ना आसान हो सकता है। –

+0

माइक, आपको अभिव्यक्ति लिखने की आवश्यकता है '(फ़िल्टर # (expr1) (मानचित्र # (expr2) expr3)) '। क्या आप आंतरिक expr3 या फ़िल्टर से टाइप करना शुरू कर देंगे? – Alexey

+3

मैं आमतौर पर बाहर से शुरू करता हूं और अपना रास्ता काम करता हूं। इसलिए मैं जो चाहता हूं उसके बारे में सोचता हूं और उससे पीछे की तरफ चलता हूं। –

उत्तर

3

मैं वास्तव में एक ही बाधा देखा था जब मैं पहली बार एक तुतलाना के साथ शुरू किया और जब तक मैं तरीके यह कोड सरल और अधिक स्पष्ट करता है, देखा यह वास्तव में कष्टप्रद था एक बार मैं उल्टा झुंझलाहट फीका

initial + scale + offset 
समझा

बन

(+ initial scale offset) 

और फिर (+) उपसर्ग अंकन कोशिश कार्यों उनकी खुद की पहचान को महत्व देता है निर्दिष्ट कर सकते हैं

user> (*) 
1 
user> (+) 
0 

बहुत सारे उदाहरण हैं और मेरा बिंदु उपसर्ग नोटेशन की रक्षा नहीं करना है। मुझे उम्मीद है कि सीखने की अवस्था (भावनात्मक रूप से) सकारात्मक पक्षों के रूप में स्पष्ट हो जाएगी।

निश्चित रूप से जब आप मैक्रोज़ लिखते हैं तो उपसर्ग नोटेशन एक सुविधा के बजाय होना चाहिए।


अपने प्रश्न के दूसरे भाग, पर पहले विचार धागा और हालांकि कोई भी गलती होगी शुद्ध गणित की तुलना में कॉल थ्रेड पिछले मैक्रो मुहावरेदार कभी भी वे कोड और अधिक स्पष्ट :) वे अधिक बार कार्यों में किया जाता है कर रहे हैं करने के लिए उनका उपयोग करने के लिए जब वे समीकरण को और अधिक आकर्षक बनाते हैं।


पुनश्च: (.. object object2 object3) ->object().object2().object3();

(doto my-object 
    (setX 4) 
    (sety 5)` 
+0

आर्थर, तो क्या आप ऐसा करते हैं कि उपसर्ग नोटेशन कोड को लिखने के लिए विश्वसनीय है, 'dot' के साथ '.methods' के इन्फिक्स आमंत्रण के रूप में, या यह वास्तव में कम सुविधाजनक है लेकिन अन्य फायदे हैं? – Alexey

+1

एक बार मुझे '..' मैक्रो मिला, मुझे जेव में बहुत बोझिल और पढ़ने और टाइप करने के लिए मुश्किल में inflix नोटेशन मिलता है। (यह सिर्फ मेरी विनम्र राय है) –

+1

@ आर्थरउल्फेल्ड, क्या आप "मैक्रोज़ लिखना शुरू करते समय निश्चित रूप से विस्तृत कर सकते हैं, फिर सुविधा के बजाय इन्फ्लिक्स नोटेशन होना चाहिए"? या आप यहाँ उपसर्ग कहना चाहते थे? – ivant

4
मेरी जानकारी -> करने के लिए

और ->> Clojure में मुहावरेदार है। मैं उन्हें हर समय उपयोग करता हूं, और मेरी राय में वे आमतौर पर अधिक पढ़ने योग्य कोड का नेतृत्व करते हैं।

यहाँ इन मैक्रो के कुछ उदाहरण Clojure "पारिस्थितिकी तंत्र" भर से लोकप्रिय परियोजनाओं में इस्तेमाल किया जा रहा हैं:

उदाहरण के द्वारा सबूत :)

9

मुझे वही लगा शुरुआत में लिस्पस के बारे में मुझे तुम्हारा दर्द महसूस होता है :-)

हालांकि अच्छी खबर यह है कि आपको कुछ समय और नियमित उपयोग के साथ मिल जाएगा, आप शायद उपसर्ग नोटेशन पसंद करना शुरू कर देंगे। वास्तव में गणितीय अभिव्यक्तियों के अपवाद के साथ अब मैं इसे इंफिक्स शैली पसंद करता हूं। - सबसे अधिक भाषाओं इन्फ़िक्स का मिश्रण (गणितीय संचालकों) और उपसर्ग (कार्यात्मक कॉल) संकेतन का उपयोग

  • कार्यों साथ संगति:

    कारण उपसर्ग अंकन पसंद करने के लिए। लिस्पस में यह सभी सुसंगत है, यदि आप गणितीय ऑपरेटरों को

  • मैक्रोज़ - फ़ंक्शन कॉल हमेशा पहली स्थिति में होने पर अधिक सचेत हो जाते हैं, तो यह एक निश्चित लालित्य है।
  • वरर्ग - यह आपके लिए बहुत सारे ऑपरेटरों के लिए पैरामीटर की एक चरणीय संख्या रखने में सक्षम होना अच्छा है। (+ 1 2 3 4 5) अच्छे IMHO 1 + 2 + 3 + 4 + 5

से एक चाल तो librerally -> और ->> उपयोग करने के लिए जब यह तार्किक समझ में आता है अपने कोड इस तरह की संरचना करने के है। वस्तुओं या संग्रहों पर बाद के संचालन से निपटने पर यह आम तौर पर उपयोगी होता है, उदा।

(->> 
    "Hello World" 
    distinct 
    sort 
    (take 3)) 

==> (\space \H \W) 

अंतिम चाल मैं बहुत उपयोगी पाया जब उपसर्ग शैली में काम जब अधिक जटिल भाव के निर्माण खरोज का अच्छा इस्तेमाल किया जा सके। आप ठीक ढंग से इंडेंट है, तो आप पाएंगे कि उपसर्ग अंकन वास्तव में काफी पढ़ने के लिए स्पष्ट है:

(defn add-foobars [x y] 
    (+ 
    (bar x y) 
    (foo y) 
    (foo x))) 
+0

'->' और '- >> 'के साथ असुविधा है कि आपके पास उनमें से दो हैं। कुछ फ़ंक्शंस ('cons',' map', 'apply') समग्र ऑब्जेक्ट को अंतिम तर्क के रूप में लेते हैं, और अन्य ('conj',' update-in') पहले के रूप में और आप उन्हें सिंगल' -> 'या ' '- >>'। अनुलेखरूबी और स्मॉलटाक इंफिक्स नोटेशन जैसी शुद्ध ओओपी भाषाओं में पूरी तरह से संगत है: '1। + (2), [1] .zip ([2]) 'और समग्र वस्तु हमेशा डॉट से पहले तर्क है। – Alexey

+3

@Alexey: '->' और '- >> 'और भिन्न तर्क आदेश का एक कारण है। यह seq abstraction और संग्रह के बीच भेद के कारण है। मुझे लगता है कि यह भ्रमित है क्योंकि एक संग्रह अक्सर एक वर्ग के रूप में माना जाता है। मैं अक्सर रिच हिकी के स्पष्टीकरण को संदर्भित करता हूं - http://groups.google.com/group/clojure/msg/a8866d34b601ff43 –

+2

यदि आप वास्तव में इसे चाहते हैं, तो स्विस-तीर लाइब्रेरी हीरा वंड मैक्रो प्रदान करता है: http: // stackoverflow .com/q/10068398/148578 –

3

आप एक लंबे अभिव्यक्ति श्रृंखला है, तो let का उपयोग करें। लंबे भागने वाले भाव या गहरा घोंसला वाले अभिव्यक्ति किसी भी भाषा में विशेष रूप से पठनीय नहीं हैं। यह बुरा है:

(do-something (map :id (filter #(> (:age %) 19) (fetch-data :people)))) 

यह मामूली बेहतर है:

(do-something (map :id 
        (filter #(> (:age %) 19) 
          (fetch-data :people)))) 

लेकिन यह भी बुरा है:

fetch_data(:people).select{|x| x.age > 19}.map{|x| x.id}.do_something 

हम यह पढ़ रहे हैं, तो क्या हम जानते हैं की जरूरत है? हम people के कुछ सबसेट के कुछ विशेषताओं पर do_something पर कॉल कर रहे हैं। यह कोड पढ़ना मुश्किल है क्योंकि पहले और आखिरी के बीच इतनी दूरी है कि हम उस समय भूल जाते हैं जब हम उनके बीच यात्रा करते हैं।

रुबी के मामले में, do_something (या जो भी हमारे अंतिम परिणाम का उत्पादन कर रहा है) लाइन के अंत में खो गया रास्ता है, इसलिए यह कहना मुश्किल है कि हम अपने people पर क्या कर रहे हैं। क्लोजर के मामले में, यह तुरंत स्पष्ट है कि do-something वह है जो हम कर रहे हैं, लेकिन यह कहना मुश्किल है कि हम इसे पूरी चीज़ के अंदर अंदर पढ़ने के बिना क्या कर रहे हैं।

इस सरल उदाहरण से अधिक जटिल कोई भी कोड बहुत दर्दनाक बनने जा रहा है। यदि आपका पूरा कोड इस तरह दिखता है, तो आपकी गर्दन स्पेगेटी की इन सभी पंक्तियों में आगे और पीछे थक गई है। फिर मैं do-something उन्हें मैं people के साथ शुरू, मैं चारों ओर मूर्ख, और:

(let [people (fetch-data :people) 
     adults (filter #(> (:age %) 19) people) 
     ids (map :id adults)] 
    (do-something ids)) 

अब यह स्पष्ट है:

मैं कुछ इस तरह पसंद करेंगे।

और आप इस के साथ दूर हो सकती है:

fetch_data(:people).select{|x| 
    x.age > 19 
}.map{|x| 
    x.id 
}.do_something 

लेकिन मैं शायद बल्कि यह, बहुत कम से कम करना चाहते हैं:

adults = fetch_data(:people).select{|x| x.age > 19} 
do_something(adults.map{|x| x.id}) 

यह भी जब भी let उपयोग करने के लिए अनसुना नहीं है आपके मध्यस्थ अभिव्यक्तियों के अच्छे नाम नहीं हैं। (इस शैली कभी कभी, Clojure के अपने स्रोत कोड में प्रयोग किया जाता है defmacro के लिए स्रोत कोड जैसे)

(let [x (complex-expr-1 x) 
     x (complex-expr-2 x) 
     x (complex-expr-3 x) 
     ... 
     x (complex-expr-n x)] 
    (do-something x)) 

यह, डिबगिंग में एक बड़ी मदद हो सकता है क्योंकि आप ऐसा करके किसी भी बिंदु पर बातें निरीक्षण कर सकते हैं:

(let [x (complex-expr-1 x) 
     x (complex-expr-2 x) 
     _ (prn x) 
     x (complex-expr-3 x) 
     ... 
     x (complex-expr-n x)] 
    (do-something x)) 
संबंधित मुद्दे