【问题标题】:Correct usage of Clojure for macro正确使用 Clojure 进行宏
【发布时间】:2017-04-03 18:00:52
【问题描述】:

场上有 100 头水牛。 场上有 100 支拂尘。 每头站立的水牛吃 5 个拂子。 每头躺着的水牛吃 3 根拂子。 每 3 头老水牛吃 1 把。 场地上有多少头每种类型的水牛?

这是我用来解决这个问题的 Clojure 代码:

;; s: number of Standing buffaloes
;; l: number of Lying buffaloes
;; o: number of Old buffaloes
(for [s (range 101) l (range 101) o (range 101)
      :while (and 
              (= 100 (+ s l o)
               (= 100 (+ (* s 5) (* l 3) (* o 1/3)))))]
     [s l o])

我的代码不起作用。它应该返回每种类型的水牛数量,但我的代码只返回一个空序列。这似乎在逻辑上是不正确的。它有什么问题?

【问题讨论】:

  • 这太模糊了。不工作怎么办?你调试过吗?我也不知道 for 循环是否是这里工作的最佳工具。我认为您将 Clojure 的 for 循环与典型的命令式 for 循环混淆了。 Clojure 的 for 循环类似于 Python 的列表推导式。
  • 不起作用意味着:结果不正确。它应该返回有多少站立的、躺着的、老水牛在场上。但我的代码只返回一个空序列。这在逻辑上是不正确的。
  • 再一次,我认为 for 循环在这里不合适。当您想要生成某物的列表时,您可以使用 for 循环。这是它的主要用例。这听起来不像你想在这里做的。
  • 为什么不呢?我创建了一个可能的结果列表。例如,可以有 8 头站立的水牛或 10 或 11 头或其他。可能的结果是从 0 到 100。因此(范围 101)。
  • 你不想产生 3 个值吗?每种类型的水牛 1 个? loop/recur 模式似乎更合适。

标签: clojure


【解决方案1】:

2 个主要问题:

  • 通过使用:while,您告诉它一旦条件返回假就停止搜索。我相信您的意图是跳过条件为假的情况。为此,您使用:when

  • 您的条件有一个放错位置的大括号,导致您比较布尔值和数字,这总是错误的。在(= 100 (+ s l o) 的末尾添加一个大括号。如果您使用 Cursive 编写此代码,请确保垂直对齐表单,以便 Parinfer 可以为您管理大括号。

【讨论】:

    【解决方案2】:

    评论

    使用@Carcigentate's advice 改正,您可以改正这样:

    (for [s (range 101), l (range (- 101 s)) :let [o (- 100 s l)]
          :when (= 100 (+ (* s 5) (* l 3) (* o 1/3)))]
         [s l o])
    

    【讨论】:

    • 好建议。这应该会大大减少搜索时间。我现在真的很好奇改进是什么!也许我会通过 Criterium 运行这些。
    • @Carcigenicate 我将它设为 200 的因数:o 从 100 中取一个正确的值;并且天真的解决方案平均浪费了 s 的 100 个值的一半。
    • 47.955795 毫秒 vs 3.831184 毫秒。
    • 然后是 37.532622 ms vs 3.741322 ms 在另一个测试中。所以〜10-12x。
    • @Carcigenicate 算术必须相当昂贵。我只是在计算病例数。
    猜你喜欢
    • 2011-09-14
    • 1970-01-01
    • 2015-05-25
    • 2011-07-24
    • 1970-01-01
    • 1970-01-01
    • 2021-08-29
    • 2010-11-29
    • 1970-01-01
    相关资源
    最近更新 更多