Clojure动态绑定 [英] Clojure Dynamic Binding

查看:133
本文介绍了Clojure动态绑定的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我意识到以下是一个坏主意,有很多原因。我也意识到,由于我有一个stackoverflow rep 23,它的性质假设我是一个新手学习程序。但是,请幽默我,并专注于我们怎么能做到这一点而不是你为什么要这样做/你不想这样做方面。

I realize the following is a bad idea for many reasons. I also realize that given I have a stackoverflow rep of 23, it's nature to assume that I'm a newb learning to program. However, please humor me, and focus on the "how can we do this" rather than "why do you want to do this / you don't want to do this" aspect.

我想要的:

(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

所以基本上,我想要与动物

So basically, I want with-animal to be a macro s.t. all occurences of the "speak" function call gets mapped to the object I'm calling the block with.

特别是,我不想写:

(let-binding [speak (fn [] "woof")] ...)
(let-binding [speak (fn [] "meow")] ...)

动物让 功能映射到我正在呼叫的对象的某些方法。

Rather, I want the with-animal to make the speak function map to some method of the object I'm calling with.

有一个干净的方法来做这个Clojure?

Is there a clean way to do this in Clojure?

感谢!

推荐答案

它有很多伟大的用途,所以没有担心被火焰寻求理解它: - )有一些混乱浮动在许多老的Clojure教程,预先需要添加^:动态元数据vars你期望动态重新绑定。

Dynamic binding exists for a reason and it has lots of great uses, so no worries about being flamed for seeking to understand it :-) There is some confusion floating around many older Clojure tutorials that pre-date the need for adding ^:dynamic metadata to vars that you expect to dynamically rebind.

此第一个示例通过重新绑定现有名称使用动态绑定。这不需要宏引入一个新的符号:



首先使一些动物,我只是在这个例子中使用地图,很多人会使用一些其他类型的对象:

This first example uses dynamic binding by rebinding an existing name. This removes the need for the macro to introduce a new symbol:


first make some animals, I just use maps in this example, many people will use some other type of Object:

(def dog {:sound #(str "wooooof")})
(def cat {:sound #(str "mewwww")})

定义我们将重新绑定为动态(允许重新绑定) / p>

define the function we will be rebinding to be dynamic (which allows rebinding)

(defn :^dynamic speak [] (println "eh?"))

写一个基本的模板宏来绑定动物中的函数:

write a basic template macro to bind speak to the function in the animal:

(defmacro with-animal [animal & body] 
    `(binding [speak (:sound ~animal)] 
       ~@body))

并测试:

(with-animal dog  
  (println (str "Dog: " (speak) "\n")))
Dog: wooooof                                                   



现在的高级版本只是在范围中引入了一个符号 speak 使用let不需要动态绑定。这不是说绑定在某种程度上是坏的,它更符合你的愿望不写(let-binding [speak(fn []meow)] ...) code>这种类型的maco被称为anaphoric(如果你是这样的名字):


and now the "advanced version" which just introduces a symbol speak into the scope using a let with no need for dynamic binding. This is not to say that binding is bad in some way, it just more closely fits your desire to not write (let-binding [speak (fn [] "meow")] ...) This type of maco is called anaphoric (if you're into such fancy names):

重要的部分是〜在讲话符号之前明确引入未限定符号的

the important part is the ~' before the speak symbol that explicitly introduces an un-qualified symbol into the scope:

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主体的值和从该主体调用的任何内容。第二个示例为宏的主体引入名称ONLY。


I hope that the contrast between these two examples serves to answer your question about binding behavior from an object into a scope. The first example binds the value for the body of the maco AND anything that is called from that body. The second example introduces the name ONLY for the body of the macro.

这篇关于Clojure动态绑定的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