Я научил ghci составлять мои сообщения Stackru. Могу ли я сделать это более гладким?
Препроцессор макета Haskell Stack Overflow
module Stackru where -- yes, the source of this post compiles as is
Перейдите к пункту Что нужно сделать, чтобы он заработал, если вы хотите поиграть с этим первым (1/2 пути вниз).
Перейдите к пункту " Что бы я хотел", если я немного увядаю, а вы просто хотите узнать, какую помощь я ищу.
Резюме вопроса TLDR:
- Могу ли я получить ghci, чтобы добавить завершение имени файла в
:so
команда, которую я определил в моемghci.conf
? - Могу ли я как-то определить команду ghci, которая возвращает код для компиляции вместо возврата команды ghci, или же вместо этого у ghci есть лучший способ подключить код на Haskell в качестве препроцессора, специфичного для расширения файла, так что
:l
будет работать для.hs
а также.lhs
файлы, как обычно, но используйте мой рукописный препроцессор для.so
файлы?
Фон:
Haskell поддерживает грамотное программирование в .lhs
Исходные файлы двумя способами:
- Латекс стиль
\begin{code}
а также\end{code}
, - Следы птиц: код начинается с
>
Все остальное является комментарием.
Между кодом и комментариями должна быть пустая строка (чтобы избежать случайного случайного неправильного использования>
).
Разве правила отслеживания птиц не похожи на блоки кода Stackru?
Ссылки: 1. Руководство.ghci 2. GHCi haskellwiki 3. Блог Нила Митчелла о :{
а также :}
в.ghci
Препроцессор
Мне нравится писать SO ответы в текстовом редакторе, и мне нравится делать пост, который состоит из кода, который работает, но в конечном итоге с блоками комментариев или >
s, что я должен отредактировать перед публикацией, что не так весело.
Итак, я написал себе препроцессор.
- Если я вставил некоторые элементы ghci как блок кода, он обычно начинается с
*
или же:
, - Если строка совершенно пустая, я не хочу, чтобы она воспринималась как код, потому что в противном случае я получаю случайные ошибки code-next-to-comment-line, потому что не вижу 4 пробела, которые я случайно оставил в пустой строке.
- Если в предыдущей строке не было кода, эта строка также не должна быть, поэтому мы можем справиться с использованием отступа в Stackru для разметки текста вне блоков кода.
Сначала мы не знаем (не знаю), является ли эта строка кодом или текстом:
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
но если мы знаем, мы должны оставаться в том же режиме, пока не достигнем пустой строки:
knowNow :: Bool -> [String] -> [String]
knowNow _ [] = []
knowNow itsCode (line:lines)
| all (==' ') line = line:dunnoNow lines
| otherwise = (if itsCode then '>':line else line):knowNow itsCode lines
Получение GHCI использовать препроцессор
Теперь мы можем взять имя модуля, предварительно обработать этот файл и сказать ghci загрузить его:
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")
Я использовал молча переопределение :rso
команда, потому что мои предыдущие попытки использовать let currentStackruFile = ....
или же currentStackruFile <- return ...
не получил меня никуда.
Что нужно сделать, чтобы это заработало
Теперь мне нужно положить его в мой ghci.conf
файл, т.е. в appdata/ghc/ghci.conf
согласно инструкции
:{
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
использование
Теперь я могу сохранить весь этот пост в LiterateSo.so
и делать милые вещи в GHCI, как
*Prelude> :so Stackru
[1 of 1] Compiling Stackru ( Stackru_so.lhs, interpreted )
Ok, modules loaded: Stackru.
*Stackru> :rso
[1 of 1] Compiling Stackru ( Stackru_so.lhs, interpreted )
Ok, modules loaded: Stackru.
*Stackru>
Ура!
Что бы я хотел:
Я бы предпочел включить ghci для более прямой поддержки. Было бы неплохо избавиться от промежуточного .lhs
файл.
Кроме того, кажется, что ghci выполняет завершение имени файла, начиная с самой короткой подстроки :load
который определяет, что вы на самом деле делаете load
так что используя :lso
вместо :so
не обманешь
(Я не хотел бы переписывать свой код на C. Я также не хотел бы перекомпилировать ghci из исходного кода.)
TLDR Вопрос напоминание:
- Могу ли я получить ghci, чтобы добавить завершение имени файла в
:so
команда, которую я определил в моемghci.conf
? - Могу ли я как-то определить команду ghci, которая возвращает код для компиляции вместо возврата команды ghci, или же вместо этого у ghci есть лучший способ подключить код на Haskell в качестве препроцессора, специфичного для расширения файла, так что
:l
будет работать для.hs
а также.lhs
файлы, как обычно, но используйте мой рукописный препроцессор для.so
файлы?
1 ответ
Я бы попытался создать автономный препроцессор, который запускает код предварительной обработки SO или стандартный литературный препроцессор, в зависимости от расширения файла. Тогда просто используйте :set -pgmL SO-preprocessor
в ghci.conf
,
Для стандартного литературного препроцессора запустите unlit
запрограммировать или использовать Distribution.Simple.PreProcess.Unlit
,
Сюда, :load
и завершение имени файла просто работает нормально.
GHCI передает препроцессору 4 аргумента в следующем порядке: -h
, метка, имя исходного файла и имя файла назначения. Препроцессор должен прочитать источник и записать в место назначения. Метка используется для вывода #line
псевдокомментарии. Вы можете проигнорировать это, если не измените количество строк в источнике (т.е. замените строки "комментария" на --
комментарии или пустые строки).