【问题标题】:Puzzled: Clojure for loop with :while -> unexpected behaviour?困惑:带有 :while -> 意外行为的 Clojure for 循环?
【发布时间】:2023-03-14 15:20:01
【问题描述】:

我一直在学习 Clojure,但对以下内容感到困惑:

user=> (for [a (range 1 4) b (range 1 4)] [a b])
([1 1] [1 2] [1 3] [2 1] [2 2] [2 3] [3 1] [3 2] [3 3]); _no surprise here_

让我们添加:while (not= a b),我希望看到一个空列表,因为如果条件为假,循环应该停止。在这种情况下,它是a=b=1 的第一项。让我们看看:

user=> (for [a (range 1 4) b (range 1 4) :while (not= a b) ] [a b])

([2 1] [3 1] [3 2]) ; _surprise!_

:while 更改为 :when 以过滤掉 (= a b)

user=> (for [a (range 1 4) b (range 1 4) :when (not= a b) ] [a b])
([1 2] [1 3] [2 1] [2 3] [3 1] [3 2]); _expected_

谁能解释为什么(for [ ... :while ..] ...) 会这样?

我在 OS X 上使用 Clojure 1.3。

感谢您并为缺少格式表示歉意。这是我在 StackOverflow 上的处女帖。

【问题讨论】:

    标签: clojure


    【解决方案1】:

    让我们看看每次迭代。

    a = 1
      b = 1 -> a == b, break because of while
    
    a = 2
      b = 1 -> a != b, print [2 1]
      b = 2 -> a == b, break because of while
    
    a = 3
      b = 1 -> a != b, print [3 1]
      b = 2 -> a != b, print [3 2]
      b = 3 -> a == b, break because of while
    

    【讨论】:

    • 谢谢你,尼基塔。因此,如果 :while 仅适用于内部循环,我如何使其也适用于外部循环?我遇到的问题是:(对于 [从 [:a :b :c :d :e :f] 到 [:a :b :c :d :e :f] :let [path (find-path a b)] :while 路径) 路径);当 path 为 nil 时,循环应该停止。
    • 对不起,我的意思是(对于 [从 [:a :b :c :d :e :f] 到 [:a :b :c :d :e :f] :let [path ( find-path from to)] :while path] path)
    • @jbear,我不知道 :( 可能你最好创建路径的惰性序列并在它们不为空时使用。我不确定 for 是惰性的。
    【解决方案2】:

    for 中的:while 条件仅终止最内层循环。我一直使用for,但:while 很少,以至于我从未意识到这一点;谢谢你的好问题!

    遗憾的是,我认为您能做的最好的事情就是在 for 周围包裹一个 take-while,因为您想要在输出序列上使用“全局”停止计数器,而不是在您的输入序列之一上使用停止计数器'正在迭代。例如:

    (->> (for [a (range 1 4)
               b (range 1 4)]
           [a b])
         (take-while (fn [[a b]] (not= a b))))
    
    ()
    

    【讨论】:

    • 为了清楚起见,:while 测试适用于紧接在它之前的序列,不一定是最内层循环。
    • 感谢您的澄清,亚历克斯。考虑到该语言的重要性,我不禁感到有点失望,因为其中一个基本构建块——列表理解——结果却是相当有限的。希望随着我学习的进步,在大家的大力帮助下,我会发现更多/更好的方法。
    • @jbear 实际上,这种方式的限制比另一种方式要少。这样,如果您想要“全局”行为,您可以轻松地将 for 表达式包装在 take-while 中。但是,如果“全局”行为是 for/:while 所做的,您将如何恢复当前的“中间”行为?你必须完全放弃for 并建立一个由地图、地图猫、过滤器、花时间组成的老鼠巢。
    • 感谢您富有洞察力的评论。我没有考虑过替代行为。现在这一切都说得通了:我缺乏理解,而不是对for/:while 设计的疏忽。
    猜你喜欢
    • 2020-03-07
    • 2020-12-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多