使用GHC编译非常大的常量

24
今天我让 GHC 编译了一个8MB的 Haskell 源文件。GHC 花了大约6分钟的时间考虑,消耗了近2GB的内存,最终由于内存不足错误而放弃。
[顺便说一句,我很高兴 GHC 有良好的判断力,选择放弃而不是让整个电脑崩溃。]
基本上,我有一个程序,它读取一个文本文件,进行一些高级解析,构建数据结构,然后使用 show 将其转储到文件中。与其在最终应用程序中包含整个解析器和源数据,我想将生成的数据作为编译时常量包含进去。通过向 show 输出添加一些额外的内容,可以使其成为有效的 Haskell 模块。但是 GHC 显然不喜欢编译多 MB 的源文件。
(最奇怪的部分是,如果你只是将数据 read 回来,它实际上并不需要太多的时间或内存。奇怪的是,String I/O 和 read 都被认为非常低效...)
我模糊地记得其他人在过去曾经遇到过让 GHC 编译巨大文件的困难。对于 -O0 我也尝试过,它加快了崩溃速度,但没有阻止它的发生。那么什么是将大量编译时常量包含在 Haskell 程序中的最佳方法呢?
(在我的情况下,这个常量只是一个带有一些有趣标签的嵌套 Data.Map。)
起初,我认为 GHC 可能只是不喜欢读取长度为800万个字符的单行模块。(!) 和布局规则之类的东西有关。或者可能深度嵌套的表达式让它感到不适。但我尝试将每个子表达式变成顶级标识符,那也没有帮助。(为每个表达式添加显式类型签名似乎确实使编译器稍微开心了一些。) 还有其他我可以尝试的方式吗?

最终,我成功将我实际想要存储的数据结构变得更小了,只有300KB。这使得 GHC 更加高兴,同时也让最终的应用程序运行更快。但是,为了日后参考,我还想知道如何最好地处理这个问题。


3
我也曾以为将数据放入源代码中会更好,但后来发现从文件中读取数据在运行时速度要__快得多__。 - AndrewC
4
如果你想将数据和程序捆绑在一个文件中,你可以将它们作为一个字符串常量包含进去,然后只需使用read函数读取,无需进行额外的文件IO操作。在我的笔记本电脑上,GHC可以编译包含50MB字符串的文件。 - leftaroundabout
1
我记得 GHC 在编译长文字列表等方面经常会出问题。不过,我找不到最近的票证或邮件列表线程详细讨论这些问题。 - Daniel Fischer
似乎Data.Binary是正确的选择,但数据类型是隐藏的,我的ghc-foo不够强大,无法看出如何使Data.Map k v成为Data.Binary的实例。你的键的类型是什么,也许Data.IntMap会起作用。另外,你使用的ghc版本是什么,看起来Data.Map.*在7.6.1(明天发布)中进行了大量重写。http://www.haskell.org/pipermail/haskell-cafe/2012-May/101082.html。 - ja.
@ja,FYI,Data.Binary现在有一个适用于Data.Map的实例。我不知道这是什么时候添加的。 - dfeuer
2个回答

5
你最好的选择可能是将值的字符串表示编译到可执行文件中。要以清晰的方式完成此操作,请参考我在先前问题中的回答
使用它时,只需将表达式存储在myExpression.exp中,并启用QuasiQuotes扩展,然后执行read [litFile|myExpression.exp|],表达式将会被“存储为字符串文字”在可执行文件中。

我尝试过类似的方法来存储实际常量,但是它失败了,因为和在 .hs 文件中嵌入值的方法一样。我的尝试是:

Verbatim.hs:

module Verbatim where

import Language.Haskell.TH
import Language.Haskell.TH.Quote
import Language.Haskell.Meta.Parse

readExp :: String -> Q Exp
readExp = either fail return . parseExp

verbatim :: QuasiQuoter
verbatim = QuasiQuoter { quoteExp = readExp }

verbatimFile :: QuasiQuoter
verbatimFile = quoteFile verbatim

测试程序:

{-# LANGUAGE QuasiQuotes #-}
module Main (main) where

import Verbatim

main :: IO ()
main = print [verbatimFile|test.exp|]

这个程序适用于小的test.exp文件,但在这台计算机上,大约2MiB时就会失败。

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接