【问题标题】:Map laziness in clojureclojure 中的映射惰性
【发布时间】:2011-11-25 00:12:31
【问题描述】:

我正在 Clojure 中构建一个简单的摇摆 GUI。我正在尝试通过在 let 的上下文中使用 map 将单个函数应用于多个 GUI 组件:

(map #(f % component4) [component1 component2 component3])

所有组件都在 let 中定义。

有问题的是,map 是惰性的,并且该操作不会应用于组件,但是,我可以通过将上述内容包装在“take”中来强制它。

有没有非懒惰的地图替代品?或者我应该以不同的方式解决这个问题?

编辑: 在日食中逆时针使用。我使用 REPL 中的 (use 'Lib :reload) 和编辑器中的 CTRL+Enter 得到了不同的结果。重新加载会启动 GUI,但会出现上述问题。在编辑器中使用 CTRL+Enter 时没有出现该问题,因此我认为我对问题的描述可能不准确。无论如何,在这种情况下,doseq 似乎是比 map 更好的选择。

【问题讨论】:

    标签: swing map clojure lazy-evaluation


    【解决方案1】:

    我质疑你的断言,即让 take 参与其中会产生任何影响。如果你将它包裹在 doalldorun 中,它会做你想做的事,但你应该考虑使用 doseq 而不是 map 来进行这种只有副作用的操作。

    注意

    最初作为对问题的评论发布;复制以响应大众需求。

    【讨论】:

    • 我不关注。如果你把所有的元素都拿走了,你不强迫实现它们吗?我并不是说 doall 等不是更好,但大概采取 3 也可以吗?
    • 啊!我从来不知道,但确实: (first (take 10000 (map #(do (Thread/sleep 10) %) (range)))) 返回非常快。
    • @AdrianMouat 它实际上实现了 32 个元素,因为 range 和 map 都是为了效率而分块的——所以它需要 0.32 秒。但(first (take 10000 (map #(do (Thread/sleep 10) %) (repeat 1)))) 确实在 0.01 秒内返回,如预期。
    • 我确实想知道为什么它超时(在 tryclj.com 上)具有更高的睡眠值。谢谢,今天早上我学到了很多:)
    【解决方案2】:

    doseq 可能是解决此问题的最佳方法。 doseq 大致相当于在许多其他语言中循环遍历集合的每个元素的“for-each”语句。保证不偷懒。

    (doseq 
      [comp [component1 component2 component3]]
      (f comp component4))
    

    一些一般性建议:

    • 当您想要一个序列作为输出时,使用 ma​​p 及其懒惰的朋友(包括 take、drop 等)
    • 当您对副作用更感兴趣时,请使用 doseqdoalldotimes

    【讨论】:

    • 经验法则:副作用?在名称中查找do
    【解决方案3】:

    将您的地图包裹在 doall 中将强制对其进行评估。或者更好的选择是doseq,它用于涉及副作用的事情。

    【讨论】:

    • 谢谢,效果很好。该语法也更适合我尝试做的事情。
    猜你喜欢
    • 2011-10-25
    • 2012-06-16
    • 1970-01-01
    • 1970-01-01
    • 2011-09-27
    • 1970-01-01
    • 2012-03-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多