clojure循环参见值 [英] clojure loop see values

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

问题描述

使用 reduce 时, reduction 函数查看列表连续减少。是否有类似于调试 循环 的东西在Clojure?

解决方案

@progo是对的,你总是可以添加另一个累加器,但如果你真的不想做它每次,你可以使一些实用程序宏为你做,而在语义上等于默认 loop / recur (我想的对 loop + / recur + (后者将被隐含地使用):

 (defmacro recur + args] 
(let [names(repeated(count args)gensym)]
`(let〜(vec(interleave names args))
(recur〜@ names(conj〜循环历史[〜@ names])))))

(defmacro loop + [bindings& body]
(let [ gensym)
vals(take-nth 2(rest bindings))
binding-lefts(take-nth 2 bindings)]
`(let [〜@(interleave val-names vals)
(loop [〜@(interleave binding-lefts val-names)
〜'& loop-history [〜(vec val-names)]]
〜@(clojure.walk / postwalk-replace
{'recur'recur +
'loop'loop +}
body)))))

$您可以看到 loop + 引入隐式值& loop-history ,并用 loop + 替换所有的内部 loop s和 recur $ c>和 recur + ,而 recur + 将此隐式var添加到 recur call( val-names vals binging-lefts 对于避免对传递给 loop + 的表单进行双重评估是必要的。



所以,假设你有这样的循环:

  user> (loop [a 1 b 2] 
(if(<= b 10)
(recur a(inc b))
(str ab)))
1 11

使用新循环只需调用loop +而不是循环:

  user> (loop + [a 1 b 2] 
(if(<= b 10)
(recur a(inc b))
(str ab)))
1 11

它扩展为以下内容:

 (let * 
[G__20054 1 G__20055 2]
(loop *
[a G__20054 b G__20055& loop-history [ G__20054 G__20055]]]
(if(< = b 10)
(let *
[G__20056 a G__20057(inc b)]
(recur
G__20056
G__20057
(conj& loop-history [G__20056 G__20057])))
(str ab))))

现在& loop-history 完全可以在loop +内访问:

  user> (循环+ [a 1 b 2] 
(if(<= b 10)
(do
(printlnhistory length:(count& loop-history)
last item:(last& loop-history))
(recur a(inc b)))
{:result(str ab)
:history& -history}))

;;历史长度:1最后一项:[1 2]
;;历史长度:2最后一项:[1 3]
;;历史长度:3最后一项:[1 4]
;;历史长度:4最后一个项目:[1 5]
;;历史长度:5最后一项:[1 6]
;;历史长度:6最后一项:[1 7]
;;历史长度:7最后一项:[1 8]
;;历史长度:8最后一项:[1 9]
;;历史长度:9最后一项:[1 10]
;; {:result1 11,:history [[1 2] [1 3] [1 4] [1 5] [1 6] [1 7] [1 8] [1 9] [1 10] [1 11 ]]

注意,它还引入了& / code>用于内部循环,而不需要更改源代码:

  user& (循环+ [a 1 b 2] 
(if(<= b 10)
(do(println:outer-hist& loop- history)
))
(loop [aa]
(if(> = a -4)
(do(println:inner-hist& loop- history)
dec a)))
(str ab))))

:outer-hist [[1 2]]
:outer-hist [[1 2] [1 3]]
:outer-hist [[1 2] [1 3] [1 4]]
:outer-hist [[1 2] [1 3] [1 4] ]
:outer-hist [[1 2] [1 3] [1 4] [1 5] [1 6]]
: 4] [1 5] [1 6] [1 7]]
:outer-hist [[1 2] [1 3] [1 4] [1 5] [1 6] [1 7] [1 8]]
:outer-hist [[1 2] [1 3] [1 4] [1 5] [1 6] [1 7] [1 8] [1 9]]
:外部组织[1 2] [1 3] [1 4] [1 5] [1 6] [1 7] [1 8] [1 9] [1 10]]
: [1]]
:inner-hist [[1] [0]]
:inner-hist [[1] [0] [-1] 1] [0] [-1] [-2]]
:inner-hist [[1] [0] [-1] [-2] [-3] [[1] [0] [-1] [-2] [-3] [-4]]
-511

When using reduce there is the reductions function to see the list of successive reductions. Is there something similar to debug a loop in Clojure ?

解决方案

@progo is right, you can always add another accumulator, but if you don't really want to do it every time, you could make some utility macro doing that for you, while being semantically equal to the default loop/recur (i am thinking of pair of loop+/recur+ (the latter would be used implicitly):

(defmacro recur+ [& args]
  (let [names (repeatedly (count args) gensym)]
    `(let ~(vec (interleave names args))
       (recur ~@names (conj ~'&loop-history [~@names])))))

(defmacro loop+ [bindings & body]
  (let [val-names (repeatedly (/ (count bindings) 2) gensym)
        vals (take-nth 2 (rest bindings))
        binding-lefts (take-nth 2 bindings)]
    `(let [~@(interleave val-names vals)]
       (loop [~@(interleave binding-lefts val-names)
              ~'&loop-history [~(vec val-names)]]
         ~@(clojure.walk/postwalk-replace
            {'recur 'recur+
             'loop 'loop+}
            body)))))

as you can see, loop+ introduces the implicit value &loop-history, and replaces all the inner loops and recurs with loop+ and recur+, while recur+ adds this implicit var to the recur call (the part with val-names, vals and binging-lefts is essential to avoid the double evaluation of the forms passed to the loop+).

so, imagine you have some loop like this:

user> (loop [a 1 b 2]
        (if (<= b 10)
          (recur a (inc b))
          (str a " " b)))
"1 11"

to use the new loop just call loop+ instead of loop:

user> (loop+ [a 1 b 2]
        (if (<= b 10)
          (recur a (inc b))
          (str a " " b)))
"1 11"

it is expanded into the following:

(let*
  [G__20054 1 G__20055 2]
  (loop*
    [a G__20054 b G__20055 &loop-history [[G__20054 G__20055]]]
    (if (<= b 10)
      (let*
        [G__20056 a G__20057 (inc b)]
        (recur
          G__20056
          G__20057
          (conj &loop-history [G__20056 G__20057])))
      (str a " " b))))

now &loop-history is totally accessible anywhere inside loop+:

user> (loop+ [a 1 b 2]
        (if (<= b 10)
          (do
            (println "history length: " (count &loop-history)
                     "last item: " (last &loop-history))
            (recur a (inc b)))
          {:result (str a " " b)
           :history &loop-history}))

;; history length:  1 last item:  [1 2]
;; history length:  2 last item:  [1 3]
;; history length:  3 last item:  [1 4]
;; history length:  4 last item:  [1 5]
;; history length:  5 last item:  [1 6]
;; history length:  6 last item:  [1 7]
;; history length:  7 last item:  [1 8]
;; history length:  8 last item:  [1 9]
;; history length:  9 last item:  [1 10]
;; {:result "1 11", :history [[1 2] [1 3] [1 4] [1 5] [1 6] [1 7] [1 8] [1 9] [1 10] [1 11]]}

notice, that it also introduces &loop-history for inner loops, without the need to change the source code:

user> (loop+ [a 1 b 2]
        (if (<= b 10)
          (do (println :outer-hist &loop-history)
              (recur a (inc b)))
          (loop [a a]
            (if (>= a -4)
              (do (println :inner-hist &loop-history)
                  (recur (dec a)))
              (str a b)))))

:outer-hist [[1 2]]
:outer-hist [[1 2] [1 3]]
:outer-hist [[1 2] [1 3] [1 4]]
:outer-hist [[1 2] [1 3] [1 4] [1 5]]
:outer-hist [[1 2] [1 3] [1 4] [1 5] [1 6]]
:outer-hist [[1 2] [1 3] [1 4] [1 5] [1 6] [1 7]]
:outer-hist [[1 2] [1 3] [1 4] [1 5] [1 6] [1 7] [1 8]]
:outer-hist [[1 2] [1 3] [1 4] [1 5] [1 6] [1 7] [1 8] [1 9]]
:outer-hist [[1 2] [1 3] [1 4] [1 5] [1 6] [1 7] [1 8] [1 9] [1 10]]
:inner-hist [[1]]
:inner-hist [[1] [0]]
:inner-hist [[1] [0] [-1]]
:inner-hist [[1] [0] [-1] [-2]]
:inner-hist [[1] [0] [-1] [-2] [-3]]
:inner-hist [[1] [0] [-1] [-2] [-3] [-4]]
"-511"

这篇关于clojure循环参见值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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