我可能已经超越了自己,我在学习Clojure的第一天几乎没有参与其中的功能,但我认为我会雄心勃勃并且做一个递归函数来将浮动值转换为三元组。如果我按名称调用该函数而不是使用recur
,则效果很好。我理解问题是我只是recur
函数的1-arity版本,是否有一种标准的方法来处理多元函数的递归?我正在阅读的这本书似乎并没有涵盖它。
(defn float-to-ternary
([x k s]
(def a (int x))
(def r (- x a))
(def carry-string (str s (. Integer toString a 3)))
(cond
(== r 0) carry-string
(> k 20) carry-string
:default (recur (* 3 r) (inc k) carry-string)
)
)
([x]
(def a (int x))
(def r (- x a))
(def carry-string (str (. Integer toString a 3) "."))
(cond
(== r 0) (str (. Integer toString a 3))
:default (recur (* 3 r) 1 carry-string)
)
)
)
答案 0 :(得分:6)
如果您希望" recur
进入另一个arity",只需显式调用该函数而不是使用recur
:
(defn float-to-ternary
([x k s]
(def a (int x))
(def r (- x a))
(def carry-string (str s (. Integer toString a 3)))
(cond
(== r 0) carry-string
(> k 20) carry-string
:default (recur (* 3 r) (inc k) carry-string)))
([x]
(def a (int x))
(def r (- x a))
(def carry-string (str (. Integer toString a 3) "."))
(cond
(== r 0) (str (. Integer toString a 3))
:default (float-to-ternary (* 3 r) 1 carry-string))))
这是安全的。你"花费"当你不使用recur
时,一个堆栈框架,但其余的递归使用recur
,所以它很好。
我也有一些强制性的建议:
除非你有充分的理由,否则不要在函数内部使用def
。 def
创建的全局变量在函数返回时不会超出范围!
您不必使用cond
。
在第一个正文中,您要为前两个条件返回carry-string
。您可以只创建一个条件,将两者连接到or
,这样您就可以使用if
。
由于第二次使用只有两个结果,if
再次更有意义。
考虑到这一点,您的代码看起来更像是:
(defn float-to-ternary
([x k s]
(let [a (int x)
r (- x a)
carry-string (str s (. Integer toString a 3))]
(if (or (> k 20) (== r 0))
carry-string
(recur (* 3 r) (inc k) carry-string))))
([x]
(let [a (int x)
r (- x a)
carry-string (str (. Integer toString a 3) ".")]
(if (== r 0)
(str (. Integer toString a 3))
(float-to-ternary (* 3 r) 1 carry-string)))))