【问题标题】:What is the correct term for the following functional programming pattern?以下函数式编程模式的正确术语是什么?
【发布时间】:2011-03-30 09:55:48
【问题描述】:

我听说它被称为 stream 被称为 infinite list,有时甚至被称为 lazy sequence em>

以下模式的正确术语是什么? (显示的 Clojure 代码)

(def first$ first)

(defn second$ [str]
  (cond
    (empty? str) ()
    true ((first (rest str)))))

(defn stream-builder [next_ n]
  (cons n (cons (fn [] (stream-builder next_ (next_ n))) ())))

(defn stream [str n]
  (cond
    (= 0 n) ()
    true (cons (first$ str) (stream (second$ str) (- n 1)))))

(def odd 
  (stream-builder (fn [n] 
        (+ 2 n))1))

(println (stream odd 23))

> (1 3 5 7 9 11 13 15 17 19 21 23 25 27 29 31 33 35 37 39 41 43 45)

【问题讨论】:

  • 我不确定你在问什么。看起来您已经为它找到了 3 个名称。在您看来,什么会使任何答案比这些同义词中的任何其他同义词更“正确”?

标签: functional-programming clojure lisp terminology sequence


【解决方案1】:

简短回答:stream-builder 返回一个函数,该函数返回一个无限序列/列表,必须“懒惰”地对其进行评估(因为您无法在有限时间内无限长地评估某事)。在 Clojure 世界中,您可能不应该将示例中的任何内容称为“流”,以避免与另一个概念混淆。

更长的答案:

编程语言中思想多样性的一个不幸的副作用是,我们经常使用相同的词来表示不同的含义。您提到的所有三个词(“Stream”、“infinite list”、“lazy sequence”)都指以串行方式处理元素,在 Clojure 中我们将这些词称为“Sequences”。但是,每个词所隐含的细微差别略有不同。

“流”通常是指一些元素序列,现在经常用于有限字符序列的上下文中。这些字符序列通常来自文件、网络源或 Unix 管道。

如果一个序列被定义为它有无限数量的元素,我们可以称它为无限序列。通常无限序列在内部表示为 linked list ,因此我们可以称这些为“无限列表”。不过,老实说,我更愿意在 Clojure 社区中听到“无限序列”这个词,因此我们不依赖于特定的实现。

最后,Clojure 中“惰性序列”的细微差别是指对“按需”发生的数据结构进行顺序评估的模式。换句话说,这里的重点是评估的惰性性质;序列中特定元素的值在您要求之前不会实际计算。

总之,在 Clojure 中你应该使用这些词:

  • “list”指的是具有链表实现的东西
  • “懒惰”指的是按需评估的事物
  • “infinite”指的是非有限大小的序列(因此必须是惰性的)
  • “流”指来自外部源的管道状(字符)序列

【讨论】:

    【解决方案2】:

    这不是你问题的答案,但为了编写“漂亮”的 clojure 代码,我想用你的例子指出一些事情。

    函数式风格的好处之一是能够将函数组合在一起。但是,如果您看一下您编写的函数,它们在不依赖其他地方提供的功能的情况下单独做的并不多。

    例如,stream-builder 只返回一个包含两个元素的 n 列表和一个处理伪递归的匿名函数。

    我的猜测是您尝试使用惰性序列,但这样做需要支持函数,这些函数知道实现细节以实现下一个元素,即streamsecond$。值得庆幸的是,您可以按如下方式完成它:

    (defn stream-builder [f x] ; f 是函数 arg 的惯用语 (lazy-seq ; n 是计数的惯用语,所以请改用 x (缺点 x (流构建器 f (f x)))))

    上面实际上会返回一个无限的值序列,所以我们需要拉出捆绑在stream中的限制行为:

    (defn limit [n coll] ; coll 是集合 arg 的惯用语 (lazy-seq ; 翻转顺序,在 seqs 上工作的 fns 通常把 seq 放在最后 (当(位置?n) (when-let [s (seq coll)] (缺点(第一个) (限制 (dec n) (下 s)))))))

    上面将懒惰地返回colln元素:

    用户=> (限制 5 (stream-builder inc 1)) (1 2 3 4 5)

    最后,每个函数都做好一件事,并且可以与其他函数组合:

    最后,您将odd 定义为奇数的惰性序列。危险在于序列在实现时会一直存在(这被称为“抓住序列的头部”)。这可能会不必要地占用多余的内存来保存已实现的每个元素,并防止垃圾收集。

    要解决这个问题,要么不定义惰性序列,要么用限制定义它,例如:

    (def 赔率 (limit 23 (stream-builder #(+ 2 %) 1)))

    为了将来参考,我们刚刚编写的内容在核心库中分别为iteratetake

    用户=>(取 5(迭代公司 1)) (1 2 3 4 5)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-12-27
      • 1970-01-01
      • 2011-02-09
      • 2015-07-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多