2011-11-04 12 views
10

मान लीजिए मैं दो प्रोटोकॉल है:आप किसी अन्य प्रोटोकॉल पर क्लोजर प्रोटोकॉल कैसे बढ़ा सकते हैं?

(defprotocol A 
    (f [this])) 

(defprotocol B 
    (g [x y])) 

और मैं सभी उदाहरणों का समर्थन करने वाले प्रोटोकॉल एक करने के लिए प्रोटोकॉल बी का विस्तार करना चाहते:

(extend-protocol A 
    String 
    (f [this] (.length this))) 

(extend-protocol B 
    user.A 
    (g [x y] (* (f x) (f y)))) 

प्राथमिक प्रेरणा सभी के लिए अलग से बी का विस्तार करने के लिए होने से बचने के लिए है संभावित वर्ग जिन्हें ए को विस्तारित किया जा सकता है, या यहां तक ​​कि अज्ञात भविष्य के वर्गों तक भी, जो अन्य लोग ए को बढ़ा सकते हैं (कल्पना करें कि ए सार्वजनिक रूप से सार्वजनिक एपीआई का हिस्सा था या नहीं)।

हालांकि यह काम नहीं करता - आप निम्नलिखित की तरह कुछ मिलता है:

(g "abc" "abcd") 
=> #<IllegalArgumentException java.lang.IllegalArgumentException: 
No implementation of method: :g of protocol: #'user/B found for 
class: java.lang.String> 

बिल्कुल यह संभव है? यदि नहीं, तो क्या वही उद्देश्य प्राप्त करने के लिए एक समझदार कामकाज है?

उत्तर

7

यह है कि आप f के मामले में समारोह g लागू कर सकते हैं मुझे लगता है। यदि ऐसा है तो आपके पास प्रोटोकॉल B प्रोटोकॉल के बिना आवश्यक सभी पॉलीमोर्फिज्म है।

क्या मेरा मतलब है निम्नलिखित, यह देखते हुए कि f बहुरूपी है, तो

(defn g [x y] 
    (* (f x) (f y))) 

एक समारोह g जो सभी प्रकार के जो प्रोटोकॉल A लागू करता है समर्थन करता है पैदावार है।

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

अनुक्रम पुस्तकालय इस का एक बड़ा उदाहरण है। सरलीकृत, दो बहुलक कार्य हैं, first और rest। शेष अनुक्रम पुस्तकालय सामान्य कार्य है।

+0

धन्यवाद। मुझे लगता है कि यह मेरे मामले में सबसे अच्छा तरीका है - अनुक्रम पुस्तकालय के साथ समानता अच्छी तरह से काम करती है! – mikera

9

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

आप एक से अधिक प्रकार है कि सभी एक ही कार्यान्वयन के लिए हो है, तो आप बस एक आम समारोह कॉल कर सकते हैं। वैकल्पिक रूप से, आप उस मानचित्र के साथ एक विधि मानचित्र और extend प्रत्येक प्रकार बना सकते हैं। उदा .:

 
(defprotocol P 
    (a [p]) 
    (b [p])) 

(deftype R []) 
(deftype S []) 
(deftype T []) 

(def common-P-impl 
    {:a (fn [p] :do-a) 
    :b (fn [p] :do-b)}) 

(extend R 
    P common-P-impl) 
(extend S 
    P common-P-impl) 
(extend T 
    P common-P-impl) 

यदि आप अपने वास्तविक परिदृश्य पर कुछ और जानकारी प्रदान करते हैं, तो हम सही दृष्टिकोण का सुझाव दे सकते हैं।

+0

यह मेरा समाधान भी होगा - मुझे लगता है कि डुप्लिकेशंस को हटाने के लिए 'मानचित्र' का लाभ उठाया जा सकता है, उदाहरण के लिए '(नक्शा # (विस्तार% पी आम-पी-इम्प्लायर) [आर एस टी])' – KingCode

+0

