2013-05-06 15 views
10

मैंने अभी क्लोजर के साथ हैकिंग शुरू कर दी है, और हालांकि मैं भाषा की पूजा करता हूं, मैं समझ नहीं पा रहा हूं कि कुछ चीजों को मूर्खतापूर्वक कैसे किया जाए।बेवकूफ क्लोजर (+ कार्यात्मक) कोड कैसे लिखें?

compojure का उपयोग कर एक वेब एप्लिकेशन लेखन, यहाँ मेरी नियंत्रक क्रियाओं में से एक है:

(defn create [session params] 
    (let [user (user/find-by-email (params :email))] 
    (if user 
     (if (user/authenticate user (params :password)) 
      (do (sign-in session user) 
       (resp/redirect "/home?signed-in=true")) 
      (resp/redirect "/?error=incorrect-password")) 
     (let [new-user (user/create params)] 
      (sign-in session new-user) 
      (resp/redirect "/home?new-user=true"))))) 

मैं एक बहुत ही जरूरी तरीके से इस लिख रहा हूँ। इतने सारे let एस/if एस/do एस का उपयोग करके, मैं मदद नहीं कर सकता लेकिन लगता है कि मैं कुछ गलत कर रहा हूं। मैं इसे कार्यात्मक रूप से कैसे लिखूं?

यहाँ मैं क्या

look if user exists 
    if user exists, try to sign user in using password provided 
    if password is wrong, redirect to "/?error=incorrect-password" 
    if password is correct, sign user in and redirect to "/home?signed-in=true" 
    else create user, sign user in, and redirect to "/home?new-user=true" 

धन्यवाद करने के लिए इतना कोशिश कर रहा हूँ के लिए psuedocode है!

उत्तर

8

वहाँ कुछ भी if के बारे में गैर कार्यात्मक नहीं है - यह एक पूरी तरह से अच्छा है, पूरी तरह कार्यात्मक निर्माण है कि एक अभिव्यक्ति सशर्त का मूल्यांकन करता है। एक ही स्थान पर बहुत सारे if रों (उच्च आदेश कार्यों की एक संरचना प्रोटोकॉल के साथ जैसे cond बहुरूपता मुल्टीमेथड्स???) हालांकि एक चेतावनी संकेत हो सकता है, कि आप एक अलग निर्माण का उपयोग कर किया जाना चाहिए

do अधिक मुश्किल है: अगर आपके पास ऐसा है तो इसका तात्पर्य है कि आप साइड इफेक्ट के लिए कुछ कर रहे हैं, जो निश्चित रूप से गैर-कार्यात्मक है। आपके मामले में sign-in और user/create यहां दुष्प्रभावपूर्ण अपराधी प्रतीत होते हैं।

साइड इफेक्ट्स के बारे में आपको क्या करना चाहिए?वैसे वे कभी-कभी जरूरी होते हैं, इसलिए चुनौती यह है कि आपकी संरचना आपके कोड को कैसे नियंत्रित करती है ताकि साइड इफेक्ट्स नियंत्रित और प्रबंधित हो सकें (आदर्श रूप से एक विशेष राज्य-हैंडलिंग खतरे के क्षेत्र में दोबारा प्रतिक्रिया दी जाती है ताकि आपका शेष कोड साफ और पूरी तरह कार्यात्मक हो सके)।

अपने मामले में आप सोच सकते हैं:

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

लंबे + विस्तृत प्रतिक्रिया के लिए बहुत बहुत धन्यवाद! एक हैंडलर फ़ंक्शन/फ़ंक्शन ब्रेकअप कैसे दिखता है? और झंडे से तुम्हारा क्या मतलब है? समारोह उचित तार वापस करेगा? – hurshagrawal

+0

बहुत सारे विकल्प हैं। एक तरफ आपके प्रतिक्रिया मानचित्र में साइड इफेक्ट "एक्शन" की एक सूची हो सकती है कि हैंडलर फ़ंक्शन अनुक्रम में निष्पादित होता है। आप यह भी देखना चाहेंगे कि कुछ रिंग मिडलवेयर कैसे काम करता है। – mikera

+2

वास्तव में, "if-then-else" निर्माण का आविष्कार लिस्प के निर्माता जॉन मैककार्थी ने किया था, विशेष रूप से कार्यात्मक प्रोग्रामिंग को आसान बनाने के लिए। https://en.wikipedia.org/wiki/McCarthy_Formalism –

5

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

3

यह अधिकतर उचित दिखता है, और चूंकि आपका एकमात्र दुष्प्रभाव "आवश्यक" है, यानी सत्र में जोड़ना, मैं इसे बहुत जरूरी नहीं कहूंगा। हालांकि तीसरे एक वैकल्पिक है वहाँ, तीन परिवर्तन मैं होगा हैं:

  • एक और जवाब के रूप में सुझाव दिया, एक भी if-let में if/let जोड़ी बदल जाते हैं।
  • मानचित्र में कीवर्ड लुकअप के लिए (:foo bar) का उपयोग करें, (bar :foo) पर नहीं। यह सिर्फ standard way to do it है।
  • new-user के लिए स्थानीय बनाने की परेशानी न करें, क्योंकि आप केवल इसे एक बार उपयोग करते हैं; आप बस इसे रेखांकित कर सकते हैं।

एक और बदलाव है जो मैं नहीं करूँगा, क्योंकि मुझे लगता है कि यह पठनीयता को कम करेगा। हालांकि, यह शैली और निर्णय का विषय है, इसलिए मैं इसके बारे में सोचने के लिए कुछ के रूप में इसका उल्लेख करूंगा। ध्यान दें कि if भूलभुलैया की प्रत्येक शाखा resp/redirect पर कॉल में समाप्त होती है: आप उन सभी कॉल को शीर्ष-स्तर पर खींच सकते हैं। और फिर तय करें कि इसके पास कौन से तर्क पारित किए जाएंगे। अन्य बदलाव के साथ संयुक्त, यह लगेगा की तरह:

(defn create [session params] 
    (resp/redirect (if-let [user (user/find-by-email (:email params))] 
        (if (user/authenticate user (:password params)) 
        (do (sign-in session user) 
         "/home?signed-in=true") 
        "/?error=incorrect-password") 
        (do (sign-in session (user/create params)) 
         "/home?new-user=true")))) 
+0

यह बहुत अच्छा है। बहुत बहुत धन्यवाद! – hurshagrawal

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