Clojure多重复杂

Tri*_*ase 2 recursion function clojure

我可能已经超越了自己,在学习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)
    )
  )
)
Run Code Online (Sandbox Code Playgroud)

Car*_*ate 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))))
Run Code Online (Sandbox Code Playgroud)

这很安全.你不使用时"花"一个堆栈帧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)))))
Run Code Online (Sandbox Code Playgroud)