是否可以在clojure的函数内部使用def进行递归定义?

时间:2019-06-02 01:07:16

标签: clojure

我正在尝试使用Clojure中的流创建sqrt函数。为此,我需要在函数内部定义流并返回它。问题在于流是根据自身定义的。因此,不可能使用let,而使用def是伪造的,因为它会影响全局范围。有什么方法可以在不影响全局范围的函数内使用def进行模拟?

Locale locale;
locale.getLanguage()

Locale locales = LocaleContextHolder.getLocale();
locales.getLanguage();

我不希望sqrt-stream创建全局猜测流。

2 个答案:

答案 0 :(得分:1)

我不得不承认,我不完全了解您的大多数代码的意图。因此,我很难对其进行更改以显示如何进行改进。

我可以建议的是iterate。它反复将函数应用于初始值,并返回结果的无限懒惰列表。这与原始代码具有相同的效果,但是完全依赖于core构造:

(defn average [a b]
  (/ (+ a b) 2.0))

(defn sqrt-improve [guess x]
  (average guess (/ x guess)))

(defn sqrt-stream [n]
  (iterate #(sqrt-improve % n) ; Apply this function over and over again
           1.0)) ; The initial value to iterate over

然后,像这样使用它:

(->> (sqrt-stream 10)
     (take 10))

=>
(1.0
 5.5
 3.659090909090909
 3.196005081874647
 3.16245562280389
 3.162277665175675
 3.162277660168379
 3.162277660168379
 3.162277660168379
 3.162277660168379)

通过获取尽可能多的结果以获得所需的准确性,然后获取最终的{last)值,您可以得出最终的答案:

(->> (sqrt-stream 10)
     (take 100)
     (last))

=> 3.162277660168379

答案 1 :(得分:1)

我刚注意到@Carciginate在发布以下答案之前约十二小时,在接受的答案后附加了基于iterate的解决方案。


无需设置特殊功能来操纵流。 standard sequence functions旨在处理符合序列接口的任何内容。

您的定义

(defn stream-car [stream] (first stream))
(defn stream-cdr [stream] (rest stream))

...可以更简单地表示为

(def stream-car first)
(def stream-cdr rest)

换句话说

  • stream-carfirst的同义词
  • stream-cdrrest的同义词。

类似地,您的cons-stream本质上是复制旧的lazy-cons,现在已不推荐使用。

您的stream-map函数没有为标准map添加任何东西,该标准已经很懒了。还错误地假设只有第一个序列可能会枯竭。

无论如何,您在这里不需要map。更合适的是iterate,可以将其定义为

(defn iterate [f x]
  (lazy-seq (cons x (iterate f (f x)))))

然后我们可以将您的sqrt-stream定义为

(defn sqrt-stream [x]
  (iterate
    (fn [guess] (sqrt-improve guess x))
    1.0))

例如

=> (take 10 (sqrt-stream 10))
(1.0 5.5 3.659090909090909 3.196005081874647 3.16245562280389 
 3.162277665175675 3.162277660168379 3.162277660168379 
 3.162277660168379 3.162277660168379)

有些问题会扩展Clojure的序列表,但这不是问题之一。

很抱歉,它看起来如此消极,但是在设计Clojure时已经考虑了很多想法,以避免某些Lisps以前倾向于使用的序列函数的复制。