Haskell: Parsing command line arguments

后端 未结 4 1102
耶瑟儿~
耶瑟儿~ 2021-02-02 09:14

This more of a style question, rather than a how to.

So I\'ve got a program that needs two command line arguments: a string and an integer.

I implemented it this

4条回答
  •  半阙折子戏
    2021-02-02 10:04

    I agree the optparse-applicative package is very nice. Awesome! Let me give an up-to-date example.

    The program takes as arguments a string and an integer n, returns the string replicated n times, and it has a flag which reverses the string.

    -- file: repstring.hs
    import Options.Applicative
    import Data.Monoid ((<>))
    
    data Sample = Sample
      { string :: String
      , n :: Int
      , flip :: Bool }
    
    replicateString :: Sample -> IO ()
    replicateString (Sample string n flip) = 
        do 
          if not flip then putStrLn repstring else putStrLn $ reverse repstring
              where repstring = foldr (++) "" $ replicate n string
    
    sample :: Parser Sample
    sample = Sample
         <$> argument str 
              ( metavar "STRING"
             <> help "String to replicate" )
         <*> argument auto
              ( metavar "INTEGER"
             <> help "Number of replicates" )
         <*> switch
              ( long "flip"
             <> short 'f'
             <> help "Whether to reverse the string" )
    
    main :: IO ()
    main = execParser opts >>= replicateString
      where
        opts = info (helper <*> sample)
          ( fullDesc
         <> progDesc "Replicate a string"
         <> header "repstring - an example of the optparse-applicative package" )
    

    Once the file is compiled (with ghc as usual):

    $ ./repstring --help
    repstring - an example of the optparse-applicative package
    
    Usage: repstring STRING INTEGER [-f|--flip]
      Replicate a string
    
    Available options:
      -h,--help                Show this help text
      STRING                   String to replicate
      INTEGER                  Number of replicates
      -f,--flip                Whether to reverse the string
    
    $ ./repstring "hi" 3 
    hihihi
    $ ./repstring "hi" 3 -f
    ihihih
    

    Now, assume you want an optional argument, a name to append at the end of the string:

    -- file: repstring2.hs
    import Options.Applicative
    import Data.Monoid ((<>))
    import Data.Maybe (fromJust, isJust)
    
    data Sample = Sample
      { string :: String
      , n :: Int
      , flip :: Bool
      , name :: Maybe String }
    
    replicateString :: Sample -> IO ()
    replicateString (Sample string n flip maybeName) = 
        do 
          if not flip then putStrLn $ repstring ++ name  else putStrLn $ reverse repstring ++ name
              where repstring = foldr (++) "" $ replicate n string
                    name = if isJust maybeName then fromJust maybeName else ""
    
    sample :: Parser Sample
    sample = Sample
         <$> argument str 
              ( metavar "STRING"
             <> help "String to replicate" )
         <*> argument auto
              ( metavar "INTEGER"
             <> help "Number of replicates" )
         <*> switch
              ( long "flip"
             <> short 'f'
             <> help "Whether to reverse the string" )
         <*> ( optional $ strOption 
              ( metavar "NAME"
             <> long "append"
             <> short 'a'
             <> help "Append name" ))
    

    Compile and have fun:

    $ ./repstring2 "hi" 3 -f -a rampion
    ihihihrampion
    

提交回复
热议问题