A command-line argument parsing library for Koka, inspired by Rust's clap.
- Flags — boolean switches with short (
-v) and long (--verbose) forms - Options — key-value arguments (
--sort=name,-S name) - Positional arguments — unnamed trailing arguments (
FILE...) - Positional validation —
.values(),.required, and.multipleenforced at parse time - Combined short flags —
-alRexpands to-a -l -R - Multiple values — collect repeated options into a list
- Allowed values — restrict an option to a set of choices
- Default values — fall back when an option is not supplied
- Auto-generated help —
--helpand--versionout of the box - Error handling — structured
klap-erroreffect for parse failures
Add klap as a git submodule in your project:
git submodule add https://github.com/cladam/klap.git lib/klapThen compile with -i pointing at the submodule:
koka -ilib/klap myapp.kkTo update klap later:
git submodule update --remote lib/klapImport the top-level klap module, which re-exports everything:
import klap
fun main()
val app = command("myapp")
.version("0.1.0")
.about("My awesome tool")
.arg(flag-short("verbose", 'v').help("Enable verbose output"))
.arg(option-short("output", 'o').value-name("FILE").help("Output file"))
.arg(positional("INPUT").multiple)
val m = app.parse-or-exit(get-args())
if m.get-flag("verbose") then
println("verbose mode on")
match m.get-one("output")
Just(f) -> println("writing to " ++ f)
Nothing -> println("writing to stdout")
m.get-positionals().foreach fn(p)
println("input: " ++ p)// Boolean flag: --all / -a
flag-short("all", 'a').help("show all entries")
// Long-only flag: --recursive
flag("recursive")
// Option with value: --sort <WORD> / -S <WORD>
option-short("sort", 'S')
.values(["name", "size", "time"])
.default-value("name")
.help("sort by WORD")
// Option that can be repeated: --ignore <PATTERN> / -I <PATTERN>
option-short("ignore", 'I')
.value-name("PATTERN")
.multiple
.help("ignore pattern")
// Positional argument (collects all trailing args)
positional("FILE").multiple
// Positional with allowed values and required
positional("COMMAND")
.values(["build", "run", "check", "clean", "help"])
.requiredval m : arg-matches = app.parse-or-exit(get-args())
m.get-flag("verbose") // bool
m.get-one("output") // maybe<string>
m.get-one-or("sort", "name") // string (with default)
m.get-many("ignore") // list<string>
m.get-positionals() // list<string> (flat list, all positionals)
m.get-one("COMMAND") // maybe<string> (positional by name)
m.get-many("FILE") // list<string> (multiple positional by name)
m.get-count("verbose") // int (number of occurrences)parse-or-exit prints an error message and exits on failure. For programmatic error handling, use the klap-error effect directly:
match try-klap({ app.parse(args) })
Right(m) -> // use matches
Left(msg) -> println("error: " ++ msg)MIT — see LICENSE for details.