Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/clojure/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在第一个真谓词匹配的嵌套映射上退出Clojure walk postwalk?_Clojure - Fatal编程技术网

如何在第一个真谓词匹配的嵌套映射上退出Clojure walk postwalk?

如何在第一个真谓词匹配的嵌套映射上退出Clojure walk postwalk?,clojure,Clojure,我使用clojure.walk/postwark将谓词与嵌套集合中的每个映射进行比较,并希望在第一个true中以true退出。我该怎么做?我同意它遍历整个数据结构,如果存在true匹配,则返回true 作为一个推论问题,我想同样的问题也适用于执行map而不是postwark时 更新:这确实是一个令人厌倦/懒惰的问题;我应该提供一个代码示例。这就是说,我把它留着,以防现在有人对我这个半生不熟的问题给出答案。唯一比问别人更糟糕的是,在有人友善地开始帮忙后,把它取下来。如果没有人回答,如果他们要求一个

我使用
clojure.walk/postwark
将谓词与嵌套集合中的每个映射进行比较,并希望在第一个
true
中以true退出。我该怎么做?我同意它遍历整个数据结构,如果存在
true
匹配,则返回true

作为一个推论问题,我想同样的问题也适用于执行
map
而不是
postwark


更新:这确实是一个令人厌倦/懒惰的问题;我应该提供一个代码示例。这就是说,我把它留着,以防现在有人对我这个半生不熟的问题给出答案。唯一比问别人更糟糕的是,在有人友善地开始帮忙后,把它取下来。如果没有人回答,如果他们要求一个更好的问题,或者他们只是给我一些研究建议,我会非常满意。

您可能对我称之为
walk seq
的这个功能感兴趣。它返回一个数据结构上的延迟深度优先序列,然后您可以对该序列进行
搜索
以找到第一个匹配项。我发现在这里更可取,因为它不需要回调和异常来像
clojure.walk/postwark
那样提前退出


(定义如下)
“返回数据结构中所有表单的延迟深度优先序列。”
[表格]
(树序列集合?序列表格)
(defn seek)
“查找集合中与pred匹配的第一个元素,
else返回未找到。请注意,使用seek可能导致
性能差,应始终使用索引数据
结构,而不是对同一数据进行多次搜索。”
([pred coll]
(搜索pred coll nil))
([pred coll未找到]
(减少(fn[nf x](如果(pred x)(减少的x)nf))未找到coll)))
walk seq的用法

(defn find-deep [pred data not-found]
  (->> data
       (tree-seq coll? seq)
       (some #(when (pred %) [%]))
       ((fnil first [not-found]))))

user> (find-deep #(= (:c %) 30) [{:a 10 :b [{:c 20 :d {:c 30}}]}] ::none)
;;=> {:c 30}

user> (find-deep #(= (:c %) 40) [{:a 10 :b [{:c 20 :d {:c 30}}]}] ::none)
;;=> :user/none

(行走序列{:a[{:b-1}{:b1}]:b2})
=>
({:a[{:b-1}{:b1}],:b2}
[:a[{:b-1}{:b1}]]
:a
[{:b-1}{:b 1}]
{:b-1}
[:b-1]
:b
-1
{:b1}
[:b 1]
:b
1.
[:b2]
:b
2)
将两者结合起来:

(seek(每个pred编号?pos?)(walk seq{:a[{:b-1}{:b1}]:b2})
=>
1.

如我在注释中所建议的,只要谓词为true,就可以通过postwalk抛出异常来完成。这种方法非常传统,但很简洁,让我们可以重用
postwark
的逻辑来遍历数据结构:

(defn walk-some [pred data]
  (try
    (clojure.walk/postwalk
     #(if (pred %)
        (throw (ex-info "Found" {:data %}))
        %)
     data)
    false
    (catch clojure.lang.ExceptionInfo e
      true)))

(walk-some #(and (number? %) (odd? %)) {:a [[9] 3]})
;; => true

(walk-some #(and (number? %) (even? %)) {:a [[9] 3]})
;; => false

很少需要为控制流使用异常,但偶尔也需要稍微偏离约定。您可能需要定义一个自定义异常类型,以提高健壮性,以防谓词可以抛出类型为
ExceptionInfo
的对象,方法稍有不同,还可以使用
树序列

(defn find-deep [pred data not-found]
  (->> data
       (tree-seq coll? seq)
       (some #(when (pred %) [%]))
       ((fnil first [not-found]))))

user> (find-deep #(= (:c %) 30) [{:a 10 :b [{:c 20 :d {:c 30}}]}] ::none)
;;=> {:c 30}

user> (find-deep #(= (:c %) 40) [{:a 10 :b [{:c 20 :d {:c 30}}]}] ::none)
;;=> :user/none

如果您想要的唯一结果是
true
false
,那么听起来您根本不想要
postwark
。您希望编写一个递归函数,该函数使用您的一个结构并生成一个布尔值。如果在一个分支中发现结果,则可以短路。听起来不错。。。现在我将对此进行研究。一旦谓词为true,您就可以在walk中抛出异常。如果周围的代码捕捉到该异常,则表示谓词在某个地方为true。这种方法当然是非传统的,但它可以工作。我相信
coll?
(来自标准库)可以用来代替
branch?
,谢谢。我已将答案更新为使用
coll?
。我对一些案例有模糊的记忆,这导致我改用了
seqable?
,但我现在找不到它——也许它是针对我项目中的自定义数据类型的。