Clojure会反复出现 [英] Clojure recur with multi-arity

查看:50
本文介绍了Clojure会反复出现的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我可能会超越自我,在学习Clojure的第一天我几乎没有投入函数的使用,但是我认为我会很有野心,并且会做一个递归函数来将浮点值转换为三进制.如果我通过名称而不是使用 recur 来调用函数,则效果很好.我知道问题在于我只是对该函数的1-arity版本进行 recur ,是否存在处理多arar函数中的递归的标准方法?我正在阅读的书似乎没有涵盖这本书.

I'm probably getting ahead of myself, I'm barely into functions on my first day of learning Clojure, but I thought I would be ambitious and make a recursive function to convert floating values to ternary. If I call the function by name instead of using recur it works great. I understand the problem is that I am just recuring the 1-arity version of the function, is there a standard way to handle recursion in multi-arity functions? The book I'm reading doesn't seem to cover it.

(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)
    )
  )
)

推荐答案

如果您想" recur 放入另一个Arity",只需显式调用该函数即可,而不是使用 recur :

If you want to "recur into a different arity", just explicitly call the function instead of using 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 ,所以很好.

This is safe. You "spend" one stack frame when you don't use recur, but the rest of the recursions use recur, so it's fine.

我也有一些强制性建议:

I have some obligatory suggestions too though:

    除非您确实有充分的理由,否则请不要在函数内部使用
  • def . def 创建的全局变量在函数返回时不会超出范围!

  • Don't use def inside of functions unless you really have a good reason. def creates global variables that don't go out of scope when the function returns!

您无需使用 cond .

  • 在第一个正文中,您要为前两个条件返回 carry-string .您可以只创建一个条件,将两个条件与或关联,从而可以简单地使用 if .

  • In the first body, you want to return carry-string for the first two conditions. You could just make that one condition, connecting the two with an or, which lets you simply use if.

由于第二次使用只有两个结果,因此 if 再次有意义.

Since the second use only has two outcomes, if again makes more sense.

考虑到这一点,您的代码将更像:

Taking this into consideration, your code would look more like:

(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)))))

这篇关于Clojure会反复出现的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