2024年Clojure状态调查!中分享您的想法。

欢迎!有关如何操作的更多信息,请参阅关于页面。

+1
Clojure
许多API(如Elasticsearch、GitHub、S3等)的某些部分
在用法中,最终以迭代方式使用。你做一次API调用
并使用结果进行另一项API调用,依此类推。这通常出现在
API具有某种分页结果的概念,你可以翻页,在HTTP API中非常
普遍。这似乎是一种非常常见的模式,如果Clojure有内置的

对该模式的支持那将非常棒。
你可能认为Clojure已经有了对该的支持,因为毕竟,Clojure有

`iterate`。实际上,`iterate`的文档字符串
明确说明您提供给它的函数必须是无副作用的。
我建议向clojure.core添加一个名为`unfold`的函数来支持这个用例。
`unfold`将返回ReduceInit的实现。`unfold`的名称与Haskell中相似

的函数名称相匹配(https://hackage.haskell.org/package/base-4.8.2.0/docs/Data-List.html#v:unfoldr
,同时也与一些现有的Clojure库中使用的函数的名称相匹配
https://github.com/amalloy/useful/blob/develop/src/flatland/useful/seq.clj#L128-L147)。
`unfold`在某种程度上类似于`take-while`和`iterate`的结合,
尽管`iterate`需要一个纯函数。另一种可能的解决方案是
不需要纯函数的`iterate`版本。
对于我为`unfold`构思的使用场景,非缓存可归约似乎是完美的。

但是,这会让那些喜欢序列的人无所适从,所以也许至少应该考虑
序列。
邮件列表上的讨论在这里
https://groups.google.com/forum/#!topic/clojure-dev/89RNvkLdYc4

你可能想与之交互的某些类型的不太真实的API可能看起来是这样的
(导入'(java.util.UUID))
((def uuids (重复1000 #(UUID/randomUUID)))
((def uuid-index (

  (循环[uuids uuids
         index  {}]

    (if (序列uuids)


      ( rejuvenate (rest uuids) (关联索引(第一uuids) (rest uuids)))

      index)))

  )
  ))
  
  
  
  

  
  
  
  
  
                        (从uuid-index列表中获取)}}
    {:page页面}
     :下一个(最后一页)}}


基于上述API,如果您有一个实现`unfold`的函数,该函数有一个决定何时展开的谓词,一个生产函数,给在序列中的值生成下一个值,以及一个初始值,您可以这样做


(= uuids (into [] (mapcat :page) (unfold :next (comp api :next) (api :start))))


结果将是true。

等价的take-while + iterate将类似于以下内容


;; 停止条件并不是严格相同的
(= uuids (into [] (mapcat :page) (take-while (comp seq :page) (iterate (comp api :next) (api :start)))))

14 答案

0
by

评论者:hiredman

我对这个API进行了两个修改,一个添加了上述讨论的unfold,另一个添加了ingeminate,它在某种程度上类似于iterate,但不受函数纯度限制,并且不返回一个seq。

0
by

评论者:gshayban

尽管语法比语义不重要,但我能否提议为此命名一个名为progression(展开)?Clojure的fold被称为reduce,所以unfold与Haskell太相似了。我还考虑过其他名称,包括evolve 和 derivations。

0
by

评论者:alexbiller

另一个选项是productions(类似于reductions)。

0
by

评论者:hiredman

Production听起来不错。 emanate也能工作,会靠近eduction。

0

评论者:gshayban

添加了一个使用 clojure.lang.{Seqable,IReduceInit} 实现的补丁。

生成测试断言序列和 reduce 两半是等效的。

测试断言基本功能,遵循 reduce,并实现 seq 实现的最大惰性。

文档字符串已润色,函数命名为 productions

0

评论者:hiredman

展开函数显然是 SRFI 1: Scheme 地区的列表库的一部分 http://srfi.schemers.org/srfi-1/srfi-1.html#FoldUnfoldMap

它们展开函数看起来是 take-while + iterate + map

0

评论者:gshayban

方案/implement 的主要区别
谓词反转(stop? 相对于 continue?)
方案有一个“映射函数”,用于从当前种子产生不同的值,而 Clojure 没有(但是有转换器)
方案有一个额外的可选参数来构建列表的尾部

我现在比较喜欢这个名字 {{successions}}。

0
_由 michalmarczyk 发布的评论_

我可以证实我在 Scheme 时代发现 {{unfold}} 非常有用。

在 Clojure 中,这种通用模式可以通过转置器以少量的按键成本表达


(def numbers (doall (range 1000)))

(defn api [list-from]
  (if list-from
    (let [page (vec
                   (                           take 10 (if (= :start list-from)
                                numbers
                                (drop list-from numbers))))]
      {:page page
       :next (some-> (last page) inc)})))

(= numbers
   (sequence (comp (take-while some?)
                          (mapcat :page))
             (iterate (comp api :next)
                      (                      api :start))))
;= true


这可能可以通过迭代器的 xform 启用版本来简化?


(defn iterate*
  ([f seed]
   (iterate f seed))
  ([xform f seed]
   (sequence xform (iterate f seed))))

(= numbers
   (iterate*
     (comp (take-while some?) (mapcat :page))
     (comp api :next)
     (api :start)))
;= true


诚然,这样需要更多的字符,但相当通用,在{{iterate}}中使用具有转换器启用的重载对我来说感觉非常自然。附加了一个简单的补丁,在{{clojure.core/iterate}}中实现此功能—I会查看{{clojure.lang.Iterate}},看看是否值得稍后实现直接支持,除非当然没有人需要这个。:-)
0

评论区:michalmarczyk

0001-CLJ-1906-transducer-enabled-iterate.patch 为{{iterate}}添加了一个三元重载,该重载委托给二元重载和{{sequence}}。

0

评论者:gshayban

关于重载{iterate}的一些不太令人满意的地方
1) iterate的文档字符串说{f必须没有副作用}
2) 终止项周围有样板和微妙之处。在这种情况下,最后API调用无条件地进行,导致一个额外的空/标记项,该项由take-while过滤。按目前的提案,谓词从内部控制迭代

0

评论者:gshayban

更新补丁以干净地应用于核心

0

评论者:gshayban

我不确定我现在是否仍然对这个表示肯定,我已经在邮件列表上提出了不同的方法 https://groups.google.com/d/msg/clojure-dev/89RNvkLdYc4/PAJh8gfmDAAJ

0

评论者:gshayban

我已经在考虑两个生成器函数,它们涵盖了包括上述在内的用例。

其中之一类似于Scheme的unfold,但在Clojure中更适合的一些差异。另一个函数接受具有副作用的生产器和哨兵值。

忽略命名并检查语义。 https://gist.github.com/ghadishayban/902373e247e920855139902912d237f0

0
by
参考资料:https://clojure.atlassian.net/browse/CLJ-1906(由hiredman报告)
...