clojure - `for` 作为函数而不是宏
问题描述
我想要一个forall
函数,它的行为类似于for
但将序列列表作为输入。
(forall (fn [arr]
(prn arr))
(range 10)
(range 10)
(range 10))
=>
; [0 0 0]
; [0 0 1]
; [0 0 2]
; ....
; [9 9 9]
有什么好办法写这个吗?
解决方案
我想你想映射输入序列的笛卡尔积,对吧?如果是这样,您可以使用例如clojure.math.combinatorics/cartesian-product
来自clojure.math.combinatorics库的函数创建笛卡尔积的惰性序列,然后对其进行映射。
(defn forall [f & seqs]
(map f (apply clojure.math.combinatorics/cartesian-product seqs)))
当有多个序列时,这个函数或多或少类似于宏。for
这是调用它的示例,以及您将获得的结果:
(forall (fn [arr]
[:element arr])
(range 3)
(range 3)
(range 3))
;; => ([:element (0 0 0)] [:element (0 0 1)] [:element (0 0 2)] [:element (0 1 0)] [:element (0 1 1)] [:element (0 1 2)] [:element (0 2 0)] [:element (0 2 1)] [:element (0 2 2)] [:element (1 0 0)] [:element (1 0 1)] [:element (1 0 2)] [:element (1 1 0)] [:element (1 1 1)] [:element (1 1 2)] [:element (1 2 0)] [:element (1 2 1)] [:element (1 2 2)] [:element (2 0 0)] [:element (2 0 1)] [:element (2 0 2)] [:element (2 1 0)] [:element (2 1 1)] [:element (2 1 2)] [:element (2 2 0)] [:element (2 2 1)] [:element (2 2 2)])
请注意,在您的示例代码中,您调用的prn
函数是有副作用的,而for
-macro 会产生一个惰性序列。通常不鼓励将惰性与副作用结合起来,因为除非您知道惰性序列是如何工作的,否则副作用可能不会在您期望它发生时发生。
如果不想拉clojure.math.combinatorics
入库,可以轻松实现自己的笛卡尔积函数,例如
(defn cart2 [a b]
(for [x a
y b]
(conj x y)))
(defn my-cartesian-product [& arrs]
(reduce cart2 [[]] arrs))
推荐阅读
- grafana - Grafana 在图例中显示所有过滤器
- delphi - 如何将表情符号放入 TButton 或 TBitBtn Caption
- github-actions - 如何忽略 GitHub 操作函数“hashFiles”中的 node_modules?
- python - 如何更改包含许多项目的列表中特定项目的值?
- postgresql - 如何在 PostgreSQL 中进行递归横向连接?
- spring-boot - 使用 Spring-data 进行 sl4j mongo 日志记录
- react-native - SyntaxError:意外的令牌类型
- awk - 如何在 awk 中使用一个文件,一个文件作为输入文件,一个文件作为搜索词
- visual-studio - 为什么 Visual Studio 不允许我构建我的 dll?
- python - 如何分别显示私人成员?