Haskell命令行选项

问题描述

| 我已经编写了一个从stdIn读取的基本头部仿真器:
import IO
import System

io lineList = interact (unlines . lineList . lines)
--Found this. Basically it takes all input from stdIn and reads it lazily.
main = do
    [numLines] <- getArgs
    io (take (read numLines))
    --reads by lines.
然后,我尝试像这样添加命令行(来源:http://leiffrenzel.de/papers/commandline-options-in-haskell.html)
import IO
import System
import System.Console.Getopt

io lineList = interact (unlines . lineList . lines)
--Found this. Basically it takes all input from stdIn and reads it lazily.
main = do
    args <- getArgs
    let ( actions,nonopts,msgs ) = getopt     RequireOrder     options args
    opts <- foldl (>>=) (return defaultOptions) actions
    let Options {   optNum = input,optOut = output} = opts
    input >>= output

data Options = Options {
        optNum :: IO String,optOut :: String -> IO ()
    }

defaultOptions :: Options
defaultOptions = Options {
        optNum = \"10\",optOut = io (take optNum)
    }

options :: [OptDescr (Options -> IO Options)]
options = [
    Option [\'n\'] [\"numlines\"] (OptArg readNumLines     )    \"read x amount of lines\"
    ]

readNumLines arg opt = return opt (go arg)
go w = io (take (read w))
    --reads by lines.
现在,我在这里的经验即将耗尽。如果设置了N开关,似乎我真正要调用的readNumLines的唯一位置是从选项。现在,如果未设置N开关,则我想以arg 10来运行readNumLines命令。我显然没有正确执行此操作。 提前致谢 :) 编辑:因此,经过一番摸索之后,我将其设置为不会向我抛出任何错误的状态,但仍然无法编译:不在范围内:数据构造函数\'options \”,但是我已经定义了选项?编辑:我已经更改了选项构造函数,但现在它告诉我它无法将IO选项的预期类型与实际类型的选项相匹配。     选择<-foldl(>> =)(返回defaultOptions)操作 我尝试删除操作,但这没用。 编辑:所以我删除了大部分有问题的行,并且它起作用。 选择<-返回defaultOptions 但是,传递-n不会执行任何操作,它只会返回前10行。     

解决方法

        让我们回顾一下ѭ2的主体应该做什么。 读取命令行参数:
args <- getArgs
解析参数:
let ( actions,nonOpts,msgs ) = getOpt RequireOrder options args
将参数组合为一组程序参数:
opts <- foldl (>>=) (return defaultOptions) actions
提取参数:
let Options { optNum = input,optOut = output} = opts
使用参数:
input >>= output
GetOpt库仅处理解析命令行参数。在您的情况下,命令行参数唯一可以控制的是输出的行数,因此Options数据结构应仅包含输出的行数。将其编码为字符串没有意义,您可以仅使用int。
data Options = Options { optNum :: Int }
当您指定命令行选项时,将使用ArgDescr来指定选项参数的解析器。解析器采用字符串并将其转换为程序特定的数据结构。您想要的是将字符串转换为可更新“选项”值的函数。请注意,我取出了IO类型(您不需要IO),这将需要对代码中的其他地方进行一些小的更改。
readNumLines :: String -> Options -> Options
readNumLines n options = options {optNum = read n}
解析选项后,默认选项将按照每个命令行参数的指示进行更新(请记住,解析会生成可更新Options值的函数),以生成最终选项。您正在使用IO来执行此步骤,但实际上并不需要。
opts <- foldl (>>=) (return defaultOptions) actions
由于
Options
的字段已更改,因此main中的选项提取代码必须更新为
let Options { optNum = opt_num } = opts
此时,您将拥有一个变量,该变量根据命令行选项保存应打印的实际代码行数,并且您可以使用它进行任何操作。