The Cli structure provides a combinator-style API for building command-line argument parsers.
datatype ('a, 'e) result = Ok of 'a | Err of 'eStandard result type for representing success or failure.
datatype 'a command = Command of 'a | Help of string | Version of stringRepresents the outcome of parsing:
Command config- Successfully parsed arguments into a configuration valueHelp text- User requested help (-hor--help)Version text- User requested version (-Vor--version)
datatype error =
UnknownOption of string
| MissingValue of string
| InvalidValue of {name: string, value: string, expected: string}
| MissingRequired of stringParse errors:
UnknownOption- Unrecognized flag or optionMissingValue- Option provided without a valueInvalidValue- Value doesn't match expected type (e.g., non-integer for int option)MissingRequired- Required positional argument missing
type 'a parser (* A parser being built with combinators *)
type 'a cli (* A finalized parser that can have subcommands *)val app : string -> string -> string -> 'a -> 'a parserCreate a new CLI application parser.
Parameters:
name- Application name (shown in help text)version- Version string (shown with--version)description- Short description (shown in help text)initFn- Initial value or curried function to receive parsed arguments
Example:
val parser = Cli.app "myapp" "1.0.0" "A sample application"
(fn verbose => fn output => {verbose = verbose, output = output})val cli : 'a parser -> 'a cliConvert a parser to a CLI. Required before adding subcommands or running.
Example:
val myCli = Cli.cli parserval parse : 'a cli -> string list -> ('a command, error) resultParse command-line arguments, returning a result for custom handling.
Example:
case Cli.parse myCli ["--verbose", "output.txt"] of
Cli.Ok (Cli.Command config) => (* use config *)
| Cli.Ok (Cli.Help text) => print text
| Cli.Ok (Cli.Version text) => print text
| Cli.Err e => Cli.die (Cli.errorToString e ^ "\n")val exec : ('a -> unit) -> 'a cli -> unitMain entry point that handles help, version, errors, and exit codes automatically. Reads arguments from CommandLine.arguments().
Example:
val () = Cli.exec (fn config => (* use config *)) myCliAll combinators use the pipe operator |> to chain onto a parser.
val flag : {long: string, short: char option, help: string}
-> (bool -> 'a) parser
-> 'a parserAdd a boolean flag. Defaults to false when not provided.
Parameters:
long- Long option name (used as--long)short- Optional short option character (used as-c)help- Help text description
Example:
Cli.app "myapp" "1.0.0" "desc" (fn v => v)
|> Cli.flag {long = "verbose", short = SOME #"v", help = "Enable verbose output"}val option : {long: string, short: char option, help: string,
placeholder: string, default: string}
-> (string -> 'a) parser
-> 'a parserAdd a string option with a default value.
Parameters:
long- Long option nameshort- Optional short option characterhelp- Help text descriptionplaceholder- Placeholder shown in help (e.g.,FILE)default- Default value when not provided
Example:
|> Cli.option {long = "output", short = SOME #"o", help = "Output file",
placeholder = "FILE", default = "out.txt"}val optionOpt : {long: string, short: char option, help: string,
placeholder: string}
-> (string option -> 'a) parser
-> 'a parserAdd an optional string option. Returns NONE when not provided.
Example:
|> Cli.optionOpt {long = "config", short = SOME #"c",
help = "Config file", placeholder = "FILE"}val optionInt : {long: string, short: char option, help: string,
placeholder: string, default: int}
-> (int -> 'a) parser
-> 'a parserAdd an integer option with a default value. Returns InvalidValue error for non-integer input.
Example:
|> Cli.optionInt {long = "count", short = SOME #"n", help = "Number of items",
placeholder = "NUM", default = 10}val optionIntOpt : {long: string, short: char option, help: string,
placeholder: string}
-> (int option -> 'a) parser
-> 'a parserAdd an optional integer option. Returns NONE when not provided.
Example:
|> Cli.optionIntOpt {long = "port", short = SOME #"p",
help = "Port number", placeholder = "PORT"}val positional : {name: string, help: string}
-> (string -> 'a) parser
-> 'a parserAdd a required positional argument. If not provided, shows help text automatically.
Parameters:
name- Argument name (shown in help as<name>)help- Help text description
Example:
|> Cli.positional {name = "input", help = "Input file to process"}val positionalOpt : {name: string, help: string}
-> (string option -> 'a) parser
-> 'a parserAdd an optional positional argument. Returns NONE when not provided.
Example:
|> Cli.positionalOpt {name = "output", help = "Output file (optional)"}val positionalList : {name: string, help: string}
-> (string list -> 'a) parser
-> 'a parserAdd a variadic positional argument that collects all remaining positional arguments into a list. Returns empty list when none provided.
Example:
|> Cli.positionalList {name = "files", help = "Input files"}val subcommand : {name: string, help: string, cmd: 'a parser}
-> 'a cli
-> 'a cliAdd a subcommand to a CLI. All subcommands must produce the same result type.
Parameters:
name- Subcommand namehelp- Short description for help listingcmd- Parser for the subcommand
Example:
datatype cmd = Add of string list | Status of bool
val addCmd = Cli.app "add" "" "Add files" (fn files => Add files)
|> Cli.positionalList {name = "files", help = "Files to add"}
val statusCmd = Cli.app "status" "" "Show status" (fn short => Status short)
|> Cli.flag {long = "short", short = SOME #"s", help = "Short format"}
val myCli = Cli.app "mygit" "1.0.0" "Git clone" (Status false)
|> Cli.cli
|> Cli.subcommand {name = "add", help = "Add files to staging", cmd = addCmd}
|> Cli.subcommand {name = "status", help = "Show repo status", cmd = statusCmd}val help : 'a cli -> stringGenerate help text for a CLI (includes subcommands if present).
val parserHelp : 'a parser -> stringGenerate help text for a parser (before conversion to CLI).
val errorToString : error -> stringConvert an error to a human-readable string.
Example:
Cli.errorToString (Cli.UnknownOption "--foo")
(* Returns: "error: unknown option '--foo'" *)val die : string -> 'aPrint a message to stderr and exit with failure status. Useful for error handling in CLI applications.
Example:
case Cli.parse myCli args of
Cli.Ok (Cli.Command config) => runApp config
| Cli.Ok (Cli.Help text) => print text
| Cli.Ok (Cli.Version text) => print text
| Cli.Err e => Cli.die (Cli.errorToString e ^ "\n")Options can be specified in multiple ways:
- Long form:
--option valueor--option=value - Short form:
-o valueor-o=value - Combined short flags:
-abcexpands to-a -b -c
--helpor-h- Shows help text--versionor-V- Shows version--- Stops option parsing; remaining args are treated as positionals
Options and positional arguments can be mixed in any order. The parser will correctly associate values with their respective options.
type config = {
verbose: bool,
output: string,
count: int,
input: string
}
val parser =
Cli.app "myapp" "1.0.0" "Process files with options"
(fn verbose => fn output => fn count => fn input =>
{verbose = verbose, output = output, count = count, input = input})
|> Cli.flag {long = "verbose", short = SOME #"v", help = "Enable verbose output"}
|> Cli.option {long = "output", short = SOME #"o", help = "Output file",
placeholder = "FILE", default = "out.txt"}
|> Cli.optionInt {long = "count", short = SOME #"n", help = "Number of iterations",
placeholder = "NUM", default = 1}
|> Cli.positional {name = "input", help = "Input file to process"}
val () = Cli.exec
(fn cfg =>
print ("Processing " ^ #input cfg ^
" with count=" ^ Int.toString (#count cfg) ^ "\n"))
(Cli.cli parser)Usage:
$ myapp input.txt
$ myapp -v --output=result.txt -n 5 input.txt
$ myapp --help