【问题标题】:Haskell command line optionsHaskell 命令行选项
【发布时间】:2011-09-13 09:13:41
【问题描述】:

我编写了一个从 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 Options 的预期类型与实际类型 Options 匹配 opts >=) (return defaultOptions) 动作

我尝试删除操作,但没有成功。

编辑:所以我删除了大部分有问题的行,它起作用了。

opts

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

【问题讨论】:

  • 拖钓代码从来都不是一件好事。导致不必要的不​​安,IMO。

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


【解决方案1】:

让我们来看看main的正文应该做什么。

读取命令行参数:
args &lt;- getArgs

解析参数:
let ( actions, nonOpts, msgs ) = getOpt RequireOrder options args

将参数组合成一组程序参数:
opts &lt;- foldl (&gt;&gt;=) (return defaultOptions) actions

提取参数:
let Options { optNum = input, optOut = output} = opts

使用参数:
input &gt;&gt;= output

GetOpt 库仅处理解析命令行参数。在您的情况下,命令行参数唯一可以控制的是输出的行数,因此 Options 数据结构应该只包含输出的行数。将其编码为字符串没有意义,您可以使用 int。

data Options = Options { optNum :: Int }

当您指定命令行选项时,ArgDescr 用于指定选项参数的解析器。解析器接受一个字符串并将其转换为特定于程序的数据结构。你想要的是把一个字符串变成一个更新选项值的函数。请注意,我取出了 IO 类型(您不需要 IO),这将需要在您的代码的其他地方进行一些小的更改。

readNumLines :: String -> Options -> Options
readNumLines n options = options {optNum = read n}

解析选项后,默认选项会按照每个命令行参数的指示进行更新(请记住,解析会生成更新选项值的函数),以生成最终选项。您正在使用 IO 执行此步骤,但您确实不需要。
opts &lt;- foldl (&gt;&gt;=) (return defaultOptions) actions

由于Options的字段发生了变化,main中的选项提取代码必须更新为
let Options { optNum = opt_num } = opts

此时,您有了一个变量,该变量根据命令行选项保存应打印的实际代码行数,您可以用它做任何您想做的事情。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-14
    相关资源
    最近更新 更多