代码之家  ›  专栏  ›  技术社区  ›  hawkeye

以下函数式编程模式的正确术语是什么?

  •  10
  • hawkeye  · 技术社区  · 15 年前

    stream , 作为一个 infinite list , lazy sequence .

    (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)
    
    2 回复  |  直到 8 年前
        1
  •  14
  •   ivar    15 年前

    简短回答: stream-builder 返回一个函数,该函数返回一个无限序列/列表,该序列/列表必须“延迟”求值(因为不能在有限时间内无限长地求值)。在Clojure世界中,您可能不应该将示例中的任何东西都称为“streams”,以避免与另一个概念混淆。

    长答案:

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

    如果一个序列的定义方式是它有无限多的元素,我们可以称之为无限序列。通常无限序列在内部表示为 linked list

    最后,Clojure中“lazy sequence”的细微差别是指“按需”对数据结构进行顺序评估的模式。换句话说,这里的重点是 懒惰的 求值的性质;序列中某个特定元素的值直到您请求时才实际计算出来。

    总之,在Clojure中,您应该使用以下词语:

    • “无限”指的是不是有限大小的序列(因此必须是惰性的)
        2
  •  10
  •   Alex Taggart    15 年前

    函数式的好处之一是能够将函数组合在一起。但是如果你看一看你写的函数,如果不依赖其他地方提供的功能,它们就不能单独发挥作用。

    stream-builder 只返回一个包含两个元素的 n 以及处理伪递归的匿名函数。

    stream second$

    (defn stream-builder [f x] ; f is idiomatic for a function arg
      (lazy-seq                ; n is idiomatic for a count, so use x instead
        (cons x 
          (stream-builder f (f x)))))
    

    上面的内容实际上会返回一个无穷多的值序列,因此我们需要拉出捆绑在里面的限制行为 流动 :

    (defn limit [n coll] ; coll is idiomatic for a collection arg
      (lazy-seq          ; flipped order, fns that work on seqs usually take the seq last
        (when (pos? n)
          (when-let [s (seq coll)]
            (cons (first s) 
              (limit (dec n) (next s)))))))
    

    以上将 返回到 coll :

    user=> (limit 5 (stream-builder inc 1))
    (1 2 3 4 5)
    

    最后,每个函数都能很好地完成一件事,并且可以与其他函数组合:

    odd 是奇数整数的惰性序列。危险的是,当序列被实现的时候,它会粘在周围(这被称为“抓住序列的头部”)。这可能会不必要地占用多余的内存来保存所有实现的元素,并防止垃圾收集。

    要解决此问题,请不要定义延迟序列,或使用限制来定义它,例如:

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

    为了将来的参考,我们刚刚编写的内容可以在core lib中作为 iterate take ,分别是:

    user=> (take 5 (iterate inc 1))
    (1 2 3 4 5)