【问题标题】:Mutually recursive definitions in ClojureClojure 中的相互递归定义
【发布时间】:2011-03-13 21:46:13
【问题描述】:

如何在 Clojure 中进行相互递归定义?

这是 Scala 中使用递归定义查找素数的代码:

val odds: Stream[Int] = cons(3, odds map { _ + 2 })
val primes: Stream[Int] = cons(2, odds filter isPrime)
def primeDivisors(n: Int) =
    primes takeWhile { _ <= Math.ceil(Math.sqrt(n))} filter { n % _ == 0 }
def isPrime(n: Int) = primeDivisors(n) isEmpty

primes take 10

我把它翻译成 Clojure:

(def odds (iterate #(+ % 2) 3))
(def primes (cons 2 (filter is-prime odds)))
(defn prime-divisors [n]
    (filter #(zero? (mod n %)) 
        (take-while #(<= % (Math/ceil (Math/sqrt n))) 
            primes)))
(defn is-prime [n] (empty? (prime-divisors n)))

(take 10 primes)

但是在 Clojure REPL 中一一写出定义

java.lang.Exception: Unable to resolve symbol: is-prime in this context (NO_SOURCE_FILE:8)

在我写(def primes (cons 2 (filter is-prime odds)))之后。

有没有办法在 Clojure 中进行相互递归定义?

【问题讨论】:

  • 描述您尝试做的事情的术语是您尝试定义一对相互递归函数。我已编辑您的问题以使其更清楚。
  • @ken:感谢您更正术语。

标签: clojure definition recursion


【解决方案1】:

您需要在第一次引用它之前(declare is-prime)

这称为“前向声明”。

【讨论】:

  • 然后在输入(def primes (...)) 行后抛出java.lang.IllegalStateException: Var user/is-prime is unbound. (NO_SOURCE_FILE:3)
【解决方案2】:

格雷格的回答是正确的。但是,您必须重新排列您的代码:(def odds ...) (declare primes) (defn prime-divisors ...) (defn prime? ...) (def primes ...)。这应该可以解决问题。

问题是,素数的定义不是函数。它会立即执行,因此会尝试取消引用尚未绑定的 prime? Var。因此例外。重新安排应该解决这个问题。

(免责声明:我尚未检查代码是否适用于重新排列。)

我认为prime? 坏了。 (prime? 2) 应该给false,不是吗?

【讨论】:

  • 顺便说一句,还有 letfn 来定义相互递归的函数。
  • 2 是质数。它的唯一因素是 2(本身)和 1。
  • @Ken:我知道二是质数。而在上面prime-divisors(Math/ceil (Math/sqrt 2)) 给出2。所以来自primes2 通过take-whilefilter。因此在(is-prime 2)prime-divisors 的返回值不为空并且返回false。尔格:is-prime 坏了。我承认,我的表述有点不清楚。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-11
  • 1970-01-01
  • 1970-01-01
  • 2011-03-25
相关资源
最近更新 更多