如何理解clojure的lazy-seq

2024-03-24

我正在尝试理解 Clojurelazy-seq运算符,以及惰性求值的一般概念。我知道这个概念背后的基本思想:表达式的求值被延迟,直到需要该值为止。

一般来说,这可以通过两种方式实现:

  • 在编译时使用宏或特殊形式;
  • 在运行时使用 lambda 函数

通过惰性求值技术,可以构建无限的数据结构,并在使用时进行求值。这些无限序列利用了 lambda、闭包和递归。在 clojure 中,这些无限数据结构是使用生成的lazy-seq and cons forms.

我想了解如何lazy-seq这很神奇吗?我知道这实际上是一个宏。考虑以下示例。

(defn rep [n]
  (lazy-seq (cons n (rep n))))

在这里,rep函数返回类型的延迟计算序列LazySeq,现在可以使用序列 API 对其进行转换和使用(从而进行评估)。该API提供的功能take, map, filter and reduce.

在展开的形式中,我们可以看到如何利用 lambda 来存储单元格的配方,而不立即对其进行评估。

(defn rep [n]
  (new clojure.lang.LazySeq (fn* [] (cons n (rep n))))) 
  • But 序列 API 实际如何工作LazySeq?
  • 下面的表达式实际发生了什么?

(reduce + (take 3 (map inc (rep 5))))

  • 中间操作如何map应用于序列,
  • 如何take限制序列 and
  • 终端如何操作reduce评估序列?

Also, 这些功能如何与Vector or a LazySeq?

Also, 是否可以生成嵌套的无限数据结构?: 列表包含列表,包含列表,包含列表...无限宽和深,评估为使用序列 API 消耗?

最后一个问题,这之间有什么实际区别吗

(defn rep [n]
  (lazy-seq (cons n (rep n))))

and this?

(defn rep [n]
  (cons n (lazy-seq (rep n))))

这是很多问题!

seq API 实际上如何与 LazySeq 配合使用?

如果你看一下LazySeq https://github.com/clojure/clojure/blob/206d94c9cfb01f981a157142929c9456c547d6ea/src/jvm/clojure/lang/LazySeq.java#L17的类源代码你会注意到它实现了ISeq https://github.com/clojure/clojure/blob/206d94c9cfb01f981a157142929c9456c547d6ea/src/jvm/clojure/lang/ISeq.java接口提供类似的方法first, more and next.

功能类似于map, take and filter是使用构建的lazy-seq(它们产生惰性序列)和first and rest(这又使用more)这就是他们如何使用惰性序列作为输入集合 - 通过使用first and more的实施LazySeq class.

下面的表达式实际上发生了什么?

(reduce + (take 3 (map inc (rep 5))))

关键是看如何LazySeq.first作品。它将调用包装的函数来获取并存储结果。在您的情况下,它将是以下代码:

(cons n (rep n))

因此它将是一个缺点单元格n作为它的值和另一个LazySeq实例(递归调用的结果rep) 就像它一样rest部分。它将成为这个的实现价值LazySeq对象和first将返回缓存的 cons 单元格的值。

你打电话时more在此之上,它将以同样的方式确保特定的价值LazySeq对象被实现(或重用记忆值)并调用more在其上(在本例中more在包含另一个的 cons 单元上LazySeq目的)。

一旦您获得另一个实例LazySeq对象与more当你打电话时,故事会重复first on it.

map and take将创建另一个lazy-seq那会打电话first and more集合的数量作为他们的参数传递(只是另一个惰性序列),所以这将是类似的故事。区别仅在于值如何传递到cons生成(例如调用f到通过以下方式获得的值first调用于LazySeq映射到的值map而不是像这样的原始值n在你的rep功能)。

With reduce它有点简单,因为它会使用loop with first and more迭代输入的惰性序列并应用归约函数来产生最终结果。

因为实际的实现看起来像map and take我鼓励您检查他们的源代码 - 它很容易理解。

seq API 如何处理不同的集合类型(例如惰性 seq 和持久向量)?

正如刚才提到的,map, take和其他功能的工作方式first and rest(提醒 -rest是在之上实现的more)。因此我们需要解释如何first and rest/more可以使用不同的集合类型:它们检查集合是否实现ISeq(然后它直接实现这些功能)或者他们尝试创建一个seq查看收集并整理其实施first and more.

是否可以生成嵌套的无限数据结构?

这绝对是可能的,但我不确定您想要获得的确切数据形状是什么。你的意思是得到一个惰性序列,它生成另一个序列作为它的值(而不是像这样的单个值n在你的rep)但将其作为平面序列返回?

(defn nested-cons [n]
  (lazy-seq (cons (repeat n n) (nested-cons (inc n)))))

(take 3 (nested-cons 1))

;; => ((1) (2 2) (3 3 3))

宁愿返回(1 2 2 3 3 3)?

对于这种情况你可以使用concat代替cons它创建两个或多个序列的惰性序列:

(defn nested-concat [n]
  (lazy-seq (concat (repeat n n) (nested-concat (inc n)))))

(take 6 (nested-concat 1))

;; => (1 2 2 3 3 3)

这有什么实际区别吗

(defn rep [n]
  (lazy-seq (cons n (rep n))))

和这个?

(defn rep [n]
  (cons n (lazy-seq (rep n))))

在这种特殊情况下并非如此。但是,如果 cons 单元格不包装原始值,而是包装计算它的函数调用的结果,则后一种形式并不是完全惰性的。例如:

(defn calculate-sth [n]
  (println "Calculating" n)
  n)

(defn rep1 [n]
  (lazy-seq (cons (calculate-sth n) (rep1 (inc n)))))

