【问题标题】:implementing foreach (doseq) in clojure在 clojure 中实现 foreach (doseq)
【发布时间】:2012-03-16 09:35:28
【问题描述】:

我正在研究 SICP - 一项练习是实施 foreach (doseq)。 这是一项学术练习。在clojure中,这是我想出的:

(defn for-each [proc, items]
  (if (empty? items) nil
      (do
        (proc (first items))
        (recur proc (rest items)))))

但是,我对do 是否作弊有点模糊,因为do 是clojure 中的一种特殊形式,我认为SICP 中还没有引入类似的东西。 还有更简约的答案吗?

这是另一个只在最后一个元素上执行 proc 的尝试:

(defn for-each-2 [proc, items]
  (let [f (first items)
        r (rest items)]
    (if (empty? r)
      (proc f)
      (recur proc r))))

【问题讨论】:

  • 你很好。 SICP在这里很棘手。请参阅以下脚注 3 的极小文本:mitpress.mit.edu/sicp/full-text/book/…。每当您在 SICP 中执行 cond 时,对于 cond 的每个子句,您都有一个隐含的 begin。 SICP 中的 begin 与 Clojure 中的 do 差不多。

标签: recursion clojure lisp scheme sicp


【解决方案1】:

使用doseq,一切就绪。例如:

(doseq [e '(1 2 3)]
       (prn e))

将打印:

1
2
3
nil

编辑:

如果您想手动实现for-each 并使用尽可能少的特殊形式,这是另一种选择,尽管它最终几乎和您的一样短:

(defn for-each [f l]
  (cond (empty? l) nil
        :else (do (f (first l)) 
                  (recur f (rest l)))))

有趣的是,同样的过程可以用 SICP 中使用的 Lisp 方言 Scheme 更简洁地编写:

(define (for-each f l)
  (cond ((null? l) null)
        (else (f (first l))
              (for-each f (rest l)))))

【讨论】:

  • 是的,我想用尽可能少的特殊形式来实现它。
  • @DustinGetz 我用另一个选项更新了我的答案,但实际上它已经尽可能短了
  • 不,至少在 Clojure 中你无法避免 do 表示需要按顺序执行多个语句
  • 啊。所以不同之处在于,在方案中,else 子句是“做”的表达式列表。 clojure 使这一点变得明确,因此需要对某种可以执行语句列表的特殊形式的依赖。谢谢!
【解决方案2】:

这是我的尝试。它只是在一个内部循环中执行函数。

(defn for-each [fun, xs]
  (loop [fun fun
         xs xs
         action nil]
    (if (first xs)
      (recur fun (rest xs) (fun (first xs)))
      xs)))

【讨论】:

  • 这很聪明——它利用了循环的括号部分是按顺序执行的绑定列表这一事实。现在我明白了,这与do 方法的复杂性相当。
  • 很高兴您发现它有帮助。我又想了想,决定action nil 没问题。
猜你喜欢
  • 2022-01-11
  • 1970-01-01
  • 1970-01-01
  • 2018-05-03
  • 2013-02-26
  • 2011-06-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多