7

में गतिशील रूप से उच्च प्रदर्शन फ़ंक्शंस उत्पन्न करना मैं गतिशील रूप से उन कार्यों को उत्पन्न करने के लिए क्लोजर का उपयोग करने की कोशिश कर रहा हूं जो डेटा की बड़ी मात्रा में लागू हो सकते हैं - यानी एक आवश्यकता यह है कि कार्यों को तेजी से निष्पादित करने के लिए बाइटकोड में संकलित किया जा सकता है, लेकिन उनके विनिर्देश रन टाइम तक ज्ञात नहीं है।क्लोजर

उदा।

(def my-spec [:add [:multiply 2 :param0] 3]) 

मैं एक समारोह संकलन कल्पना बनाने के लिए ऐसी है कि चाहते हैं: मैं की तरह एक साधारण डीएसएल के साथ काम करता है निर्दिष्ट लगता

(compile-spec my-spec) 

में से एक पैरामीटर एक्स कि 2x रिटर्न एक संकलित समारोह वापसी होगी + 3।

क्लोजर में ऐसा करने का सबसे अच्छा तरीका क्या है?

उत्तर

11

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

सबसे पहले, Clojure के कोड के बारे में ऊपर बात हमेशा संकलित किया जा रहा fn/fn* रूपों और वास्तव में कुछ और है कि एक Clojure समारोह के रूप में कार्य कर सकते हैं पर eval फोन करके उच्च क्रम कार्य करता है और बनाया कार्यों द्वारा लौटाए गए बंदी भी शामिल है। इस प्रकार आप एक अलग डीएसएल कार्यों का वर्णन करने के लिए की जरूरत नहीं है, बस उच्च आदेश कार्यों (और संभवतः मैक्रो) का उपयोग करें:

(defn make-affine-function [a b] 
    (fn [x] (+ (* a x) b))) 

((make-affine-function 31 47) 5) 
; => 202 

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

(defmacro make-primitive-affine-function [t a b] 
    (let [cast #(list (symbol (name t)) %) 
     x (gensym "x")] 
    `(fn [~x] (+ (* ~(cast a) ~(cast x)) ~(cast b))))) 

((make-primitive-affine-function :int 31 47) 5) 
; => 202 

उपयोग :int, :long, :float या :double (या गैर नाम स्थान से योग्य इसी नाम के प्रतीक) पहला तर्क लाभ लेने के लिए के रूप में आपके तर्क प्रकारों के लिए उपयुक्त अनबॉक्स किए गए आदिम अंकगणित का। आपके फ़ंक्शन के प्रदर्शन के आधार पर, यह आपको एक बहुत ही महत्वपूर्ण प्रदर्शन बढ़ावा दे सकता है।

अन्य प्रकार के संकेत आमतौर पर #^Foo bar सिंटैक्स (^Foo bar 1.2 में एक ही चीज़ के साथ प्रदान किए जाते हैं) प्रदान किए जाते हैं; यदि आप उन्हें मैक्रो-जेनरेट कोड में जोड़ना चाहते हैं, तो with-meta फ़ंक्शन की जांच करें (आपको अपने कार्यों के औपचारिक तर्कों का प्रतिनिधित्व करने वाले प्रतीकों के मेटाडेटा में '{:tag Foo} को मर्ज करने की आवश्यकता होगी या let- उन स्थानीय लोगों को जिन्हें आप टाइप संकेत देना चाहते हैं)।


ओह, और मामले में आप अभी भी पता करने के लिए अपने मूल विचार को लागू करने के लिए कैसे करना चाहते हैं ...

आप हमेशा अपने समारोह को परिभाषित करने के Clojure अभिव्यक्ति का निर्माण कर सकते हैं - (list 'fn ['x] (a-magic-function-to-generate-some-code some-args ...)) - और कॉल परिणाम पर eval।इससे आपको निम्न की तरह कुछ करने में मदद मिलेगी (यह आवश्यक होगा कि spec में पैरामीटर सूची शामिल हो, लेकिन यहां एक संस्करण है कि तर्कों को तर्क से बाहर निकाला जाना है, सभी को paramFOO कहा जाता है और उन्हें लेक्सिकोग्राफिक रूप से क्रमबद्ध किया जाता है):

(require '[clojure.walk :as walk]) 

(defn compile-spec [spec] 
    (let [params (atom #{})] 
    (walk/prewalk 
    (fn [item] 
     (if (and (symbol? item) (.startsWith (name item) "param")) 
     (do (swap! params conj item) 
      item) 
     item)) 
    spec) 
    (eval `(fn [[email protected](sort @params)] [email protected])))) 

(def my-spec '[(+ (* 31 param0) 47)]) 

((compile-spec my-spec) 5) 
; => 202 

समय के विशाल बहुमत, वहाँ बातें इस तरह से है और यह बचा जाना चाहिए करने के लिए कोई अच्छा कारण है; इसके बजाय उच्च-आदेश फ़ंक्शंस और मैक्रोज़ का उपयोग करें। हालांकि, अगर आप कुछ ऐसा कर रहे हैं, कहें, विकासवादी प्रोग्रामिंग, तो यह वहां है, परम लचीलापन प्रदान करना - और नतीजा अभी भी एक संकलित कार्य है।

+1

यह एक अच्छा जवाब है: मुझे समझने में मदद मिली कि हुड के नीचे क्या चल रहा है और समस्या को पूरी तरह से हल करता है। बहुत धन्यवाद माइकल! – mikera

+0

मदद करने के लिए खुश। :-) –

6

भले ही आप एओटी को अपने कोड को संकलित नहीं करते हैं, जैसे ही आप एक फ़ंक्शन को परिभाषित करते हैं, यह फ्लाई पर बाइटकोड में संकलित हो जाता है।