(defn rep2 [n]
  (cons (calculate-sth n) (lazy-seq (rep2 (inc n)))))

(take 0 (rep1 1))
;; => ()

(take 0 (rep2 1))
;; Prints: Calculating 1
;; => ()

因此,即使您可能不需要它,后一种形式也会评估其第一个元素。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何理解clojure的lazy-seq 的相关文章

  • 实体框架中的集合值参数?

    在我的上一个项目中 我决定使用实体框架 一切都很顺利 直到我尝试使用 在哪里 我收到一个错误 经过一番小小的搜索后我想出了这个帖子 https stackoverflow com questions 110314 linq to entit
  • 如何在 C++ 中创建多个向量的组合而无需硬编码循环?

    我有几个数据看起来像这样 Vector1 elements T C A Vector2 elements C G A Vector3 elements C G T up to VectorK elements Note also that
  • pmap 和线程数

    user gt Runtime getRuntime availableProcessors 2 并评估这个例子 http clojuredocs org clojure core clojure core pmap example 684
  • clojure 中的反转哈希映射

    我在 clojure 中有哈希映射 key1 value1 key2 value2 key3 value1 我需要将其转换为哈希映射 value1 key1 key3 value2 key2 有 Clojure 方法可以做到这一点吗 clo
  • 使用 Lambda/Template/SFINAE 自动保护 Trampoline 函数的 try/catch

    我有 100 个左右的蹦床函数 我想知道是否可以将每个都自动包装在 try catch 块中 请提前警告 这不是一个简单的问题 我将首先用 简化的 代码描述问题 然后尝试在下面尽力回答它 以便读者可以看到我所处的位置 Foo 有一个函数指针
  • Lambda 表达式中的 OrderBy 降序排列?

    我知道在正常的 Linq 语法中 orderby xxx descending很简单 但是如何在 Lambda 表达式中做到这一点呢 正如布兰农所说 这是OrderByDescending http msdn microsoft com e
  • 在 CakePHP 中向 Containable 添加条件

    以前我依赖递归 但我没有得到一些解决方案 然后我发现 Containable 对于这些问题工作得很好 我正在开发一个电影评论网站 我需要显示与特定类型相关的电影列表 我有下面的代码 example genre drama options a
  • 如何将 CORS 添加到 compojure-api 应用程序?

    如何将 CORS 添加到此代码片段 def app api swagger ui docs spec swagger json GET route a a GET route b b GET route c c 我想用https githu
  • 是否可以在更大的表达式中使用可选的 ifPresent() 来减轻对 get() 的调用?

    为了避免打电话get 这可能会引发异常 if a isPresent list add a get 我可以将此表达式替换为 a ifPresent list add 但是如果我需要执行更大的表达式 例如 if a isPresent b c
  • 传递 lambda 而不是接口

    我创建了一个界面 interface ProgressListener fun transferred bytesUploaded Long 但只能将其用作匿名类 而不能用作 lambda dataManager createAndSubm
  • Rust 中的基本树和指针

    我拥有一些 C 语言背景 尝试 学习 Rust 让我对自己的能力产生了质疑 我正在尝试找出如何更改拥有的指针 并且正在努力做到这一点 除了从额外的库中复制之外 我无法弄清楚二叉树上所需的递归 特别是 我不知道如何交换指针分支 虽然使用链表我
  • Array.Sort 使用重要的比较函数

    考虑以下代码C 5 0 简而言之 p 289 int numbers 1 2 3 4 5 Array Sort numbers x y gt x 2 y 2 0 x 2 1 1 1 这给出了结果 3 5 1 2 4 我在纸上尝试了这个并得到
  • 使用记忆化与不使用记忆化的递归

    我在学校做的作业是用递归计算加泰罗尼亚数 第一个没有记忆 def catalan rec n res 0 if n 0 return 1 else for i in range n res catalan rec i catalan rec
  • 如何获取数组中每个数字的阶乘值?

    我试图使用此方法获取数组中每个项目的阶乘值 但这仅输出一个值 任何人都可以帮助我找出我做错的地方吗 function mathh arr fn for i 1 i lt sizeof arr i arr2 arr2 i fn arr i r
  • LINQ 表达式的运行时创建

    假设我有这样的表达 int setsize 20 Expression
  • Reactjs中的递归函数

    我正在使用递归函数制作动态菜单 并且我已经制作了菜单并且它以正确的顺序显示 没有任何问题 我从以下位置收到菜单数据服务 js文件 您可以在下面的代码沙箱示例中看到整个工作应用程序 https codesandbox io s reactst
  • Clojure/Java:用于声音频谱分析的 Java 库? [关闭]

    Closed 此问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我正在寻找一个可以接受大量音频数据并返回给定频带内随时间变化的平均幅度的库 我已经在 comp dsp
  • 什么时候应该在 Clojure 中使用临时重新绑定特殊变量这一习惯用法?

    我注意到一些库 例如 clojure twitter 使用特殊的变量 用于动态绑定的变量 被星号包围 进行 oauth 身份验证 您将身份验证保存在 var 中 然后使用 with oauth myauth 我认为这是解决此类问题的一个非常
  • 如何在C++中构建复合for循环?

    是另一个fora 的计数器部分 第三部分 允许循环for环形 在我尝试优雅地编写代码来生成直角三角形 我写了这个 但它无法编译 include
  • LINQ 表达式树 Any() 位于Where() 内

    我正在尝试生成以下 LINQ 查询 Query the database for all AdAccountAlerts that haven t had notifications sent out Then get the entity

随机推荐