Параметры командной строки на Haskell - PullRequest
0 голосов
/ 12 июня 2011

Я написал базовый эмулятор головы, который читает из 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.

Теперь, мой опыт здесь заканчивается. Кажется, что единственное место, где я на самом деле вызываю readNumLines, находится в Options, если установлен переключатель N. Теперь, если переключатель N не установлен, я хочу запустить команду readNumLines с аргументом 10. Я явно не правильно делаю это.

Заранее спасибо:)

РЕДАКТИРОВАТЬ: Итак, после небольшого троллинга моего кода, я получил его в состояние, когда он не выдает никаких ошибок, но все равно не будет компилироваться: Не в области видимости: конструктор данных 'options' , но я уже определил варианты? РЕДАКТИРОВАТЬ: я изменил конструктор параметров, но теперь он говорит мне, что он не может сопоставить ожидаемый тип параметров ввода-вывода с фактическим типом параметров в opts <- foldl (>> =) (вернуть defaultOptions) действия

Я пытался удалить действия, но это не сработало.

РЕДАКТИРОВАТЬ: Итак, я удалил большую часть этой проблемной строки, и это сработало.

opts <- вернуть defaultOptions </p>

Однако передача -n ничего не делает, она возвращает только первые 10 строк.

1 Ответ

3 голосов
/ 12 июня 2011

Давайте рассмотрим, что должно делать тело 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

На данный момент у вас есть переменная, которая содержит фактическое количество строк кода, которые должны быть напечатаны, на основе параметров командной строки, и вы можете делать с ней все, что захотите.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...