haskell - official - ubuntu install ghc
Ho insegnato a ghci a compilare i miei post StackOverflow. Posso renderlo slicker? (1)
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).
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:
- Posso fare in modo che ghci aggiunga il completamento del nome file al comando
:so
ho definito il comando nel mioghci.conf
? - 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:
- Posso fare in modo che ghci aggiunga il completamento del nome file al comando
:so
ho definito il comando nel mioghci.conf
? - 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
?