Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Parsing haskell-解析命令行和REPL命令及选项_Parsing_Haskell_Command Line - Fatal编程技术网

Parsing haskell-解析命令行和REPL命令及选项

Parsing haskell-解析命令行和REPL命令及选项,parsing,haskell,command-line,Parsing,Haskell,Command Line,我正在编写一个既有命令行界面又有交互模式的程序。在CLI模式下,它执行一个命令,打印结果并退出。在交互模式下,它使用GNU readline重复读取命令,执行它们并打印结果(以REPL的精神) 命令及其参数的语法几乎相同,无论它们是来自命令行还是frmo stdin。我希望通过使用单个框架来解析命令行和交互模式输入,最大限度地提高代码重用 我建议的语法如下(方括号表示可选部分,大括号重复): 来自壳牌: program-name {[GLOBAL OPTION] ...} <comman

我正在编写一个既有命令行界面又有交互模式的程序。在CLI模式下,它执行一个命令,打印结果并退出。在交互模式下,它使用GNU readline重复读取命令,执行它们并打印结果(以REPL的精神)

命令及其参数的语法几乎相同,无论它们是来自命令行还是frmo stdin。我希望通过使用单个框架来解析命令行和交互模式输入,最大限度地提高代码重用

我建议的语法如下(方括号表示可选部分,大括号重复):

  • 来自壳牌:

    program-name {[GLOBAL OPTION] ...} <command> [{<command arg>|<GLOBAL OPTION>|<LOCAL OPTION> ...}]  
    
    程序名{[GLOBAL OPTION]…}[{| |…}]
    
  • 在交互模式下:

    <command> [{<command arg>|<GLOBAL OPTION>|<LOCAL OPTION> ...}]
    
    
    
本地选项仅对一个特定命令有效(不同的命令可能会为一个选项指定不同的含义)

我的问题是CL和交互界面之间存在一些差异: 某些全局选项仅在命令行中有效(如--help、-version或--config文件)。显然还有“quit”命令,这在交互模式中非常重要,但是从CL使用它是没有意义的

为了解决这个问题,我在web和hackage上搜索了命令行解析库。我发现最有趣的是cmdlib和optparse应用程序。然而,我对Haskell还很陌生,尽管我可以通过复制和修改库文档中的示例代码来创建一个工作程序,但我还不太了解这些库的机制,因此无法解决我的问题

我心里有这些问题:
如何为CL和REPL接口通用的命令和选项创建基本解析器,然后使用新命令和选项扩展基本解析器?
如何防止这些库在输入错误或使用“-help”时退出我的程序?
我计划为我的程序添加完整的i18n支持。因此,我想阻止我选择的库打印任何消息,因为所有消息都需要翻译。如何做到这一点


所以我希望你能给我一些提示,告诉我从这里该怎么走。cmdlib或OPTPASE应用程序(或其他库)是否支持我所寻找的内容?或者我应该恢复到手工制作的解析器吗?

我想您可以使用我的库来实现这一点。子命令功能与您要查找的命令标志解析行为完全匹配

在两个不相交的选项集之间共享子命令会有点棘手,但是助手类型类应该能够做到这一点。粗略示例代码:

-- A type for options shared between CLI and interactive modes.
data CommonOptions = CommonOptions
  {  optSomeOption :: Bool
  }
instance Options CommonOptions where ...

-- A type for options only available in CLI mode (such as --version or --config-file)
data CliOptions = CliOptions
  { common :: CommonOptions
  , version :: Bool
  , configFile :: String
  }
instance Options CliOptions where ...

-- if a command takes only global options, it can use this subcommand option type.
data NoOptions = NoOptions

instance Options NoOptions where
  defineOptions = pure NoOptions

-- typeclass to let commands available in both modes access common options
class HasCommonOptions a where
  getCommonOptions :: a -> CommonOptions
instance HasCommonOptions CommonOptions where
  getCommonOptions = id
instance HasCommonOptions CliOptions where
  getCommonOptions = common

commonCommands :: HasCommonOptions a => [Subcommand a (IO ())]
commonCommands = [... {- your commands here -} ...]

cliCommands :: HasCommonOptions a => [Subcommand a (IO ())]
cliCommands = commonCommands ++ [cmdRepl]

interactiveCommands :: HasCommonOptions a => [Subcommand a (IO ())]
interactiveCommands = commonCommands ++ [cmdQuit]

cmdRepl :: HasCommonOptions a => Subcommand a (IO ())
cmdRepl = subcommand "repl" $ \opts NoOptions -> do
  {- run your interactive REPL here -}

cmdQuit :: Subcommand a (IO ())
cmdQuit = subcommand "quit" (\_ NoOptions -> exitSuccess)
我怀疑像
runSubcommand
这样的助手函数不够专业化,因此在从REPL提示符拆分输入字符串后,您需要使用
parseSubcommand
调用解析器。这些文档提供了如何检查已解析选项的示例,包括检查用户是否请求帮助


选项解析器本身不会打印任何输出,但可能很难国际化默认类型解析器生成的错误消息。请告诉我是否有任何对库的更改会有所帮助。

base中有一个非常简单的命令行解析工具:。如果将选项作为列表提供给,则可以有3个列表:一个用于通用命令,一个用于REPL,一个用于CL
GetOpts
不会崩溃,它会返回错误消息,我认为任何好的库都应该这样做。它也不做任何打印,因为打印与命令行解析无关。在这里查看: