2013-05-02 12 views
23

Heute habe ich GHC gebeten, eine 8MB Haskell Quelldatei zu kompilieren. GHC dachte etwa 6 Minuten darüber nach, verschluckte fast 2 GB RAM und gab schließlich mit einem Fehler wegen zu wenig Speicher auf.Kompilieren sehr großer Konstanten mit GHC

[Als beiseite, ich bin froh, GHC das gute Gefühl, anstatt Boden abbrechen musste meinen ganzen PC.]

Grundsätzlich ich ein Programm haben, das eine Textdatei liest, hat einige Phantasie Parsing, erstellt eine Datenstruktur und verwendet dann show, um dies in eine Datei zu speichern. Anstatt den gesamten Parser und die Quelldaten in meine endgültige Anwendung aufzunehmen, möchte ich die generierten Daten als Kompilierzeitkonstante einbeziehen. Wenn Sie der Ausgabe von show zusätzliche Daten hinzufügen, können Sie ein gültiges Haskell-Modul erstellen. GHC scheint es jedoch nicht zu schätzen, Multi-MB-Quelldateien zu kompilieren.

(Der seltsamste Teil ist, wenn Sie nur read die Daten zurück, es eigentlich nicht viel Zeit oder Speicherplatz verbrauchen. Seltsam, dass beide String I/O und read sind angeblich sehr ineffizient ... bedenkt)

Ich erinnere mich vage daran, dass andere Leute Probleme damit hatten, GHC dazu zu bringen, in der Vergangenheit riesige Dateien zu kompilieren. FWIW, ich habe versucht, -O0 zu verwenden, was den Absturz beschleunigte, aber nicht verhinderte. Was also ist der beste Weg, um große Kompilierzeit Konstanten in einem Haskell-Programm einzuschließen?

(In meinem Fall ist die Konstante nur eine verschachtelte Data.Map mit einigen interessanten Etiketten.)

Anfangs dachte ich, GHC könnte nur unglücklich sein in ein Modul Lesen einer Zeile aus, die lange acht Millionen Zeichen ist. (!!) Etwas mit der Layout-Regel oder so zu tun. Oder vielleicht, dass die tief verschachtelten Ausdrücke es stören. Aber ich habe versucht, jeden Unterausdruck zu einem Bezeichner auf oberster Ebene zu machen, und das war keine Hilfe. (Hinzufügen von expliziten Typ-Signaturen zu jedem tat scheinen jedoch den Compiler etwas glücklicher zu machen.) Gibt es sonst noch etwas, das ich versuchen könnte, den Compiler-Job einfacher zu machen?

Am Ende war ich in der Lage, die Datenstruktur, die ich eigentlich versuche, viel kleiner zu speichern. (Wie, 300KB.) Dies machte GHC viel glücklicher. (Und die endgültige Anwendung viel schneller.) Aber für zukünftige Referenz wäre ich interessiert zu wissen, was der beste Weg, um dies zu erreichen ist.

+3

Ich bin auch davon überrascht worden, dass es besser wäre, meine Daten in den Quellcode zu stellen, nur um festzustellen, dass es __much__ schneller war, es zur Laufzeit aus der Datei zu lesen. – AndrewC

+3

Oder, wenn Sie nur die Daten und das Programm in einer Datei bündeln möchten, können Sie es als String-Konstante einfügen, die nur "gelesen" ist, ohne zusätzliche Datei-IO. GHC kompiliert Dateien mit 50 MB String auf meinem Laptop. – leftaroundabout

+1

Ich erinnere mich, dass GHC immer Probleme hatte, lange literale Listen und dergleichen zu kompilieren. Ich kann jedoch keinen neueren Ticket- oder Mailinglisten-Thread finden, der irgendwelche Details enthält. –

Antwort

5

Ihre beste Wette ist wahrscheinlich eine Zeichenfolge Darstellung Ihres Wertes in der ausführbaren Datei zu kompilieren. Um dies auf eine saubere Weise zu tun, beziehen Sie sich bitte auf my answer in a previous question.

es zu benutzen, einfach speichern Sie Ihre Expression in myExpression.exp und tun read [litFile|myExpression.exp|] mit der QuasiQuotes Erweiterung aktiviert, und der Ausdruck wird in der ausführbaren Datei „als Stringliteral gespeichert“ werden.


Ich habe versucht, etwas Ähnliches für die Speicherung von tatsächlichen Konstanten zu tun, aber es funktioniert nicht aus dem gleichen Grund, dass der Wert in einer .hs-Datei eingebettet würde.Mein Versuch war:

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 

Testprogramm:

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

import Verbatim 

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

Dieses Programm arbeitet für kleine test.exp Dateien, aber nicht bereits bei etwa 2MiB auf diesem Computer.