Haskell: Turtle: анализатор командной строки

Я пытался создать парсер командной строки с Turtle, ничего особенного: https://github.com/Tyrn/go-procr

#!/usr/bin/env stack
{-# LANGUAGE OverloadedStrings #-}

module Main where

import Turtle
import Prelude hiding (FilePath)

parserSwitch :: Parser (Bool, Bool)
parserSwitch = (,) <$> switch "verbose" 'v' "Unless verbose, just progress bar is shown"
                   <*> switch "filetitle" 'f' "Use file name for title tag"

parserArg :: Parser (FilePath, FilePath)
parserArg = (,)    <$> argPath "src" "Source directory"
                   <*> argPath "dst" "Destination directory"

main :: IO ()
main = do
  (verbose, filetitle) <- options "Flags" parserSwitch
  echo (format ("verbose: "%w) verbose)
  echo (format ("filetitle: "%w) filetitle)
  (src, dst) <- options "Args" parserArg
  echo (format ("src: "%fp) src)
  echo (format ("dst: "%fp) dst)

Требуются три вида аргументов: логические флаги; параметры, текст и целое число; позиционные аргументы. Пока что я застрял в логических флагах и позиционных аргументах. К сожалению, примеры кажутся слишком простыми даже для этого.

  1. Действительно ли мне нужно создавать отдельные парсеры для разных типов опций (мне не удалось удовлетворить синтаксис одним парсером)?

  2. В любом случае, это не сработает.

Я не могу понять, каким должен быть мой следующий шаг.

1 ответ

Решение

Ваш первый шаг - иметь что-то, где вы сможете легко хранить и извлекать ваши параметры:

data Settings = Settings
   { settingsVerbose      :: Bool
   , settingsFileTitle    :: Bool
   , settingsSource       :: FilePath
   , settingsDestination  :: FilePath
   }

После этого вы пишете парсеры для ваших опций. Чтобы прояснить ситуацию, давайте сначала будем немного многословны:

verboseParser :: Parser Bool
verboseParser = switch "verbose" 'v' "Be more verbose"

fileTitleParser :: Parser Bool
fileTitleParser = switch "filetitle" 'f' "..."

sourceParser :: Parser FilePath
sourceParser = argPath "src" "Source directory"

destinationParser :: Parser FilePath
destinationParser = argPath "dst" "Destination directory"

поскольку Parser это пример Applicative затем мы можем объединить все опции в одном парсере:

settingsParser :: Parser Settings
settingsParser = 
    Settings <$> verboseParser
             <*> fileTitleParser
             <*> sourceParser
             <*> destinationParser

Мы объединили все четыре парсера в один парсер, аналогично комбинации через (,), Теперь мы можем разобрать варианты с помощью одного вызова options, В конце концов, либо все аргументы верны, либо мы должны предоставить пользователю правильное использование:

main = do
   s <- options "Description of your program" settingsParser

   echo (format ("verbose: "%w)   (settingsVerbose s))
   echo (format ("filetitle: "%w) (settingsFileTitle s))
   echo (format ("src: "%fp)      (settingsSource s))
   echo (format ("dst: "%fp)      (settingsDestination s))

Вы, вероятно, хотите использовать более короткие имена, и, возможно, написать парсеры в settingsParser:

data Settings = Settings
   { sVerbose     :: Bool
   , sFileTitle   :: Bool
   , sSource      :: FilePath
   , sDestination :: FilePath
   }

settingsP :: Parser Settings
settingsP = 
  Settings <$> switch "verbose"   'v' "Be more verbose"
           <*> switch "filetitle" 'f' "..."
           <*> argPath "src" "Source directory"
           <*> argPath "dest" "Destination directory"

description :: Description
description = "Description of your program"

main = do
  (Settings verbose filetitle source dest) <- options description settingsP
  ...
Другие вопросы по тегам