【问题标题】:Newbie: "for" loops in functions behave in unexpected ways新手:函数中的“for”循环以意想不到的方式表现
【发布时间】:2013-11-07 22:22:56
【问题描述】:

我已经用 Java 和 Perl 开发了很长时间,但我想学习一些新的东西,所以我开始研究 clojure。我尝试的第一件事是河内塔谜题的解决方案,但我的漂亮打印功能出现了奇怪的行为。基本上,当我使用 'lein run' 运行它时,我的 for 循环永远不会进入,但当我从 repl 运行它时,它似乎工作正常。这是一个精简的示例:

(ns test-app.core
  (:gen-class))

(defn for-print
  "Print the same thing 3 times"
  [ p-string ]
  (println (str "Checkpoint: " p-string))
  (for
    [x [1 2 3]]
    (printf "FOR: %s\n" p-string)
))


(defn -main
  "I don't do a whole lot ... yet."
  [& args]
  (for-print "Haldo wurld!"))

当我使用“lein run”运行它时,我只能看到“检查点”println 的输出。如果我删除那条线,我根本就没有输出。但是,如果我运行 'lein repl' 然后键入 (-main) 它会按预期打印字符串 3 次:

test-app.core=> (-main)
Checkpoint: Haldo wurld!
(FOR: Haldo wurld!
FOR: Haldo wurld!
FOR: Haldo wurld!
nil nil nil)
test-app.core=> 

这里发生了什么?我有一种感觉,我正在以错误的方式处理这个问题,试图利用我过去的 Perl/Java 心态来编写 clojure。将同一任务运行一定次数的惯用方式是什么?

【问题讨论】:

  • 感谢您的回答。这让我明白了很多。

标签: clojure leiningen


【解决方案1】:

for 循环返回一个惰性序列,该序列仅在需要时进行评估。

当您在repl 中运行程序时,会实现 for 结果,以便在屏幕上显示结果。

但是当您使用lein run 运行时,结果从未使用过,因此无法实现集合。

你有几个选择:

1) 在for 循环外使用doall 强制实现惰性序列

例如:

(defn for-print
 "Print the same thing 3 times"
 [ p-string ]
 (println (str "Checkpoint: " p-string))
 (doall (for
    [x [1 2 3]]
    (printf "FOR: %s\n" p-string))))

2) 因为你只是打印一个副作用而不是真正创建一个集合,你可以使用doseq.

例如:

  (defn for-print
  "Print the same thing 3 times"
  [ p-string ]
  (println (str "Checkpoint: " p-string))
  (doseq [x [1 2 3]]
   (printf "FOR: %s\n" p-string)))

【讨论】:

    【解决方案2】:

    Clojure for 不是命令式循环(你应该完全避免考虑 Clojure 中的循环),它是一个列表推导式,它返回惰性序列。它用于创建序列,而不是用于打印任何内容。你可以意识到这一点,并让它发挥作用,但这是不好的方式。

    正如 Guillermo 所说,您正在寻找 doseq 宏,它是为副作用而设计的。在您的特定情况下,它可能是最惯用的 Clojure。

    在我看来,与 Clojure 中的命令式循环结构最相似的是尾递归,它是由循环/递归制成的。它仍然是 Clojure 中相当低级的构造,当然不应该以命令式循环的方式使用。更好地了解函数式编程原则以及 Clojure 核心函数。试图将 Java/Perl 思维转移到 Clojure 可能会伤害您。

    【讨论】:

      【解决方案3】:

      其他答案正确,并提供详细信息。我想添加一些可能有帮助的更高级别的说明。在大多数语言中,“for”的意思是“对于这样的和条件,执行这样的动作(可以是任意类型,包括副作用)。”这种事情可以在 Clojure 中完成,而且我见过有经验的 Clojure 程序员在它有用和方便的时候会这样做。但是,使用具有副作用的循环通常会违背语言的优势。所以在 Clojure 中,“for”这个词在大多数语言中都有不同的含义:生成(惰性)序列。它的意思是“对于这些输入,何时/何时/等。它们满足这样那样的条件,然后临时绑定到这些变量,通过以这样那样的方式处理每组值来生成(惰性)序列。”

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-12-27
        • 1970-01-01
        • 2017-07-04
        • 2019-04-05
        • 2010-09-10
        • 2014-01-19
        • 2013-10-20
        • 1970-01-01
        相关资源
        最近更新 更多