【问题标题】:How do I serialize or save to a file a Thunk?如何将 Thunk 序列化或保存到文件中?
【发布时间】:2014-04-11 22:05:18
【问题描述】:

在 Haskell 中,您可以拥有无​​限列表,因为它不会完全计算它们,而是使用 thunk。我想知道是否有一种方法可以序列化或以其他方式将一段数据的 thunk 保存到文件中。例如,假设您有一个列表[0..]。然后你对其进行一些处理(我最感兴趣的是tail(:),但它也应该支持filtermap。)这是我正在寻找的一个例子。

serial::(SerialThunk a)=>a->serThunk
serialized = serial ([0..] :: [Int])
main=writeToFile "foo.txt" serialized

deserial::(SerialThunk a)=>serThunk->a
main=do
    deserialized <- readFromFile "foo.txt" :: IO [Int]
    print $ take 10 deserialized

【问题讨论】:

标签: haskell serialization thunk


【解决方案1】:

。没有办法在 Haskell 中序列化一个 thunk。一旦代码被编译,它通常被表示为程序集(例如,这就是 GHC 所做的)并且没有办法恢复函数的可序列化描述,更不用说你想要生成的函数和环境了。

是的。您可以构建自定义解决方案,例如描述和序列化 Haskell 表达式。反序列化和执行可以通过解释的方式进行(例如使用hint 包)。

也许。有人(你?)可以制作编译器或修改现有编译器,以与平台无关的方式维护更多信息,以便用户无需手动利用 hint 就可以序列化事物。我想象这是 Cloud Haskell(又名distributed-haskell)开发人员正在探索的一个项目。

为什么?我还想要一种序列化函数的能力,以便我可以灵活地传递闭包。但大多数时候,实际上并不需要这种灵活性,而是人们希望传递某些类型的计算,这些计算可以很容易地表示为自定义数据类型和解释函数。

【讨论】:

  • 对于我的原因,我只是想在数据库中保留一个可用 id 的列表,因此不是“自动递增 id”,而是“无限的 id 列表”。这也将使添加已删除的 ID 变得更容易。
  • 我发现 a discussion (laziness and serialization) 讨论了在发送之前可能不会强制 thunk。我还不明白这是否可以以某种方式用于发送 thunk。 " 不会为您进行 deepseq 评估。如果您希望代表您完成 deepseq 评估,请改用分布式进程平台中镜像的不安全原语,它通过新的类型类 NFSerializable 使用 NFData。...接收进程可能会崩溃(由于未评估的 thunk)”
  • 而 GHCi 中的 :sprint 似乎可以访问内部大块表示 - stackoverflow.com/q/24755672/94687 。也许 GHCi 可以处理一些特殊的、未优化的代码。所以原则上,如果想序列化大块头,可以使用这种表示和:sprint 的实现,不是吗?
【解决方案2】:

packman:“作为库的 Haskell 数据的评估正交序列化”(感谢reddit link)——正是我们一直在寻找的!

...这个序列化与评估正交:参数是 序列化在其当前的评估状态,它可能是 完全未评估(重击)或仅部分评估(包含 重击)。

...该库可以在不同节点之间发送和接收数据 分布式 Haskell 系统。这是代码的来源: Eden 运行时系统。

...除了这个明显的应用程序之外,该功能还可以用于 通过记忆优化程序(跨不同的程序运行),以及 在选定的位置检查程序执行。两种用途都是 在上面链接的幻灯片中举例说明。

...另一个限制是序列化数据只能被 完全相同的二进制文件。然而,这对于许多方法来说很常见 使用函数式语言进行分布式编程。

...

【讨论】:

    【解决方案3】:

    Cloud Haskell 支持函数闭包的序列化。 http://www.haskell.org/haskellwiki/Cloud_Haskell

    【讨论】:

    • 不完全是。代码必须已经共享,并且只传输函数指针。这对某些用户来说已经足够了,但遗憾的是限制了。
    • @ThomasM.DuBuisson 你能否澄清一下关于“共享”代码的事情:如果我有相同的二进制“a.out”,并运行两个不同的进程“./a.out”,可以我安全地将一个序列化的闭包从一个进程发送到另一个进程?
    • @ThomasM.DuBuisson 为什么?我想将中间的、惰性的结果发送到另一个进程,以便它可以决定何时以及如何使用它:当它需要对它做某事时,它会使用一个表达式,在其中使用这个结果(并可能将它发送到另一个评估过程)。在评估者之间共享相同的代码不是问题,但它们可能是不同的实例......
    • @imz--IvanZakharyaschev 你似乎有正确的想法。如果系统运行相同的二进制文件,则传递闭包可以实现为发送 1)函数指针 2)参数。这并不是真正的完整“闭包”,因为实现只允许顶级函数(例如,不是 lambda),并且解决方案不允许在节点之间传递新代码。这是一种令人沮丧的半解决方案。
    • @ThomasM.DuBuisson 在阅读了有关 HdpH 的文章后,我的印象是,如果您编写代码而不是组合,则可以对表达式进行“深入”控制,以将其作为部分评估的结构发送函数,而是作为 HdpH 闭包的组合。 (也许,可以使用自动翻译器将纯 Haskell 代码转换为闭包......)我已经在 stackoverflow.com/a/17791889/94687 写下了我的想法。
    【解决方案4】:

    除了在 Cloud Haskell 和 HdpH 中关于“闭包”的工作以及说明 thunk 在运行时不可分析的部分答案之外,我发现:

    • :sprint 在 GHCi 中似乎可以访问内部 thunk 表示 - 。也许 GHCi 可以处理一些特殊的、未优化的代码。所以原则上,如果想要序列化 ​​thunk,可以使用这种表示和 :sprint 的实现,不是吗?

    • http://hackage.haskell.org/package/ghc-heap-view-0.5.3/docs/GHC-HeapView.html -- “使用此模块,您可以研究 Haskell 值的堆表示,即研究共享和惰性求值。”

    我很想知道用这些东西可以制作出什么样的用于序列化闭包的可行解决方案......

    【讨论】:

      猜你喜欢
      • 2011-05-06
      • 2010-11-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多