HaskellのOptparse-Applicativeの底力を知る
元ネタ RubyのOptionParserの底力を知る - ザリガニが見ていた...。
Haskell版で苦労最小限でオプションを解析できるのか、調べてみた。
使うライブラリは optparse-applicative
理由は最近見かけたこのスライドで推薦されていたから
Getting it Done with Haskell - Google スライド
optparse-applicative のバージョンは 0.9.1.1
githubの最新版ではいくつかの関数・APIが変更されているようで、使用バージョンではマニュアル通りに書いてもエラーになるものもあった。
基本
module Main where import Data.Monoid import Options.Applicative data MyOption= MyOption { optName :: String } runWithOptions :: MyOption -> IO () runWithOptions opts = putStrLn $ "name = " ++ optName opts main :: IO () main = execParser opts >>= runWithOptions where parser = MyOption <$> argument str (metavar "NAME") opts = info parser mempty
- オプション定義のデータ型を定義する
- ハイフン付きのオプションだけでなく素の引数も定義できる
- 簡単なヘルプが自動で出力される
$ runghc ex01.hs foo name = foo $ runghc ex01.hs Usage: ex01.hs NAME
1文字オプション
- 1文字オプションは、-で始まる1文字のオプション名。
- short で設定する
module Main where import Options.Applicative data MyOption= MyOption { optName :: String , a :: Bool , b :: String , c :: Maybe String } deriving Show run :: MyOption -> IO () run opts = print opts parser = MyOption <$> argument str (metavar "NAME") <*> switch (short 'a' <> help "1文字オプション 引数なし") <*> strOption (short 'b' <> help "1文字オプション 引数あり (必須)") <*> optional (strOption (short 'c' <> help "1文字オプション 引数あり (省略可能)")) main :: IO () main = execParser opts >>= run where opts = info parser idm
1文字オプションとロングオプション
- ロングオプションは、--で始まる2文字以上のオプション名。
module Main where import Options.Applicative data MyOption= MyOption { optName :: String , a :: Bool , b :: String , c :: Maybe String } deriving Show run :: MyOption -> IO () run opts = print opts parser = MyOption <$> argument str (metavar "NAME") <*> switch (short 'a' <> long "along" <> help "1文字オプション 引数なし") <*> strOption (short 'b' <> long "blong" <> help "1文字オプション 引数あり (必須)") <*> optional (strOption (short 'c' <> long "clong" <> help "1文字オプション 引数あり (省略可能)")) main :: IO () main = execParser opts >>= run where opts = info parser idm
noオプション
- noオプションにあたるものは無さそう
オプション引数を数値や配列として受け取る
- ハイフン指定無しの文字列引数は argument str
- 文字列引数は strOption
- 整数値などは option
- 文字列リストは many . strOption
- 整数リストはいくつか試してみたが方法がわからず
module Main where import Options.Applicative data MyOption= MyOption { optName :: String , optStr :: String , optStr2 :: String , optInt :: Int , optDouble :: Double , optStrList :: [String] -- , optIntList :: [Int] } deriving Show run :: MyOption -> IO () run opts = print opts parser = MyOption <$> argument str (metavar "NAME") <*> strOption (short 's' <> long "string" <> help "string") <*> option (short 'x' <> long "string2" <> help "string2") <*> option (short 'i' <> long "int" <> help "int") <*> option (short 'd' <> long "double" <> help "double") <*> (many . strOption) (short 'S' <> long "strlist" <> help "string list") -- <*> (many . option) (short 'I' <> long "intlist" <> help "int list") main :: IO () main = execParser opts >>= run where opts = info parser idm
オプション引数の選択肢
TODO
オプション引数のパターン指定
TODO
ヘルプ表示をデザインする
TODO
その他の関数
このあたりを読めば他に使えそうな関数が見つかる
- github最新版 optparse-applicative/Builder.hs at master · pcapriotti/optparse-applicative · GitHub
- リリース最新版(0.9.1.1)
Options.Applicative.Builder
また、gitコマンドのようにサブコマンドを定義する方法も用意されていて便利そう
optparse-applicative/Cabal.hs at master · pcapriotti/optparse-applicative · GitHub
マニュアル
- Hackage: optparse-applicative: Utilities and combinators for parsing command line options
- pcapriotti/optparse-applicative · GitHub
自分の勉強のために書いてみましたが、公式マニュアルが綺麗にまとまっているのでそっちを読んだ方がいいですよ、というオチ。