haskell - official - ubuntu install ghc



Ho insegnato a ghci a compilare i miei post StackOverflow. Posso renderlo slicker? (1)

Haskell Stack Overflow Layout preprocessore

module StackOverflow where  -- yes, the source of this post compiles as is

Vai giù a Cosa fare per farlo funzionare se vuoi giocare con questo primo (1/2 in basso).
Passa a quello che vorrei se mi divincolassi un po 'e vuoi solo scoprire quale aiuto sto cercando.

Riepilogo domande TLDR:

  1. Posso fare in modo che ghci aggiunga il completamento del nome file al comando :so ho definito il comando nel mio ghci.conf ?
  2. Potrei in qualche modo definire un comando ghci che restituisce il codice per la compilazione invece di restituire un comando ghci, o invece ghci ha un modo migliore per collegare il codice Haskell come pre-processore specifico per l'estensione del file, quindi :l per i file .hs e .lhs come al solito, ma usa il mio preprocessore manoscritto per i file .so ?

Sfondo:

Haskell supporta la programmazione alfabetica nei file di origine .lhs , in due modi:

  • Lo stile LaTeX \begin{code} e \end{code} .
  • Tracce di uccelli: il codice inizia con > , qualsiasi altra cosa è un commento.
    Ci deve essere una linea vuota tra codice e commenti (per interrompere un uso improprio banale di > ).

Le regole delle tracce Do not Bird non suonano come i blocchi di codice di StackOverflow?

Riferimenti: 1. Il manuale .ghci 2. GHCi haskellwiki 3. Neil Mitchell parla di :{ e :} in .ghci

Il preprocessore

Mi piace scrivere risposte SO in un editor di testo, e mi piace creare un post composto da codice che funzioni, ma finire con blocchi di commenti o > s che devo modificare prima di postare, il che è meno divertente.

Quindi, mi sono scritto un pre-processore.

  • Se ho incollato alcune parti di ghci come blocco di codice, di solito inizia con * o :
  • Se la riga è completamente vuota, non voglio che venga trattata come codice, perché altrimenti ho degli errori di codice accidentale-next-to-comment-line perché non riesco a vedere i 4 spazi che ho lasciato accidentalmente su una riga altrimenti vuota.
  • Se la riga precedente non era il codice, questa riga non dovrebbe essere né, quindi possiamo far fronte all'uso di indentazione di StackOverflow per scopi di layout di testo al di fuori dei blocchi di codice.

All'inizio non sappiamo (non so) se questa linea è codice o testo:

dunnoNow :: [String] -> [String]
dunnoNow [] = []
dunnoNow (line:lines)
  | all (==' ') line = line:dunnoNow lines     -- next line could be either
  | otherwise = let (first4,therest) = splitAt 4 line in 
     if first4 /="    "                 -- 
        || null therest                 -- so the next line won't ever crash
        || head therest `elem` "*:"     -- special chars that don't start lines of code.
     then line:knowNow False lines      -- this isn't code, so the next line isn't either
     else ('>':line):knowNow True lines -- this is code, add > and the next line has to be too

ma se lo sappiamo, dovremmo mantenere la stessa modalità fino a quando non premiamo su una riga vuota:

knowNow :: Bool -> [String] -> [String]
knowNow _ [] = []
knowNow itsCode (line:lines) 
  | all (==' ') line = line:dunnoNow lines
  | otherwise = (if itsCode then '>':line else line):knowNow itsCode lines

Ottenere ghci per usare il preprocessore

Ora possiamo prendere un nome di modulo, pre-processare quel file e dire a ghci di caricarlo:

loadso :: String -> IO String
loadso fn = fmap (unlines.dunnoNow.lines) (readFile $ fn++".so") -- so2bird each line
        >>= writeFile (fn++"_so.lhs")                     -- write to a new file
        >> return (":def! rso (\\_ -> return \":so "++ fn ++"\")\n:load "++fn++"_so.lhs")

Ho usato silenziosamente la ridefinizione del comando :rso perché i miei precedenti tentativi di utilizzare let currentStackOverflowFile = .... o currentStackOverflowFile <- return ... non mi ha portato da nessuna parte.

Cosa fare per farlo funzionare

Ora ho bisogno di metterlo nel mio file ghci.conf , cioè in appdata/ghc/ghci.conf come da instructions

:{
let dunnoNow [] = []
    dunnoNow (line:lines)
      | all (==' ') line = line:dunnoNow lines     -- next line could be either
      | otherwise = let (first4,therest) = splitAt 4 line in 
         if first4 /="    "                 -- 
            || null therest                 -- so the next line won't ever crash
            || head therest `elem` "*:"     -- special chars that don't start lines of code.
         then line:knowNow False lines      -- this isn't code, so the next line isn't either
         else ('>':line):knowNow True lines -- this is code, add > and the next line has to be too
    knowNow _ [] = []
    knowNow itsCode (line:lines) 
      | all (==' ') line = line:dunnoNow lines
      | otherwise = (if itsCode then '>':line else line):knowNow itsCode lines
    loadso fn = fmap (unlines.dunnoNow.lines) (readFile $ fn++".so") -- convert each line
        >>= writeFile (fn++"_so.lhs")                            -- write to a new file
        >> return (":def! rso (\\_ -> return \":so "++ fn ++"\")\n:load "++fn++"_so.lhs")
:}
:def so loadso

uso

Ora posso salvare l'intero post in LiterateSo.so e fare cose belle in ghci come

*Prelude> :so StackOverflow
[1 of 1] Compiling StackOverflow    ( StackOverflow_so.lhs, interpreted )
Ok, modules loaded: StackOverflow.

*StackOverflow> :rso
[1 of 1] Compiling StackOverflow    ( StackOverflow_so.lhs, interpreted )
Ok, modules loaded: StackOverflow.

*StackOverflow>

Evviva!

Cosa vorrei:

Preferirei consentire a ghci di supportarlo più direttamente. Sarebbe bello sbarazzarsi del file .lhs intermedio.

Inoltre, sembra che ghci esegua il completamento del nome file partendo dalla sottostringa più breve di :load che determina che stai effettivamente load , quindi usando :lso invece di :so non ingannarlo.

(Non vorrei riscrivere il mio codice in C. Inoltre non vorrei ricompilare ghci dalla fonte.)

Promemoria domanda TLDR:

  1. Posso fare in modo che ghci aggiunga il completamento del nome file al comando :so ho definito il comando nel mio ghci.conf ?
  2. Potrei in qualche modo definire un comando ghci che restituisce il codice per la compilazione invece di restituire un comando ghci, o invece ghci ha un modo migliore per collegare il codice Haskell come pre-processore specifico per l'estensione del file, quindi :l per i file .hs e .lhs come al solito, ma usa il mio preprocessore manoscritto per i file .so ?

Vorrei provare a creare un preprocessore standalone che esegua il codice di pre-elaborazione SO o il preprocessore letterario standard, a seconda dell'estensione del file. Quindi usa semplicemente :set -pgmL SO-preprocessor in ghci.conf .

Per il preprocessore letterario standard, eseguire il programma unlit o utilizzare Distribution.Simple.PreProcess.Unlit .

In questo modo :load e completamento del nome file funzionano normalmente.

GHCI passa 4 argomenti al preprocessore, nell'ordine: -h , l'etichetta, il nome del file di origine e il nome del file di destinazione. Il preprocessore dovrebbe leggere l'origine e scrivere nella destinazione. L'etichetta viene utilizzata per generare i #line #line. Puoi ignorarlo se non modifichi il conteggio delle righe della fonte (cioè sostituisci le righe di "commento" con -- commenti o righe vuote).