39

我在 Clojure 中有一个简单但令人沮丧的问题,我有一个函数(我们称之为 read-function),它可以从他的输入中找出用户想要做什么,然后调用另一个执行该操作的函数(我们称之为 action-function)。此操作函数在完成后调用读取函数,以便用户可以执行另一个任务。

现在我的问题是,如果我将 read-function 的代码放在 action-function 的代码之前,我会在 read-function 中得到一个错误,说它不知道 action-function 是什么(因为它的代码更进一步下),如果我做相反的事情,那么我显然会收到类似的错误,说无法解析读取功能等。

有没有简单的方法来解决这个问题?

实际代码:

(defn ajout [botin]
  (def botin botin)
  (readCmd botin)
)

(defn readCmd [botin]
  (println "Entrez une commande svp ")
  (def botin botin)
  (let [cmd (read-line)]
    (if (.equals cmd "a") ((println "Ajout 8o") (ajout botin))
      (if (.equals cmd "e") ((println "Elim 8o") (eliminer botin))
        (if (.equals cmd "i") ((println "Imprim 8o") (imprimer botin))
          ((println "Commande invalide, nous vous rapellons que les commandes possibles sont : ") (print-les-cmd) (readCmd))))))


)

像这样,我在 ajout 函数的 (readCmd botin) 行收到错误消息:无法解析符号:在此上下文中的 readCmd

如果我将这两个函数的代码以相反的顺序放置,我会收到一条错误消息:无法解析符号:在此上下文中的 ajout

4

4 回答 4

65

您可以在 Clojure 中使用前向声明,以便调用尚未定义的函数。

(declare readCmd)

应该管用!

在 Clojure 中,定义函数的顺序很重要,一个函数不能调用另一个尚未定义的函数(或任何其他函数)。这就是我们有前向声明的原因。

于 2009-07-13T10:47:16.967 回答
18

正如其他人已经回答的那样,您需要(声明 readCmd)来解决您的直接问题。

但是,这段代码仍然存在问题,因为它实际上使用相互递归 (readCmd -> ajout -> readCmd -> imprimer -> readCmd -> ...) 来实现迭代过程,这将消耗堆栈并且你会得到 ( on) 堆栈溢出。组织它的更好方法是使 readCmd tail 递归,并使其调用动作。当一个动作返回时, readCmd tail 递归地调用它自己。

还有这个代码片段:

((println "Ajout 8o") (ajout botin))

可能不是您想要做的:它将调用 println 并尝试将结果用作函数。改用“做”:

(do (println "Ajout 8o") (ajout botin))

您也可以考虑阅读有关 case 或 cond 的内容,它们将简化嵌套的 if。

您的代码的另一个奇怪之处是

(def botin botin)

它是关于什么的?

于 2009-07-20T11:48:22.657 回答
11

在代码的顶部放置:

(declare readCmd)
于 2009-07-12T21:12:12.920 回答
3

Clojure google group 上有一个关于这个的线程,它提供了一些有趣的考虑,特别是关于 declare 的使用如何绊倒生态系统中的一些工具:

线

当然,你可以争辩说好的工具应该适用于语言的所有结构:)

IMO,你有点习惯了自下而上的风格,只是反向阅读。这是一个不同的故事,你讲述的是你在哪里建立而不是分解它们。

当然,正如其他人所说,您可以转发声明

(declare my-function)
于 2015-08-15T16:07:48.407 回答