Давайте рассмотрим, что должно делать тело 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 используется для указания анализатора для аргумента параметра. Парсер берет строку и превращает ее в специфичную для программы структуру данных. Вам нужно превратить строку в функцию, которая обновляет значение параметров . Обратите внимание, что я вынул тип ввода-вывода (вам не нужен ввод-вывод), который потребует некоторых незначительных изменений в другом месте вашего кода.
readNumLines :: String -> Options -> Options
readNumLines n options = options {optNum = read n}
После анализа параметров параметры по умолчанию обновляются в соответствии с указаниями каждого аргумента командной строки (помните, что при синтаксическом анализе создаются функции, которые обновляют значение параметров), для генерации окончательных параметров. Вы используете IO, чтобы сделать этот шаг, но вам действительно не нужно.
opts <- foldl (>>=) (return defaultOptions) actions
Поскольку поля Options
изменились, код извлечения опций в main должен быть обновлен до
let Options { optNum = opt_num } = opts
На данный момент у вас есть переменная, которая содержит фактическое количество строк кода, которые должны быть напечатаны, на основе параметров командной строки, и вы можете делать с ней все, что захотите.