【问题标题】:Clojure constantly and map functionClojure 不断和地图功能
【发布时间】:2012-07-24 21:10:55
【问题描述】:

为什么会有这段 Clojure 代码:

user=> (map (constantly (println "Loop it.")) (range 0 3))

产生这个输出:

Loop it.
(nil nil nil)

我希望它会打印 3 次“循环它”作为对函数进行 3 次评估的副作用。

【问题讨论】:

    标签: clojure functional-programming


    【解决方案1】:

    constantly 不会多次评估其参数。它是一个函数,而不是宏,因此在 constantly 运行之前,该参数只被评估一次。 constantly 所做的只是它接受其(评估的)参数并返回一个函数,该函数在每次调用它时都返回给定的值(无需重新评估任何东西,因为正如我所说,在 constantly 甚至运行之前已经评估了参数) .

    如果您只想为范围内的每个元素调用(println "Loop it"),则应将其作为要映射的函数传入,而不是constantly。请注意,您实际上必须将其作为函数传递,而不是计算表达式。

    【讨论】:

    • 查看源代码。这看起来像个赢家。
    • 一直在尝试使用来避免显式传入我不需要的参数。不过会满足于此。
    • 请注意,如果您只想要副作用,您应该使用doseqdotimes。由于map 是惰性的,除非你用doalldorun 强制它,否则你不会得到你想要的结果。
    • @sepp2k 您对constantly 的描述有误。你描述repeatconstantly 返回一个函数,调用该函数时将返回提供给 constantly 的值。
    • @kotarak 抱歉。修好了。
    【解决方案2】:

    正如 sepp2k 正确指出的那样,constantly 是一个函数,所以它的参数只会被计算一次。

    实现您在这里所做的惯用方法是使用doseq

    (doseq [i (range 0 3)]
      (println "Loop it."))
    

    或者dotimes(在这种特殊情况下更简洁有效,因为您实际上并没有使用range产生的序列):

    (dotimes [i 3]
      (println "Loop it."))
    

    这两种解决方案都是非惰性的,如果您只是为副作用运行一些代码,这可能是您想要的。

    【讨论】:

      【解决方案3】:

      您可以通过使用 repeatedly 和 lambda 表达式获得接近您意图的行为。

      例如:

      (repeatedly 3 #(println "Loop it"))
      

      除非您在 REPL,否则它需要被 dorun 或类似名称包围。 repeatedly 很懒。

      【讨论】:

      • Lambda 无法编译,因为它想要使用我传递给它的参数。在这种情况下,我宁愿忽略这个论点。
      • 我添加了一个使用示例,与您的类似。
      • 哦,这更有意义。谢谢!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-08-11
      • 1970-01-01
      • 2018-01-15
      • 2014-11-29
      • 2014-10-30
      相关资源
      最近更新 更多