2009-10-28 6 views
11

मेरे पास क्लोजर में संख्यात्मक कार्यों का एक समूह है जो मैं तर्कों को मान्य करना चाहता हूं। कार्यों द्वारा अपेक्षित कई प्रकार के तर्क हैं, जैसे कि सकारात्मक पूर्णांक, प्रतिशत, संख्याओं के अनुक्रम, गैर-शून्य संख्याओं के अनुक्रम, और इसी तरह। मैं किसी भी व्यक्तिगत फ़ंक्शन के लिए तर्कों को मान्य कर सकता हूं:क्या क्लोजर में तर्कों को सत्यापित करने के लिए मुझे फ़ंक्शन या मैक्रो का उपयोग करना चाहिए?

  1. फ़ंक्शन सत्यापन कोड फ़ंक्शन में लिख रहा है।
  2. एक सामान्य उद्देश्य समारोह लिखना, इसे तर्क और अपेक्षित प्रकारों को पारित करना।
  3. एक सामान्य उद्देश्य मैक्रो लिखना, इसे तर्क और अपेक्षित प्रकारों को पारित करना।
  4. अन्य मैंने सोचा नहीं है।

लैरी हंटर द्वारा कुछ Lisp code # 3 का एक अच्छा उदाहरण है। (test-variables मैक्रो की तलाश करें।)

मेरा अंतर्ज्ञान यह है कि मूल्यांकन पर नियंत्रण और संकलन-समय गणना करने की क्षमता के चलते मैक्रो अधिक उचित है क्योंकि इसे रन टाइम पर करने के बजाय। लेकिन, मैं जिस कोड को लिख रहा हूं उसके लिए मैंने उपयोग के मामले में भाग नहीं लिया है, जिसके लिए इसकी आवश्यकता होती है। मैं सोच रहा हूं कि ऐसा मैक्रो लिखने के प्रयास के लायक है या नहीं।

कोई सुझाव?

उत्तर

13

क्लोज़र में पहले से ही fn एस पर पूर्व और बाद की स्थितियों के लिए समर्थन (अनियंत्रित, शायद विषय-परिवर्तन) समर्थन है।

user> (defn divide [x y] 
     {:pre [(not= y 0)]} 
     (/ x y)) 
user> (divide 1 0) 
Assert failed: (not= y 0) 
    [Thrown class java.lang.Exception] 

यद्यपि बदसूरत।

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

(defmacro assert* [val test] 
    `(let [result# ~test]    ;; SO`s syntax-highlighting is terrible 
    (when (not result#) 
     (throw (Exception. 
       (str "Test failed: " (quote ~test) 
        " for " (quote ~val) " = " ~val)))))) 

(defmulti validate* (fn [val test] test)) 

(defmethod validate* :non-zero [x _] 
    (assert* x (not= x 0))) 

(defmethod validate* :even [x _] 
    (assert* x (even? x))) 

(defn validate [& tests] 
    (doseq [test tests] (apply validate* test))) 

(defn divide [x y] 
    (validate [y :non-zero] [x :even]) 
    (/ x y)) 

तब:

user> (divide 1 0) 
; Evaluation aborted. 
; Test failed: (not= x 0) for x = 0 
; [Thrown class java.lang.Exception] 

user> (divide 5 1) 
; Evaluation aborted. 
; Test failed: (even? x) for x = 5 
; [Thrown class java.lang.Exception] 

user> (divide 6 2) 
3 
+0

नाइस; पता नहीं था कि – pmf

+0

एक और महान जवाब के लिए धन्यवाद। यह वही करता है जो मैं करना चाहता था। यह एक कारण बताता है कि मैक्रो एक बेहतर समाधान है। समस्या तर्क को असंबद्ध करने के तरीके के बारे में सोचते हुए यदि किसी फ़ंक्शन को दो विशेषताओं के साथ दो या अधिक की आवश्यकता होती है, तो दो सकारात्मक पूर्णांक कहें, मैक्रो मार्ग आपको त्रुटि संदेश में समस्या तर्क का नाम देता है, केवल मूल्य नहीं। मुझे नहीं लगता कि आप इसे एक समारोह के साथ कर सकते हैं। – clartaq

+1

पूर्व शर्त और पोस्टकंडिशन यहां दस्तावेज किए गए हैं http://clojure.org/special_forms हालत मानचित्र के लिए खोजें। – Chouser

3

बस कुछ विचार।

मुझे लगता है कि यह जटिलता और सत्यापन की संख्या, और कार्यों की प्रकृति पर निर्भर करता है।

यदि आप बहुत ही जटिल सत्यापन कर रहे हैं, तो आपको अपने वैधताओं को अपने कार्यों से बाहर करना चाहिए। तर्क यह है कि आप अधिक जटिल लोगों को बनाने के लिए सरल लोगों का उपयोग कर सकते हैं।

उदाहरण के लिए, आप लिखते हैं:

  1. एक सत्यापनकर्ता यकीन है कि एक सूची खाली नहीं है बनाने के लिए,
  2. एक सत्यापनकर्ता यकीन है कि एक मूल्य शून्य से अधिक है बनाने के लिए,
  3. उपयोग 1 और 2 को सुनिश्चित करें कि मान शून्य से अधिक मानों की एक खाली खाली सूची है।

यदि आप केवल एक बड़ी मात्रा में सरल सत्यापन कर रहे हैं, और आपकी समस्या वर्बोजिटी है, (उदाहरण के लिए आपके पास 50 कार्य हैं जिन्हें सभी को गैर-शून्य पूर्णांक की आवश्यकता होती है), तो एक मैक्रो शायद अधिक समझ में आता है।

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

अंत में, "उन लोगों को संबोधित करने के लिए जिन्हें आपने नहीं सोचा है"। क्लोजर एक प्रेषण functon पर pbased एक जेनेरिक प्रेषण का समर्थन करता है। वह फ़ंक्शन उचित कोड, या किसी भी कारकों के आधार पर त्रुटि संदेशों को प्रेषित कर सकता है।

1

एक मामले में जहां आप की जरूरत यदि आप भाषा को संशोधित करने के लिए स्वचालित रूप से इस तरह, एक ब्लॉक के भीतर परिभाषित किसी भी कार्य करने के लिए परीक्षण जोड़ना चाहते थे एक मैक्रो होगा:

(with-function-validators [test1 test2 test4] 
    (defn fun1 [arg1 arg2] 
     (do-stuff)) 
    (defn fun2 [arg1 arg2] 
     (do-stuff)) 
    (defn fun3 [arg1 arg2] 
     (do-stuff))) 
संबंधित मुद्दे

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