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