我写过一个从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行。
答案 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
此时,您有一个变量,它根据命令行选项保存应打印的实际代码行数,您可以随意使用它。