我意识到以下是一个坏主意,有很多原因。我还意识到,如果我有一个23的堆栈溢出代表,这是自然的假设,我是一个新手学习编程。然而,请幽默我,并专注于“我们如何能做到这一点”而不是“为什么你想这样做/你不想这样做”方面。
我想要的:
(def dog (Dog. ...))
(def cat (Cat. ...))
(with-animal dog
(println (str "Dog: " (speak) "\n")))
(with-animal cat
(println (str "Cat: " (speak) "\n")))到产出:
Dog: woof
Cat: meow所以,基本上,我希望-动物成为一个宏。所有出现的“call”函数调用都被映射到我正在调用块的对象。
特别是,我不想写:
(let-binding [speak (fn [] "woof")] ...)
(let-binding [speak (fn [] "meow")] ...)更确切地说,我想让with -动物将want函数映射到我正在调用的对象的某些方法。
有没有一种干净的方法在Clojure中做到这一点?
谢谢!
发布于 2012-10-08 21:46:53
动态绑定的存在是有原因的,而且它有许多很好的用途,所以不必担心会因为寻求理解它而发火:-)许多旧的Clojure教程在需要添加^:动态元数据之前就出现了一些混乱,您希望动态地重新绑定这些元数据。
第一个示例通过重新绑定现有名称来使用动态绑定。这就消除了宏引入新符号的需要:
首先制作一些动物,我只是在这个例子中使用地图,很多人会使用其他类型的对象:
(def dog {:sound #(str "wooooof")})
(def cat {:sound #(str "mewwww")})定义我们要重新绑定的函数为动态函数(这允许重新绑定)
(defn :^dynamic speak [] (println "eh?"))编写一个基本的模板宏来绑定,与动物中的函数对话:
(defmacro with-animal [animal & body]
`(binding [speak (:sound ~animal)]
~@body))并测试它:
(with-animal dog
(println (str "Dog: " (speak) "\n")))
Dog: wooooof
现在,“高级版本”使用了一个let,而不需要动态绑定,它只是在范围内引入了一个符号speak。这并不是说绑定在某种程度上是不好的,它只是更符合您不编写(let-binding [speak (fn [] "meow")] ...)的愿望--这种maco被称为回指(如果您喜欢这么花哨的名字):
重要的部分是在~'符号之前的speak符号,该符号在作用域中显式地引入了一个非限定符号:
user> (defmacro with-animal [animal & body]
`(let [~'speak (:sound ~animal)]
~@body))
#'user/with-animal
user> (with-animal dog
(println (str "Dog: " (speak) "\n")))
Dog: wooooof
nil
我希望这两个示例之间的对比有助于回答您关于将对象的行为绑定到作用域的问题。第一个示例绑定maco的主体和从该主体调用的任何内容的值。第二个示例只介绍宏主体的名称。
发布于 2015-07-17 15:09:50
如果您真的想让动物类型习惯性地说话,请使用Clojure协议:
(defprotocol ISpeak
(speak [animal] "make the type say it's thing"))
(deftype Dog []
ISpeak
(speak [this] "Woof!"))
(deftype Cat []
ISpeak
(speak [_] "Meow!!")) ;;you can "drop" the item if not used using _
(def a-dog (Dog.))
(speak a-dog)
;;=>"Woof!"
(def a-cat (Cat.))
(speak a-cat)
;;=>"Meow!!"请注意,您可以使用type方法扩展任何类型(类)。
(extend java.util.Random
ISpeak
{:speak (fn [_] "I'm throwing dices at you!")})
(speak (java.util.Random.))
;;=>"I'm throwing dices at you!"Java类的语法略有不同,请参阅协议文档获取更多信息。
https://stackoverflow.com/questions/12789350
复制相似问题