如何从嵌套剂量中脱颖而出

时间:2010-05-15 22:09:12

标签: clojure

我对嵌套剂量q循环有疑问。在start函数中,一旦我找到答案,我将atom设置为true,以便外部循环验证:while失败。然而,似乎它没有打破它,循环继续前进。怎么了?

我也对atom,refs,agents的使用感到困惑(为什么当更新函数的机制几乎相同时它们有不同的名称?)等。 在这种情况下使用原子作为旗帜是否可以?显然我需要一个像对象这样的变量来存储状态。

(def pentagonal-list (map (fn [a] (/ (* a (dec (* 3 a))) 2)) (iterate inc 1)))


(def found (atom false))


(defn pentagonal? [a]
  (let [y (/ (inc (Math/sqrt (inc (* 24 a)))) 6)
        x (mod (* 10 y) 10)]
  (if (zero? x)
    true
    false)))


(defn both-pent? [a b]
  (let [sum (+ b a)
       diff (- a b)]
    (if (and (pentagonal? sum) (pentagonal? diff))
        true
        false)))

(defn start []
 (doseq [x pentagonal-list :while (false? @found)]
  (doseq [y pentagonal-list :while (<= y x)]
       (if (both-pent? x y)
           (do
            (reset! found true)
             (println (- x y)))))))

1 个答案:

答案 0 :(得分:13)

即使原子设置为true,您的版本也无法停止运行,直到内部doseq完成(直到y&gt; x)。一旦内循环结束,它将终止外循环。当我运行它时它最终会终止。不确定你在看什么。

您不需要两个doseq来执行此操作。一个doseq可以同时处理两个seq。

user> (doseq [x (range 0 2) y (range 3 6)] (prn [x y]))
[0 3]
[0 4]
[0 5]
[1 3]
[1 4]
[1 5]

for的情况也是如此。)除了throw / catch之外,没有“突破”我所知的嵌套剂量的机制,但这不是-idiomatic。尽管如此,你根本不需要原子或doseq

(def answers (filter (fn [[x y]] (both-pent? x y))
                     (for [x pentagonal-list
                           y pentagonal-list :while (<= y x)]
                       [x y])))

您的代码风格非常重要。 “遍历这些列表,然后测试值,然后打印一些内容,然后停止循环。”在Clojure中使用原子进行控制并不是很惯用。

更实用的方法是采用seq(五边形列表)并将其包装在将其转换为其他seq的函数中,直到获得一个能够提供所需内容的seq。首先,我使用for将此seqs的两个副本转换为一对seq,其中y <= x。然后我使用filter将该seq转换为过滤掉我们不关心的值的那个。

filterfor是懒惰的,所以一旦找到first有效值,这将停止运行,如果你想要的话。这将返回您想要的两个数字,然后您可以减去它们。

(apply - (first answers))

或者您可以在另一个map中进一步包装该函数,以便为您计算差异。

(def answers2 (map #(apply - %) answers))
(first answers2)

以这种方式进行功能编程有一些优点。 seq被缓存(如果你像我一样按住头部),所以一旦计算出一个值,它就会记住它,然后你可以立即访问它。如果没有重置原子,你的版本将无法再次运行,然后必须重新计算所有内容。使用我的版本,您可以(take 5 answers)获取前5个结果,或者根据结果映射以执行其他操作(如果需要)。您可以doseq覆盖它并打印值。等等。

我确信还有其他(可能更好)的方法可以在不使用原子的情况下完成此操作。你通常应该避免改变引用,除非在Clojure中100%是必需的。

改变原子/ agent / refs的函数名称可能不同,可能是因为它们的机制不同。参考是通过交易同步和协调的。代理是异步的。原子同步且不协调。它们都是“改变引用”,并且可能某种超级函数或宏可以将它们全部包含在一个名称中,但这会掩盖它们在引擎盖下做的截然不同的事实。完全解释差异可能超出了SO职位的解释范围,但http://clojure.org完全解释了差异的所有细微差别。