在Clojure中收集Lisp的函数

时间:2018-01-04 17:08:26

标签: clojure lisp

我在Clojure中定义了一个函数is-prime?,它返回一个数字是否为素数,并且我试图定义一个函数prime-seq,它返回两个数字之间的所有素数{{1} }和n

我已经在Common Lisp中创建了这个函数,因为我对它更熟悉,我正在尝试将代码转换为Clojure。但是,我找不到如何将Lisp中的m函数替换为Clojure。

这是我在Lisp中的collect函数:

prime-seq

这是我在Clojure中所做的尝试,但它不起作用:

 (defun prime-seq (i j) 
    (loop for x from i to j
                when (is-prime x)
                collect x
     )
 )

有什么想法吗?

2 个答案:

答案 0 :(得分:2)

我尝试使用for

(for [x (range n m) :when (is-prime? x)] x)

答案 1 :(得分:2)

Clojure中的

loop与CL loop不同。您可能需要for

(defn prime-seq [i j]
  (for [x (range i j)
        :when (is-prime x)]
    x))

基本上与说法相同:

(defn prime-seq [i j]
  (filter is-prime (range i j)))

可以使用->>宏编写以便于阅读:

(defn prime-seq [i j]
  (->> (range i j)
       (filter is-prime)))

但是,你可能真的想要一个所有质数的延迟序列,你可以用这样的东西写:

(defonce prime-seq
  (let [c (fn [m numbers] (filter #(-> % (mod m) (not= 0)) numbers))
        f (fn g [s]
            (when (seq s)
              (cons (first s)
                    (lazy-seq (g (c (first s) (next s)))))))]
    (f (iterate inc 2))))

延迟序列将缓存先前计算的结果,您可以使用take-whiledrop-while之类的内容来过滤序列。

此外,您可能不应该在函数调用中使用defdef用于定义var,它基本上是全局的。然后使用def更改该值完全销毁var并将其替换为另一个指向新状态的var。这是允许基于REPL的迭代开发的东西,不应该以这种方式真正使用。 Var用于将更改本地隔离到线程,并用作系统中函数和单例等全局事物的容器。如果您编写的算法需要本地可变状态,您可以使用瞬态或原子,并使用let定义对该算法的引用,但使用序列处理库或传感器更为惯用

循环更像是尾递归函数:

(defn prime-seq [i j]
  (let [l (transient [])]
    (loop [k i]
      (when (< k j)
        (when (is-prime k)
          (conj! l k))
        (recur (inc k))))
    (persistent! l)))

但应该严格考虑性能优化。使用瞬变的决定不应掉以轻心,通常最好先从功能更强的算法开始,进行基准测试并进行相应的优化。这是一种在没有可变状态的情况下编写相同内容的方法:

(defn prime-seq [i j]
  (loop [k i
         l []]
    (if (< k j) 
      (recur (inc k)
             (if (is-prime k)
               (conj l k)
               l))
      l)))