Pertanyaan Saya mengajar ghci untuk mengkompilasi posting StackOverflow saya. Bisakah saya membuatnya jas hujan?


Haskell Stack Overflow layout preprocessor

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

Lewati ke Apa yang harus dilakukan untuk membuatnya berfungsi jika Anda ingin bermain dengan ini terlebih dahulu (1/2 jalan ke bawah).
Lewati ke Apa yang saya inginkan jika saya berbicara sedikit dan Anda hanya ingin mencari tahu bantuan yang saya cari.

Ringkasan Pertanyaan TLDR:

  1. Bisakah saya mendapatkan ghci untuk menambahkan nama file selesai ke :so perintah yang saya tetapkan dalam ghci.conf?
  2. Bisakah saya entah bagaimana mendefinisikan perintah ghci yang mengembalikan kode untuk kompilasi bukannya mengembalikan perintah ghci, atau Apakah ghci malah memiliki cara yang lebih baik bagi saya untuk memasukkan kode Haskell sebagai pra-prosesor file-ekstensi-spesifik, jadi :l akan bekerja untuk .hs dan .lhs file seperti biasa, tetapi gunakan preprocessor saya yang ditulis tangan untuk .so file?

Latar Belakang:

Haskell mendukung pemrograman literasi di .lhs file sumber, dua cara:

  • Gaya LaTeX \begin{code} dan \end{code}.
  • Trek burung: Kode dimulai dengan >, yang lain adalah komentar.
    Harus ada garis kosong antara kode dan komentar (untuk menghentikan penyalahgunaan disengaja yang sepele >).

Bukankah aturan trek Bird terdengar mirip dengan blok kode StackOverflow?

Referensi: 1  Manual .ghci 2  GHCi haskellwiki 3  Blog Neil Mitchell tentang :{ dan :} di .ghci 

The preprocessor

Saya suka menulis jawaban SO di editor teks, dan saya suka membuat posting yang terdiri dari kode yang berfungsi, tetapi berakhir dengan blok komentar atau >bahwa saya harus mengedit sebelum posting, yang kurang menyenangkan.

Jadi, saya menulis sendiri pre-processor.

  • Jika saya telah memasukkan beberapa ghci sebagai blok kode, biasanya dimulai dengan * atau :.
  • Jika baris benar-benar kosong, saya tidak ingin diperlakukan sebagai kode, karena jika tidak Saya mendapatkan kesalahan kode-samping-komentar-baris yang tidak disengaja karena saya tidak dapat melihat 4 spasi secara tidak sengaja ditinggalkan pada baris kosong.
  • Jika baris sebelumnya bukan kode, baris ini seharusnya tidak boleh, jadi kita dapat mengatasi StackOverflow penggunaan indentasi untuk keperluan tata letak teks di luar blok kode.

Awalnya kami tidak tahu (dunno) apakah baris ini adalah kode atau teks:

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

tetapi jika kita tahu, kita harus tetap dalam mode yang sama sampai kita mencapai garis kosong:

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

Membuat ghci menggunakan preprocessor

Sekarang kita dapat mengambil nama modul, preprocess file itu, dan beri tahu ghci untuk memuatnya:

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")

Saya telah menggunakan diam-diam mendefinisikan ulang :rso perintah karena menggunakan attemts saya sebelumnya let currentStackOverflowFile = .... atau currentStackOverflowFile <- return ... tidak mendapatkan saya di mana saja.

Apa yang harus dilakukan untuk membuatnya berfungsi

Sekarang saya harus memasukkannya ke dalam ghci.conf file, yaitu di appdata/ghc/ghci.conf  sesuai dengan instruksi

:{
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

Pemakaian

Sekarang saya dapat menyimpan seluruh pos ini di LiterateSo.so dan melakukan hal-hal yang indah di ghci seperti

*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>

Hore!

Apa yang saya inginkan:

Saya lebih suka mengaktifkan ghci untuk mendukung ini lebih langsung. Akan menyenangkan untuk menyingkirkan perantara .lhsmengajukan.

Juga, tampaknya ghci tidak menyelesaikan nama file dimulai pada substring terpendek :load yang menentukan Anda benar-benar melakukan load, jadi menggunakan :lso dari pada :so tidak membodohi itu.

(Saya akan tidak suka menulis ulang kode saya di C. Saya juga akan tidak ingin mengkompilasi ulang ghci dari source.)

Pengingat Pertanyaan TLDR:

  1. Bisakah saya mendapatkan ghci untuk menambahkan nama file selesai ke :so perintah yang saya tetapkan dalam ghci.conf?
  2. Bisakah saya entah bagaimana mendefinisikan perintah ghci yang mengembalikan kode untuk kompilasi bukannya mengembalikan perintah ghci, atau Apakah ghci malah memiliki cara yang lebih baik bagi saya untuk memasukkan kode Haskell sebagai pra-prosesor file-ekstensi-spesifik, jadi :l akan bekerja untuk .hs dan .lhs file seperti biasa, tetapi gunakan preprocessor saya yang ditulis tangan untuk .so file?

32
2017-10-01 01:55


asal


Jawaban:


Saya akan mencoba membuat preprocessor mandiri yang menjalankan kode SO preprocessing atau preprocessor sastra standar, tergantung pada ekstensi file. Kemudian gunakan saja :set -pgmL SO-preprocessor di ghci.conf.

Untuk preprocessor sastra standar, jalankan unlit program, atau gunakan Distribution.Simple.PreProcess.Unlit.

Cara ini, :load dan penyelesaian nama file hanya berfungsi normal.

GHCI melewati 4 argumen ke preprocessor, dalam urutan: -h, label, nama file sumber, dan nama file tujuan. Preprocessor harus membaca sumber dan menulis ke tujuan. Label digunakan untuk output #line pragmas. Anda dapat mengabaikannya jika Anda tidak mengubah jumlah baris sumber (yaitu mengganti baris "komentar" dengan -- komentar atau baris kosong).


9
2017-10-01 10:20