Haskellスタックオーバーフローレイアウトプリプロセッサ
module StackOverflow 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ファイルに私の手書きのプリプロセッサを使用しますか?
バックグラウンド:
.lhsHaskellは、2つの方法でソースファイルの文芸的プログラミングをサポートしています。
- LaTeXスタイル
\begin{code}と\end{code}。 - バードトラック:コードはで始まり
>、それ以外はコメントです。
コードとコメントの間には空白行が必要です(些細な偶発的な誤用を防ぐため>)。
Birdは、ルールをStackOverflowのコードブロックと同じように追跡しませんか?
参考資料: 1。.ghci マニュアル
2. GHCi haskellwiki3..ghci
に関するNeilMitchell のブログ:{:}
プリプロセッサ
私はテキストエディタでSOの回答を書くのが好きで、機能するコードで構成される投稿を作成するのが好きですが、>投稿する前に編集しなければならないコメントブロックやsができてしまうので、面白くありません。
それで、私は自分自身にプリプロセッサを書きました。
- いくつかのghciのものをコードブロックとして貼り付けた場合、通常は
*またはで始まり:ます。 - 行が完全に空白の場合、コードとして扱われることは望ましくありません。そうしないと、空白行に誤って残した4つのスペースが表示されないため、誤ってコメント行の次のコードエラーが発生します。
- 前の行がコードではなかった場合、この行もコードではないはずです。そのため、コードブロックの外側でテキストレイアウトの目的でStackOverflowがインデントを使用することに対処できます。
最初は、この行がコードなのかテキストなのかわかりません(わかりません)。
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 currentStackOverflowFile = ....currentStackOverflowFile <- 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 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>
やったー!
私が欲しいもの:
ghciがこれをより直接的にサポートできるようにしたいと思います。.lhs中間ファイルを取り除くといいでしょう。
また、ghciは、:load実際に実行していることを決定する最も短い部分文字列からファイル名の補完を行うようです。したがって、代わりにをload使用しても、だまされません。:lso:so
(Cでコードを書き直したくありません。また、ソースからghciを再コンパイルしたくありません。)
TLDR質問リマインダー:
- ghciにファイル名補完を
:so自分で定義したコマンドに追加させることはできますghci.confか? - どういうわけか、ghciコマンドを返す代わりにコンパイル用のコードを返すghciコマンドを定義できますか、またはghciは、ファイル拡張子固有のプリプロセッサとしてHaskellコードをプラグインするためのより良い方法を持っている
:lので.hs、.lhsいつものようにファイルしますが、.soファイルに私の手書きのプリプロセッサを使用しますか?