今天我要求GHC编译一个8MB的Haskell源文件.GHC考虑了大约6分钟,吞下了近2GB的RAM,然后最终放弃了内存不足的错误.
[顺便说一句,我很高兴GHC很有意义中止而不是整个PC.]
基本上我有一个程序,它读取文本文件,进行一些奇特的解析,构建数据结构然后用于show将其转储到文件中.我不想将整个解析器和源数据包含在我的最终应用程序中,而是将生成的数据作为编译时常量包含在内.通过向输出中添加一些额外的东西show,可以使其成为有效的Haskell模块.但GHC显然不喜欢编译多MB源文件.
(最奇怪的部分是,如果你只read回到数据,它实际上并不需要花费太多时间或内存.奇怪的是,考虑到StringI/O并且read被认为效率非常低......)
我模糊地回忆起其他人在过去使用GHC编译大文件时遇到了麻烦.FWIW,我尝试使用-O0,加速了崩溃但没有阻止它.那么在Haskell程序中包含大型编译时常量的最佳方法是什么?
(在我的例子中,常量只是嵌套Data.Map了一些有趣的标签.)
最初我认为GHC可能只是对阅读由一行长达800万个字符组成的模块感到不满.(!!)与布局规则等有关.或者深深嵌套的表达式可能会扰乱它.但我尝试将每个子表达式设置为顶级标识符,这没有任何帮助.(然而,为每个人添加显式类型签名确实会使编译器更加快乐.)还有什么我可能会尝试使编译器的工作更简单吗?
最后,我能够使我实际上试图存储的数据结构小得多.(比如300KB.)这让GHC更加快乐.(最后的应用程序要快得多.)但是为了将来参考,我有兴趣知道最好的方法是什么.
您最好的选择可能是将值的字符串表示形式编译到可执行文件中.要以干净的方式执行此操作,请参阅上一个问题中的答案.
要使用它,只需将表达式存储在启用的扩展中myExpression.exp并执行,并且表达式将"存储为可执行文件中的字符串文字".read [litFile|myExpression.exp|]QuasiQuotes
我尝试做类似的事情来存储实际的常量,但它失败的原因与将值嵌入.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
Run Code Online (Sandbox Code Playgroud)
测试程序:
{-# LANGUAGE QuasiQuotes #-}
module Main (main) where
import Verbatim
main :: IO ()
main = print [verbatimFile|test.exp|]
Run Code Online (Sandbox Code Playgroud)
此程序适用于小test.exp文件,但在此计算机上已失败约2MiB.