我试图更多地了解Clojre,所以我决定在其中使用Runge Kutta集成商项目。但是,我在使用 let 语句的不可变特性时遇到了问题。我想在循环的每次迭代中评估8个变量,并使用它们来递归它直到我的循环结束。
我理解它的方式,因为我的 recur 位于 let 的范围内,我的k和l&s赢了&每次递归都会覆盖#39;我正在寻找一种更惯用的方式来通过我的集成商进行递归。
(loop [psin 0 Xin 1 xn dx] ;initial values
(if (> xn 1)
psin
(let [k1 (evalg xn psin) ;define 4 variables to calculate next step of Xi, psi
l1 (evalf xn Xin) ;evalf and evalg evaluate the functions as per Runge Kutta
k2 (evalg (+ (* 0.5 dx) xn) (+ (* 0.5 l1) psin))
l2 (evalf (+ (* 0.5 dx) xn) (+ (* 0.5 k1) Xin))
k3 (evalg (+ (* 0.5 dx) xn) (+ (* 0.5 l2) psin))
l3 (evalf (+ (* 0.5 dx) xn) (+ (* 0.5 k2) Xin))
k4 (evalg (+ dx xn) (+ l3 psin))
l4 (evalf (+ dx xn) (+ k3 Xin))]
(do
(let [Xinew (+ Xin (* (/ dx 6) (+ k1 k4 (* 2 k3) (* 2 k2))) )
psinew (+ psin (* (/ dx 6) (+ l1 l4 (* 2 l2) (* 2 l3) )))]
(println k1)
(recur psinew Xinew (+ dx xn)))))))
非常感谢!期待更多地了解clojure:)
答案 0 :(得分:0)
首先,正如@Alex已评论过,recur
会在k
的每次迭代中重新评估您的l
和loop
。 recur
指的是它的直接封闭函数或循环形式,在这种情况下是后者。
(println k1)
表明,当你围绕k1
进行迭代时,你正在寻找的是loop
的序列。
Clojure有一个 lazy sequence 的概念:一个潜在的无穷无尽的值序列
你应该
k1
s的惰性序列,并且 - 当我们在时
它 - evalg
制作evalf
和runge-kutta
个函数参数
功能我们可以使用lazy-seq
macro中包含的显式递归从头开始构建我们的延迟序列,但是有一个完整的序列函数库,其中一个通常表达你的意图。这些比你或我写的要快,但仍然比你的loop
慢得多。
这里有一个方便的功能是iterate
。我们可以系统地将您的loop
转换为使用它,如下所示:
loop
参数转换为单个destructured
向本地函数的向量参数(我称之为step
)。k1
。 map
以获取所需数据。 我最好的猜测如下:
(defn runge-kutta [evalg evalf dx]
(letfn [(step [[k1 psin Xin xn]]
(let [k1 (evalg xn psin)
l1 (evalf xn Xin)
k2 (evalg (+ (* 0.5 dx) xn) (+ (* 0.5 l1) psin))
l2 (evalf (+ (* 0.5 dx) xn) (+ (* 0.5 k1) Xin))
k3 (evalg (+ (* 0.5 dx) xn) (+ (* 0.5 l2) psin))
l3 (evalf (+ (* 0.5 dx) xn) (+ (* 0.5 k2) Xin))
k4 (evalg (+ dx xn) (+ l3 psin))
l4 (evalf (+ dx xn) (+ k3 Xin))
Xinew (+ Xin (* (/ dx 6) (+ k1 k4 (* 2 k3) (* 2 k2))) )
psinew (+ psin (* (/ dx 6) (+ l1 l4 (* 2 l2) (* 2 l3) )))]
[k1 psinew Xinew (+ dx xn)]))]
(map first (iterate step [nil 0 1 dx]))))
这可能是错误的,因为我在黑暗中摸索。
序列无穷无尽。你可以阻止它
xn
s,并将结果包装在take-while
中
或(long (/ dx))
,
虽然那里可能存在一次性错误。然后使用nth
或take
得到你想要的东西。告诉我们您是如何继续前进的。