【问题标题】:Two functions which call each other recursively递归调用的两个函数
【发布时间】:2013-08-25 02:22:06
【问题描述】:

是否可以在 clojure 中定义两个递归调用的函数?比如这对:

(defn a [x]
  (if (= 0 x) 0 (b (dec x))))

(defn b [x]
  (if (= 0 x) 0 (a (dec x))))

编译失败:

Unable to resolve symbol: b in this context

因为当我尝试在a 中调用它时,我还没有定义b。

例如,在 ruby​​ 中,这可以正常工作:

def a(x)
  x == 0 ? x : b(x-1)
end

def b(x)
  x == 0 ? x : a(x-1)
end

【问题讨论】:

    标签: clojure


    【解决方案1】:

    要么:

    (declare b) ... ;然后可以按原样使用其余代码

    或:

    (def mutual
     (letfn [(a [ ... ] ...)
             (b [ ... ] ...)]
      [a b]))
    
    (def a (first mutual))
    (def b (second mutual))
    

    【讨论】:

    • 有道理,猜想编译速度有一个折衷,它不能向前看函数定义。感谢此文档链接的已删除答案 (clojuredocs.org/clojure_core/clojure.core/declare)
    • 权衡的不是编译速度,而是捕获错误。当两个命名空间需要相互引用时,还有resolve函数。
    • 你有更多相关信息的链接吗?编译器忽略显式函数定义避免了哪些类型的错误?
    • 对不起,我错了,我在考虑代码,就像在 repl 中一次输入一个表单(其中前瞻是不可能的),而不是从文件中加载。该行为可能与使 repl 和 file 行为实际上相同有关。
    • 此外,您可以使用 clojure.repl/doc 宏获取任何函数、宏或特殊形式的文档 -- (doc declare) (doc letfn) (doc resolve) (clojure.repl 加载到 lein repl默认任务)
    【解决方案2】:

    根据您的代码执行情况,请记住您可能会遇到堆栈溢出异常。

    (clojure.core/trampoline) 函数发挥作用并发挥其魔力。

    蹦床可用于转换需要相互的算法 没有堆栈消耗的递归。使用提供的参数调用 f,如果 任何。如果 f 返回一个 fn,则不带参数调用该 fn,并且 继续重复,直到返回值不是一个fn,然后 返回那个非 fn 值。请注意,如果您想将 fn 作为 最终值,您必须将其包装在某种数据结构中并解包 蹦床回来后。

    【讨论】:

    猜你喜欢
    • 2021-04-15
    • 2021-11-24
    • 1970-01-01
    • 1970-01-01
    • 2020-06-18
    • 1970-01-01
    • 1970-01-01
    • 2012-06-24
    • 1970-01-01
    相关资源
    最近更新 更多