对任何错误的术语表示歉意 - 我对计算机科学很陌生,我几乎只知道Clojure(但我想我会说我很清楚).
所以,我还没有对此做过大量的研究,但我有时发现在编写Clojure代码时能够从该数据结构中引用一些"我所处的任何数据结构的中间版本" (很像a let).快速举例:
=> (self-ish {:a 10
:b (inc (this :a))
:c (count (vals this))})
=> {:a 10, :b 11, :c 3}
=> (self-ish ["a" "b" (reduce str this)])
=> ["a" "b" "ab"]
//Works in any nested bits too
=> (self-ish [1 2 3 [4 5 (first this)] 6 [7 [8 (cons (second this) (nth this 3))]]])
=> [1 2 3 [4 5 1] 6 [7 [8 (2 4 5 1)]]]
Run Code Online (Sandbox Code Playgroud)
这个想法是结构逐渐建立起来,并且在任何阶段都有能力将当前的中间结构称为this.这是我当前实现的代码:
//Random straightforward …Run Code Online (Sandbox Code Playgroud) 作为前言,我在Windows 7(64位)上运行Java版本6(更新33),使用clooj作为我的IDE.我没有尝试在任何其他系统中重现我的问题.我对Clojure很有经验,但对Java一点也不熟悉.
我试图解决的问题的全部内容很难描述,但它归结为:我想说我想制作一个带有一个参数的宏,一个关联映射,并返回一个元素的向量地图与他们的订单保存.
=>(defmacro vectorize-a-map
[associative-map]
(vec associative-map))
=>#'ns/vectorize-a-map
=>(vectorize-a-map {:a 1 :b 2 :c 3 :d 4 :e 5 :f 6 :g 7 :h 8}
=>[[:a 1] [:b 2] [:c 3] [:d 4] [:e 5] [:f 6] [:g 7] [:h 8]]
Run Code Online (Sandbox Code Playgroud)
这是有效的,但添加另一个元素到地图和订单搞砸...
=>(vectorize-a-map {:a 1 :b 2 :c 3 :d 4 :e 5 :f 6 :g 7 :h 8 :i 9}
=>[[:a 1] [:c 3] [:b 2] [:f 6] [:g 7] [:d 4] [:e 5] [:i 9] …Run Code Online (Sandbox Code Playgroud) 是否有一种干净的方式来实现动态范围,以"达到"宏调用?也许更重要的是,即使有,也应该避免?
这是我在REPL中看到的内容:
user> (def ^:dynamic *a* nil)
> #'user/*a*
user> (defn f-get-a [] *a*)
> #'user/f-get-a
user> (defmacro m-get-a [] *a*)
> #'user/m-get-a
user> (binding [*a* "boop"] (f-get-a))
> "boop"
user> (binding [*a* "boop"] (m-get-a))
> nil
Run Code Online (Sandbox Code Playgroud)
这个m-get-a宏不是我的实际目标,它只是我遇到的问题的一个简化版本.我花了一段时间才意识到,因为我一直在调试macroexpand,这使得一切看起来都很好:
user> (binding [*a* "boop"] (macroexpand '(m-get-a)))
> "boop"
Run Code Online (Sandbox Code Playgroud)
在外部调用上执行macroexpand-all(使用clojure.walk)binding会让我相信"问题"(或特征,视情况而定)是(m-get-a)在动态绑定之前进行评估:
user> (macroexpand-all '(binding [*a* "boop"] (f-get-a)))
> (let* []
(clojure.core/push-thread-bindings (clojure.core/hash-map #'*a* "boop"))
(try (f-get-a) (finally (clojure.core/pop-thread-bindings))))
user> (macroexpand-all …Run Code Online (Sandbox Code Playgroud) 这是我想要的行为:
user> (bit-get 4 2)
> 1
Run Code Online (Sandbox Code Playgroud)
我知道这可以超级轻松地使用bit-test,即:
(defn bit-get [x n]
(if (bit-test x n) 1 0))
Run Code Online (Sandbox Code Playgroud)
但我很好奇是否已有任何东西.它可能对我来说有点小,但它似乎不是最佳(但是最低限度)必须测试某些东西是否,0或者1然后返回它们是否是0或者1基于该测试.因此,我也很高兴听到有任何方法可以在这里切断中间人,无论bit-getClojure或Java世界中是否有任何以前制作的功能.或许我首先弄错了,关于编译或运行时优化的一些事情使我bit-get上面的函数实际上不必运行测试只是为了返回它正在测试的值?或者 - 看到我对于按位运算符中涉及的时序/速度优化几乎一无所知 - 也许它似乎只是次优,但实际上是出于某种原因实现它的最快方式?