【问题标题】:See if part of data is lazy in clojure查看clojure中是否有部分数据是惰性的
【发布时间】:2012-03-28 22:02:05
【问题描述】:

clojure 中是否有一个函数可以检查数据是否包含一些惰性部分?

背景:

我正在用 clojure 构建一个小型服务器。每个连接都有一个状态、一个输入流和一个输出流

服务器从输入流中读取一个字节,并根据该值调用几个函数之一(以状态以及输入和输出流作为参数)。这些函数可以决定从输入流中读取更多内容,向输出流写入回复,并返回一个状态。这部分循环。

只要状态不包含任何惰性部分,这一切都会正常工作。如果状态中有一些惰性部分,那么当它被评估时(稍后,在另一个函数期间),可能会开始从输入流读取并写入输出流。

所以基本上我想为所有这些函数添加一个后置条件,说明返回状态的任何部分都不能是惰性的。有没有检查惰性序列的函数。我认为检查状态本身是否是惰性序列很容易,但我想检查例如状态是否具有包含哈希映射的向量,其中一个值是惰性的。

【问题讨论】:

    标签: clojure lazy-evaluation lazy-sequences


    【解决方案1】:

    通过doall强制评估更容易确保它不是懒惰的

    几年前我在一个流处理加密应用程序中遇到了这个问题,并尝试了几种方法,直到我最终接受了我的懒惰方面并将输入流包装在一个延迟序列中,当输入流关闭时没有更多数据可用。有效地将关闭流的关注与对流包含的内容的关注分开。您正在跟踪的状态听起来比打开和关闭要复杂一些,尽管您可以用类似的方式将其分开。

    【讨论】:

    • 不幸的是,doall 不能递归工作:(count (doall [1 2 3 4 (range)])) 将返回 5,而不是堆栈/堆溢出。
    • 啊,在第二部分:将输入流包装在惰性序列中是我考虑过的,并且有效(尽管您松散了 java DataInputStream 之类的东西)。但是,对于输出流,这不起作用,这是您真正需要副作用的地方。
    • (count (map doall (filter seq?[1 2 3 4 (range)])))
    • 如果您需要进一步嵌套,请查看使用拉链递归遍历您的结构。
    • @Claude - 通常这就是您想要的。如果您希望 range 成为同一序列的一部分,那么您可以执行 (count (doall (concat [1 2 3 4] (range 10)))) (给出 14;并且您并不真正需要 doall,因为 count 将扩展...)
    【解决方案2】:

    您当然可以按照 Arther 明智的建议使用 doall 强制进行评估。

    但是我建议改用重构来解决真正的问题,即您的处理函数有副作用(从输入读取,写入到输出)。

    如果您执行以下操作,则可以将其转换为纯函数:

    • 将输入流包装为惰性序列
    • 使用 [输入序列状态] 作为处理函数的输入
    • 使用 [list-of-writes new-state rest-of-input-sequence] 作为输出,其中写入列表是随后需要写入输出流的任何内容

    如果你这样做,你的处理函数是纯粹的,你只需要在一个简单的循环中运行它(在每次迭代时将写入列表发送到输出流),直到所有输入都被消耗和/或其他一些已达到终止条件。

    【讨论】:

    • 任何碰上懒惰的东西都会变得懒惰:)
    • @Ankur - 这是真的(假设你不强制评估),但我认为最重要的一点是,如果你坚持纯函数,那么懒惰就无关紧要了。
    • 在过去一天左右的时间里,我对这个建议进行了很多思考。一方面我喜欢纯函数。然而,使用序列会消除(在我看来)代码的清洁度。如果我有一个流,我需要先读取一个长 (a),然后是一个字节 (b),然后是 (b) 多个整数,这将很容易做到(并且对于阅读代码的任何人来说都很容易理解) (let [a (.readInt i) b (.readByte i) c (repeatedly b #(.readInt i))] ...)。一个序列如何干净地做到这一点......
    • @Claude - 你肯定需要在某些时候编写这种代码代码,但我建议将它包装到 read-message 函数中。然后你可以(repeatedly read-message) 得到一个惰性的传入消息序列。这就是您想要处理的惰性输入序列(即您想要在稍高的抽象级别上操作)
    • 这看起来像是一个干净的解决方案,特别是如果您以某种标准格式(例如 google 协议缓冲区)包装您的消息。不过,您确实失去了一些灵活性;例如,您无法在收到完整消息之前开始处理消息(问题是您多久需要此功能......)。感谢您的见解!
    猜你喜欢
    • 2012-06-17
    • 2012-09-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-14
    • 1970-01-01
    相关资源
    最近更新 更多