【问题标题】:Order of code in ClojureClojure 中的代码顺序
【发布时间】:2010-11-10 03:37:26
【问题描述】:

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

现在我的问题是,如果我将 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 in this context

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

【问题讨论】:

  • 您能否发布一个简单的代码示例来说明什么不起作用。这将有助于追查问题。
  • 当然----代码开始---- (defn add [book] (def book-in-function book) (readCmd book-in-function) ) (defn readCmd [book] (println "Enter cmd") (def book-in-function book) (let [cmd (read-line)] (if (.equals cmd "add") ((println "Adding") (add book-in-function )) (println "Dont know")) ) ) ---代码结束---如果我这样写,我会得到 Unable to resolve symbol: readCmd in this context 在 add 中 read-cmd 调用的行函数如果我将这两个函数以相反的顺序放置,我会得到类似的错误,但对于 read-cmd 函数中的 add 函数
  • 我在看到评论的样子后编辑了原始帖子:)
  • 赞成,因为我知道将来人们会在谷歌上搜索这个!好问题!

标签: clojure


【解决方案1】:

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

(declare readCmd)

应该可以!

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

【讨论】:

  • @wrongusername 和 Pascal/Modula-2/Oberon 单通道编译器。再加上改变...Forward declaration
  • 这是我编写 Clojure 时最糟糕的事情之一。我喜欢这种语言,但似乎这增加了不必要的 boolerplate。编译器可以隐式执行此操作。
  • 好吧,不得不这样做通常是一种很臭的代码味道,所以我很满意。
  • 增加了问题的复杂性,该问题可能无需前向声明即可以更简单的方式解决。
  • Rich Hickey 关于“为什么 clojure 编译器是单通的”:gist.github.com/reborg/…
【解决方案2】:

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

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

还有这个代码sn-p:

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

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

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

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

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

(def botin botin)

它是关于什么的?

【讨论】:

    【解决方案3】:

    在代码的顶部放置:

    (declare readCmd)
    

    【讨论】:

      【解决方案4】:

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

      thread

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

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

      当然,正如其他人所说,您可以使用

      转发声明
      (declare my-function)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-06-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-10-02
        相关资源
        最近更新 更多