Haskell命令行选项

时间:2011-06-12 11:40:06

标签: haskell command-line-arguments argument-passing

我写过一个从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的唯一地方来自Options。现在,如果没有设置N开关,我想运行带有arg为10的readNumLines命令。我显然没有这样做。

提前致谢:)

编辑:所以,经过一些拖拽我的代码后,我已经把它变成了一个状态,它不会给我带来任何错误,但仍然无法编译:不在范围内:数据构造函数'选项' ,但我已经定义了选项?编辑:我已经更改了Options构造函数,但是现在它告诉我它无法与预期的IO选项类型匹配实际类型选项     opts&lt; - foldl(&gt;&gt; =)(返回defaultOptions)操作

我尝试删除操作但不起作用。

编辑:所以我删除了大部分有问题的行,并且它有效。

opts&lt; - return defaultOptions

然而,传递-n没有做任何事情,它只返回前10行。

1 个答案:

答案 0 :(得分:3)

让我们回顾一下main的身体应该做些什么。

阅读命令行参数:
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的字段已更改,因此主要中的选项解压代码必须更新为let Options { optNum = opt_num } = opts

此时,您有一个变量,它根据命令行选项保存应打印的实际代码行数,您可以随意使用它。