我正在尝试使用Clojure中的流创建sqrt函数。为此,我需要在函数内部定义流并返回它。问题在于流是根据自身定义的。因此,不可能使用let,而使用def是伪造的,因为它会影响全局范围。有什么方法可以在不影响全局范围的函数内使用def进行模拟?
Locale locale;
locale.getLanguage()
Locale locales = LocaleContextHolder.getLocale();
locales.getLanguage();
我不希望sqrt-stream创建全局猜测流。
答案 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-car
是first
的同义词stream-cdr
是rest
的同义词。类似地,您的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以前倾向于使用的序列函数的复制。