【问题标题】:`for` as a function instead of a macro [duplicate]`for`作为函数而不是宏[重复]
【发布时间】:2020-08-03 05:19:33
【问题描述】:

我想要一个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


    【解决方案1】:

    我想你想映射输入序列的笛卡尔积,对吧?如果是这样,您可以使用 clojure.math.combinatorics 库中的 clojure.math.combinatorics/cartesian-product 函数创建笛卡尔积的惰性序列,然后对其进行映射。

    (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))
    

    【讨论】:

    • 这很棒。我不知道它叫什么。
    猜你喜欢
    • 1970-01-01
    • 2014-10-06
    • 1970-01-01
    • 2013-11-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多