我知道使用Clojure解决排列问题的方法有很多种。我尝试了使用Core.Logic创建DCG(确定性子句语法),但是库中的DCG部分太过实验性,没有奏效。
在下面的代码中,我尝试了两种不同的方法。一种是列表推导式(已注释掉),类似于我在Haskell中解决这个问题的方式。
第二种方法使用MapCat将cons/first应用到每个递归调用permutation的返回值上。Remove item确保我不会在每个位置上重复使用相同的字母。
请问有人能解释一下列表推导式方法和MapCat方法的问题所在吗?在Haskell中,这种问题更容易理解——我是否忽略了Clojure的某些特点?
(defn remove-item [xs]
(remove #{(first xs)} xs )
)
(defn permutation [xs]
(if (= (count xs) 1)
xs
;(for [x xs y (permutation (remove-item xs))
; :let [z (map concat y)]]
; z)
(mapcat #(map cons first (permutation (remove-item %)) ) xs)
)
)
编辑:@thumbnail 已经在评论中解决了 MapCat 子问题
(partial cons x)
相当于#(cons x %)
或(fn [coll] (cons x coll))
。它将x
添加到其顺序参数中,map
通过s
中其他所有内容的perm
运行。封闭的mapcat
连接将此过程应用于将s
的每个元素视为序列的结果。因此,该函数接受一个set参数,但返回一个sequences序列。你应该知道 - 你基本上写了它 :)。 - Thumbnail(partial cons x)
的理解是正确的;而(disj s x)
则是将元素x
从集合s
中移除。顺便说一下,从你的代码中我可以感受到Haskell可以将非空集合解构为任意成员x
和剩余的集合xs
。在Clojure中尝试这样做,xs
将会是一个序列,而不是一个集合。你可以在ClojureDocs或Grimoire上查找标准函数,如partial
或conj
。最后,如果你想继续讨论,请遵循@amalloy的建议,在其他地方重新开启一个修订后的问题。 - Thumbnail