我在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
)
)
有什么想法吗?
答案 0 :(得分:2)
我尝试使用for
:
(for [x (range n m) :when (is-prime? x)] x)
答案 1 :(得分:2)
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-while
和drop-while
之类的内容来过滤序列。
此外,您可能不应该在函数调用中使用def
。 def
用于定义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)))