如何在 clojure 中为变量重新分配另一个值
How to reassign a variable another value in clojure
我正在为斐波那契数列做这个 Clojure 程序。
(def fibonacci []
(def a 0)
(def b 0)
(def c 1)
(def n (atom 0))
(while (<= @n 10)
(do
(def c (+ a b))
(def a b)
(def b c)
(println '(a b c))
)(swap! n inc)))
(fibonacci)
我收到这个错误:
CompilerException java.lang.RuntimeException: Too many arguments to def, compiling:(C:\Users\user\AppData\Local\Temp\form-init4960759414983563364.clj:1:1)
CompilerException java.lang.RuntimeException: Unable to resolve symbol: fibonacci in this context, compiling:(C:\Users\user\AppData\Local\Temp\form-init4960759414983563364.clj:13:1)
我不知道如何重新分配变量 a
、b
和 c
。也请提出程序中需要的任何更正。
如评论中所述,在命令式语言中,您通常
通过改变变量的值来解决这样的问题。但在一个功能
像 Clojure 这样的语言,重点是不变性、函数调用和
递归。虽然您可以找到解决方案
bindings,
set!之类的,不是样式
您应该在其中使用 Clojure 进行编程(至少对于此类问题)。
因此,迭代计算斐波那契数列的函数可能看起来像
像这样(另见
this section in SICP Distilled):
(defn fibonacci
[n]
(letfn [(fib-iter [a b count]
(if (= count 0)
b
(fib-iter (+ a b) a (- count 1))))]
(fib-iter 1 0 n)))
fib-iter
是一个局部函数并递归调用自身(通过
tail call recursion)。但正如所写
here:
Since Clojure uses the Java calling conventions, it cannot, and does not, make
the same tail call optimization guarantees. Instead, it provides the recur
special operator, which does constant-space recursive looping by rebinding and
jumping to the nearest enclosing loop or function frame.
因此,您可以将尾部调用中的 fib-iter
替换为
recur 获得一个
迭代过程或者你可以使用 loop form
这稍微简化了代码:
(defn fibonacci
[n]
(loop [a 1
b 0
count n]
(if (= count 0)
b
(recur (+ a b) a (- count 1)))))
首先,让您的代码运行起来。第一个def
,定义一个函数,应该是defn
:
(defn fibonacci []
(def a 0)
(def b 0)
(def c 1)
(def n (atom 0))
(while (<= @n 10)
(do
(def c (+ a b))
(def a b)
(def b c)
(println '(a b c))
)(swap! n inc)))
它编译。让我们试试看:
> (fibonacci)
(a b c)
(a b c)
...
(a b c)
=> nil
不是你想要的。问题是 (a b c)
前面的引号,其中 returns 列表的元素未计算。我们必须去掉引号,但我们不希望 a
被视为运算符。所以输入 list
:
(defn fibonacci []
(def a 0)
(def b 0)
(def c 1)
(def n (atom 0))
(while (<= @n 10)
(do
(def c (+ a b))
(def a b)
(def b c)
(println (list a b c))
)(swap! n inc)))
让我们运行它:
> (fibonacci)
(0 0 0)
(0 0 0)
...
(0 0 0)
=> nil
好吧,我们得到了数字,尽管不是我们想要的。问题是第一个 (def c (+ a b))
抹掉了唯一的非零值。我们应该从 b
at 1
开始,暂时使用 c
即可:
(defn fibonacci []
(def a 0)
(def b 1)
(def n (atom 0))
(while (<= @n 10)
(do
(def c (+ a b))
(def a b)
(def b c)
(println (list a b c))
)(swap! n inc)))
现在...
> (fibonacci)
(1 1 1)
(1 2 2)
(2 3 3)
(3 5 5)
(5 8 8)
(8 13 13)
(13 21 21)
(21 34 34)
(34 55 55)
(55 89 89)
(89 144 144)
=> nil
万岁!
但是我们可以看到b
和c
是一样的,只是预测下一个a
.
有一个更大的问题。使用可变变量不是 Clojure 的方式。函数打印它计算的内容也不是惯用的:最好将结果开发为一个序列,我们可以用它来做我们喜欢的事情。
我们可以这样定义整个斐波那契数列:
(defn fibonacci []
(map second
(iterate
(fn [[a b]] [b (+ a b)])
[0 1])))
我们想怎么发展就怎么发展:
(take 10 (fibonacci))
=> (1 1 2 3 5 8 13 21 34 55)
我正在为斐波那契数列做这个 Clojure 程序。
(def fibonacci []
(def a 0)
(def b 0)
(def c 1)
(def n (atom 0))
(while (<= @n 10)
(do
(def c (+ a b))
(def a b)
(def b c)
(println '(a b c))
)(swap! n inc)))
(fibonacci)
我收到这个错误:
CompilerException java.lang.RuntimeException: Too many arguments to def, compiling:(C:\Users\user\AppData\Local\Temp\form-init4960759414983563364.clj:1:1)
CompilerException java.lang.RuntimeException: Unable to resolve symbol: fibonacci in this context, compiling:(C:\Users\user\AppData\Local\Temp\form-init4960759414983563364.clj:13:1)
我不知道如何重新分配变量 a
、b
和 c
。也请提出程序中需要的任何更正。
如评论中所述,在命令式语言中,您通常 通过改变变量的值来解决这样的问题。但在一个功能 像 Clojure 这样的语言,重点是不变性、函数调用和 递归。虽然您可以找到解决方案 bindings, set!之类的,不是样式 您应该在其中使用 Clojure 进行编程(至少对于此类问题)。
因此,迭代计算斐波那契数列的函数可能看起来像 像这样(另见 this section in SICP Distilled):
(defn fibonacci
[n]
(letfn [(fib-iter [a b count]
(if (= count 0)
b
(fib-iter (+ a b) a (- count 1))))]
(fib-iter 1 0 n)))
fib-iter
是一个局部函数并递归调用自身(通过
tail call recursion)。但正如所写
here:
Since Clojure uses the Java calling conventions, it cannot, and does not, make the same tail call optimization guarantees. Instead, it provides the recur special operator, which does constant-space recursive looping by rebinding and jumping to the nearest enclosing loop or function frame.
因此,您可以将尾部调用中的 fib-iter
替换为
recur 获得一个
迭代过程或者你可以使用 loop form
这稍微简化了代码:
(defn fibonacci
[n]
(loop [a 1
b 0
count n]
(if (= count 0)
b
(recur (+ a b) a (- count 1)))))
首先,让您的代码运行起来。第一个def
,定义一个函数,应该是defn
:
(defn fibonacci []
(def a 0)
(def b 0)
(def c 1)
(def n (atom 0))
(while (<= @n 10)
(do
(def c (+ a b))
(def a b)
(def b c)
(println '(a b c))
)(swap! n inc)))
它编译。让我们试试看:
> (fibonacci)
(a b c)
(a b c)
...
(a b c)
=> nil
不是你想要的。问题是 (a b c)
前面的引号,其中 returns 列表的元素未计算。我们必须去掉引号,但我们不希望 a
被视为运算符。所以输入 list
:
(defn fibonacci []
(def a 0)
(def b 0)
(def c 1)
(def n (atom 0))
(while (<= @n 10)
(do
(def c (+ a b))
(def a b)
(def b c)
(println (list a b c))
)(swap! n inc)))
让我们运行它:
> (fibonacci)
(0 0 0)
(0 0 0)
...
(0 0 0)
=> nil
好吧,我们得到了数字,尽管不是我们想要的。问题是第一个 (def c (+ a b))
抹掉了唯一的非零值。我们应该从 b
at 1
开始,暂时使用 c
即可:
(defn fibonacci []
(def a 0)
(def b 1)
(def n (atom 0))
(while (<= @n 10)
(do
(def c (+ a b))
(def a b)
(def b c)
(println (list a b c))
)(swap! n inc)))
现在...
> (fibonacci)
(1 1 1)
(1 2 2)
(2 3 3)
(3 5 5)
(5 8 8)
(8 13 13)
(13 21 21)
(21 34 34)
(34 55 55)
(55 89 89)
(89 144 144)
=> nil
万岁!
但是我们可以看到b
和c
是一样的,只是预测下一个a
.
有一个更大的问题。使用可变变量不是 Clojure 的方式。函数打印它计算的内容也不是惯用的:最好将结果开发为一个序列,我们可以用它来做我们喜欢的事情。
我们可以这样定义整个斐波那契数列:
(defn fibonacci []
(map second
(iterate
(fn [[a b]] [b (+ a b)])
[0 1])))
我们想怎么发展就怎么发展:
(take 10 (fibonacci))
=> (1 1 2 3 5 8 13 21 34 55)