将文学化的Haskell (.lhs) 转为 Haskell (.hs)

7
有没有一种简单的方法将文学 Haskell 文件(.lhs)转换为常规的 Haskell (.hs) 源文件?
我想可能有一个 GHC 选项,但是 GHC 手册似乎没有关于文学程序或 .lhs 格式的太多信息。甚至索引中都没有出现“文学”这个词!
维基上的文学编程链接包括了一些转换"bird"和"\begin{code}..\end{code}"风格或将.lhs转换为TeX格式的脚本链接,但仅限于此。

为什么这个问题被认为是离题的?它很明确、简洁,而且肯定是实用和可回答的。我也认为文学化 Haskell 文件的语法和语义非常符合“有关 Haskell 的问题”的范围。 - oisdk
2个回答

7

GHC本身使用一个名为unlit的独立C程序来处理.lhs文件。你可能可以在GHC安装的某个地方找到它。如果你运行它,它会显示一些命令行选项但没有解释:

$ cd ~/.stack/programs/x86_64-linux/ghc-8.6.4/lib/ghc-8.6.4/bin
$ ./unlit
usage: unlit [-q] [-n] [-c] [-#] [-P] [-h label] file1 file2

深入源代码查看,看起来选项有:
-q   "quiet": ignore certain errors, so permit missing empty lines before and after
     "bird" style and accept completely empty programs
-n   (default) "noisy": opposite of -q, so be noisy about errors
-c   "crunch": don't leave blank lines where literate comments are removed
-#   delete lines that start with "#!"
-P   suppress CPP line number pragma, but only matters if `-h` is supplied
-h   File name for an initial `#line` pragma

所以,命令行:
$ /path/to/unlit -c myfile.lhs myfile.hs

它可能会很好地转换myfile.lhs文件:

This is a literate program

> main :: IO ()

using both code styles
\begin{code}
  main = putStrLn "hello"
\end{code}

将以下内容翻译成中文:

对于一个"文盲"程序myfile.hs

  main :: IO ()
  main = putStrLn "hello"

对于“bird”样式,它实际上将'>'字符替换为空格,并保留其余缩进不变。因此,针对我上面的示例,在myfile.hs中的两行都以两个空格缩进,这可能是一个缺点。

0

只需像下面这样匆忙地编写一个脚本即可 :) 这将把文学部分转换为行注释。

{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ViewPatterns #-}

import Control.Monad (forM_)
import System.FilePath.Glob (glob)
import qualified Data.Text as T
import qualified Data.Text.IO as T
import System.FilePath (replaceExtension)
import Development.Shake.Command

unLiterateHaskell :: T.Text -> T.Text
unLiterateHaskell = T.unlines . map processLine . T.lines

processLine :: T.Text -> T.Text
processLine (T.stripEnd -> txt) = case T.uncons txt of
  Nothing -> txt
  Just ('>', txt) -> T.drop 1 txt -- may need to adjust here depending on style
  Just{} -> "-- " <> txt

main :: IO ()
main = do
  files <- glob "**/*.lhs"
  forM_ files $ \f -> do
    src <- T.readFile f
    T.writeFile (replaceExtension f "hs") (unLiterateHaskell src)
    Exit _ <- cmd ("mv" :: String) f (f <> ".bak")
    pure ()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接