क्षमा करें, 'डोसेक', या एक संलग्न 'डोल' का उपयोग फिर से किया जाना चाहिए: नक्शा आलसी होना .. – KingCode

0

हालांकि मैं पूरी तरह से समझ में नहीं आता तुम क्या करने कोशिश कर रहे हैं, मुझे आश्चर्य है अगर clojure मुल्टीमेथड्स आपकी समस्या के लिए एक बेहतर समाधान हो जाएगा।

1

मैं क्या देख से, प्रोटोकॉल वास्तव में प्रोटोकॉल का विस्तार कर सकते हैं। मैं यहाँ एक उदाहरण बना दिया: https://github.com/marctrem/protocol-extend-protocol-example/blob/master/src/extproto/core.clj

उदाहरण में, हम एक Animalia प्रोटोकॉल (जो की अनुमति देने के अपने सदस्यों करना dream) जो एक Erinaceinae प्रोटोकॉल (जो go-fast को अपने सदस्यों की अनुमति देता है) के लिए बढ़ा दी है।

हमारे पास Hedgehog रिकॉर्ड है जो Erinaceinae प्रोटोकॉल का हिस्सा है। रिकॉर्ड का हमारा उदाहरण dream और go-fast दोनों कर सकता है।

(ns extproto.core 
    (:gen-class)) 


(defprotocol Animalia (dream [this])) 

(defprotocol Erinaceinae (go-fast [this])) 

(extend-protocol Animalia 
    extproto.core.Erinaceinae 
    (dream [this] "I dream about things.")) 

(defrecord Hedgehog [lovely-name] 
    Erinaceinae 
    (go-fast [this] (format "%s the Hedgehog has got to go fast." (get this :lovely-name)))) 



(defn -main 
    [& args] 
    (let [my-hedgehog (Hedgehog. "Sanic")] 
    (println (go-fast my-hedgehog)) 
    (println (dream my-hedgehog)))) 

;1> Sanic the Hedgehog has got to go fast. 
;1> I dream about things. 
1
में

"Clojure लागू किया" वहाँ प्रोटोकॉल द्वारा विस्तार प्रोटोकॉल का एक नुस्खा

(extend-protocol TaxedCost 
    Object 
    (taxed-cost [entity store] 
    (if (satisfies? Cost entity) 
     (do (extend-protocol TaxedCost 
      (class entity) 
      (taxed-cost [entity store] 
       (* (cost entity store) (+ 1 (tax-rate store))))) 
      (taxed-cost entity store)) 
     (assert false (str "Unhandled entity: " entity))))) 

वास्तव में कुछ भी नहीं है एक दूसरे से

(extend-protocol TaxedCost 
    Cost 
    (taxed-cost [entity store] 
    (* (cost entity store) (+ 1 (tax-rate store))))) 

द्वारा बस का विस्तार प्रोटोकॉल से रोकता है, जबकि किताब में लिखा यह नहीं है मुमकिन। मैंने इस बारे में एलेक्स मिलर से बात की है और उन्होंने निम्नलिखित कहा:

यह वास्तव में सभी मामलों में काम नहीं करता है। प्रोटोकॉल जावा इंटरफ़ेस उत्पन्न करता है और आप निश्चित रूप से उस इंटरफ़ेस में प्रोटोकॉल का विस्तार कर सकते हैं। समस्या यह है कि प्रत्येक प्रोटोकॉल कार्यान्वयन उस इंटरफ़ेस को लागू नहीं करता है - केवल (defrecord Foo [a] TheProtocol (foo ...)) जैसे इनलाइन घोषणा के साथ ऐसा रिकॉर्ड या प्रकार करता है। यदि आप extend-type या extend-protocol का उपयोग कर प्रोटोकॉल को कार्यान्वित कर रहे हैं, तो उन उदाहरणों को प्रोटोकॉल इंटरफ़ेस के विस्तार से पकड़ा नहीं जाएगा। तो, आपको वास्तव में ऐसा नहीं करना चाहिए :)

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