问题描述
|
我已经编写了一个从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
此时,您将拥有一个变量,该变量根据命令行选项保存应打印的实际代码行数,并且您可以使用它进行任何操作。