我试图理解 Clojure 中这个笛卡尔积函数的语法

I'm trying to understand the syntax of this cartesian-product function in Clojure

这是笛卡尔积的一些代码,它可以是两个列表、两个向量或两者的任意数量的组合。我非常感谢对第二行、第四行和最后一行的帮助,解释每行在做什么

(defn cartesian-product ;function name definition
      ([] '(())) ;need help understanding this
      ([xs & more] ; at least two variables, xs is one of them
       (mapcat #(map (partial cons %) ;mapcat means a create a concatenated map of the following
                                      ;still trying to figure out partial, but cons takes a
                                      ;variable and puts it in front of a sequence
                     (apply cartesian-product more)) ; this is the sequence that is mapped
                                                     ; using (partial cons %)
               xs))) ;not sure what this is here for

这是一个重新设计的版本,说明了正在发生的事情(以及如何发生):

(ns tst.demo.core
  (:use demo.core tupelo.core tupelo.test))

;----------------------------------------------------------------------------
; Lesson: how map & mapcat work
(defn dup [x]
  "Return 2 of the arg in a vector"
  [x x])

(dotest
  (let [nums [0 1 2]]
    (is= (mapv inc nums) [1 2 3])
    (is= (mapv dup nums) [[0 0] ; like a matrix, 2-D
                          [1 1]
                          [2 2]])

    ; mapcat glues together the inner "row" vectors. So the result is 1-D instead of 2-D
    (is= (mapcat dup nums) [0 0 1 1 2 2])))

然后是修改后的代码

;----------------------------------------------------------------------------
(def empty-matrix [[]]) ; 0 rows, 0 cols

(defn cartesian-product ;function name definition
  "When called with 1 or more sequences, returns a list of all possible combinations
  of one item from each collection"
  ([]     ; if called with no args
   empty-matrix) ; return an empty matrix

  ; if called with 1 or more args,
  ([xs    ; first arg is named `xs` (i.e. plural for x values)
    & more] ; all other args are wrapped in a list named `more`
   (let [recursion-result (apply cartesian-product more) ; get cartesian prod of sequences 2..N
         inner-fn         (fn [arg] (map ; for each recursion-result
                                       (partial cons arg) ; glue arg to the front of it
                                       recursion-result))
         ; for each item in the first sequence (xs), glue to front of 
         ; each recursion result and then convert 2D->1D
         output           (mapcat inner-fn xs)]
     output)))

和一些单元测试来展示它的实际效果

(dotest
  (is= (cartesian-product [1 2 3]) [[1] [2] [3]])

  (is= (cartesian-product [1 2 3] [:a :b])
    [[1 :a]
     [1 :b]
     [2 :a]
     [2 :b]
     [3 :a]
     [3 :b]])

  (is= (cartesian-product [1 2 3] [:a :b] ["apple" "pea"])
    [[1 :a "apple"]
     [1 :a "pea"]
     [1 :b "apple"]
     [1 :b "pea"]
     [2 :a "apple"]
     [2 :a "pea"]
     [2 :b "apple"]
     [2 :b "pea"]
     [3 :a "apple"]
     [3 :a "pea"]
     [3 :b "apple"]
     [3 :b "pea"]]))