Algorithm 列出列表的笛卡尔积及其本身

Algorithm 列出列表的笛卡尔积及其本身,algorithm,function,clojure,Algorithm,Function,Clojure,所以我有一个完整的代码要解释,但这部分对我来说没有意义,有人能给我解释一下吗?我知道列表iter在您希望看到列表中的每个元素完成某些操作时使用,但我很难遵循此处的路径。让我们假设slist iter执行您解释为list iter的行为,即“当您希望看到列表中的每个元素完成某些操作时使用” 现在,我将向您展示另一种使用Clojure核心函数进行笛卡尔积的方法,这样我可以为您指出可能会让您困惑的关键元素 (defn slist笛卡尔[lst] (doseq[x lst y lst] (println

所以我有一个完整的代码要解释,但这部分对我来说没有意义,有人能给我解释一下吗?我知道列表iter在您希望看到列表中的每个元素完成某些操作时使用,但我很难遵循此处的路径。

让我们假设
slist iter
执行您解释为
list iter
的行为,即“当您希望看到列表中的每个元素完成某些操作时使用”

现在,我将向您展示另一种使用Clojure核心函数进行笛卡尔积的方法,这样我可以为您指出可能会让您困惑的关键元素

(defn slist笛卡尔[lst]
(doseq[x lst
y lst]
(println x y)))
这就是
doseq
所做的。你们可以读它,比如lst中的每个x,lst中的每个y,打印x和y

现在,这里的关键部分是,您正在为
x
y
重复
lst
。这样我们就得到了
lst
lst
的笛卡尔积

这正是您显示的代码所做的。它使用
lst
作为两个
slistiter
调用要处理的列表

要明白,每次从一开始就需要处理列表,以得到你想要的:笛卡尔积

现在,您可以通过doseq表达式和slist iter函数来实现这一点

可能您需要理解为什么可以slist iter的形式进行操作

这是可能的,因为
fn
创建了一个函数,并且该函数是“这意味着“它”可以访问创建函数时范围内的所有变量”

这意味着调用第一个
slist iter
时,正在使用
fn
创建的函数
slist cartesian
可以访问参数
lst
。让我们将该函数称为匿名函数

每当第一个
slist iter
开始处理
lst
的新元素时,将再次调用该匿名函数,但
lst
将与后者创建前者时接收和使用的
slist笛卡尔
相同

我希望这回答了你的问题


如果你还想对这个主题进行更多的思考和挖掘,还有另一种思考方法,那就是一步一步地构造函数

用你自己的话来说

(defn slist笛卡尔[lst]
(slist iter)
lst;;包含元素的列表
对列表中的元素执行的操作
))
要做的事情是一个函数,它接收1参数。该函数将被调用,作为参数传递列表的一个元素,列表中的所有元素一次传递一个元素

如果我们将函数设为
println
,它将多次调用它,列表中每个元素调用一次,并将该元素作为参数。这意味着它将打印整个列表,一次打印一项:

(defn slist-cartesian [lst] 
  (slist-iter
   lst
   (fn [x]
     (slist-iter
      lst
      (fn [y]
        (println x y))))))
当您需要向打印内容添加更多信息时会发生什么情况?您需要一个比简单的
println
更复杂的函数

让我们创建一个函数,该函数将为列表中的每个项目添加一个文本前缀并打印它们。让我们在文本
前面加上前缀“number:”
。因为我们有
slistiter
,我们只需要解决文本前缀为单个数字的问题,函数只有一个参数,因此它可以被
slistiter
使用,从而解决列表中所有元素的问题。让我们把这个解决方案变成一个函数:

(defn前缀文本编号和打印[x]
(打印号码:x)
现在,让我们使用它来构建一个函数,该函数为列表中的所有元素添加前缀
“number:”
,并打印它们。让我们调用该函数
为每个
添加文本编号前缀:

(每个[lst]的defn前缀文本编号)
(slist iter)
lst
前缀(文本编号和打印)
(在每个“(1 2 3)”前面加上文本编号)
;; 编号:1
;; 编号:2
;; 电话:3
酷。但是如果我们需要更改前缀的文本,会发生什么呢?这意味着需要通过为前缀添加一个参数来通用函数
前缀文本编号和打印。但这将使该函数对
slistiter
无效。然后呢

我们将要做的是创建一个广义函数,然后以某种方式从中导出一个精确时刻所需的特殊函数

(defn slist-cartesian [lst]
  (slist-iter 
   lst
   println
   ))

(slist-cartesian '(1 2 3))
;; 1
;; 2
;; 3
因此,对于即将推出的函数
为每个
添加前缀文本,我们将执行以下操作:

(为每个[prefix,x]定义前缀文本)
(slist iter)
lst
(以某种方式派生函数前缀文本和打印前缀));;注意
有许多方法可以当场创建函数。您已经在显示的代码中为此使用了一个工具。您正在使用函数
fn
就地构建函数。另一种方法是使用函数
partial
。让我们首先探索
部分
选项

为此,我将执行
为文本添加前缀并打印
,这与我对
为文本编号添加前缀并打印
所做的操作相反。我将专门研究它。我将根据
前缀文本和打印
定义
前缀文本编号和打印
。首先用手,然后用
partial

;;手工
(defn前缀文本编号和打印[x]
(前缀文本和打印“编号:”x)
;; 使用部分
(def前缀文本编号和打印)
(部分前缀文本和打印“编号:”)
两个定义产生相同的结果:一个函数。注意,最后一个使用
def
而不是
defn

使用partial的定义很简单
(defn prefix-text-and-print [prefix, x] ;; Generalized function
  (println prefix x))
(def print-2-lsts-combined [a-lst b-lst]
  (slist-iter
   b-lst
   (partial prefix-list-and-print a-lst)))
(print-2-lsts-combined '(1 2 3) '(10 20 30))
;; 1 10
;; 1 20
;; 1 30
;; 2 10
;; 2 20
;; 2 30
;; 3 10
;; 3 20
;; 3 30