A functional-first scripting language with static typing
Static type inference with unification, occurs check, and generalized let-polymorphism for ints, bools, strings, functions, and data structures.
Haskell-like lambdas, `do { ... }` blocks, precedence, keywords, and multi-statement files with expression-only core.
User input with `input`, readable effect sequencing via `do` blocks, type conversions (`parseInt`, `toString`, `show`), and practical examples including text analysis, CLI tools, and interactive workflows.
588 passing examples with property-based testing, script evaluation, CLI coverage, stress checks, and example smoke coverage.
CLI with help, inline evaluation, file execution, --debug flag for development, and comprehensive documentation.
Import modules with `import ModuleName`, top-level definitions with `let` and `letrec`, mutual recursion support, circular import detection, explicit exports, and module resolution.
stack build && stack test
stack exec kai -- --help
stack exec kai -- -e "print (42 + 1)"
stack exec kai -- --debug -e "42 + 1"
stack exec kai -- path/to/script.kai
stack exec kai -- examples/text_analysis.kai
stack exec kai -- examples/calculator.kai
make install
export PATH="$HOME/.local/bin:$PATH"
kai tests/arithmetic.kai
42
-3
true
false
"hi"
()
+
-
*
/
++
==
<
>
and
or
not
if condition then expr1 else expr2
\\x -> x + 1
\\f -> f 42
let x = 42 in x + 1
do { print "hello"; 42 }
let _ = expensiveCall in 42
letrec factorial = \\n -> if n == 0 then 1 else n * (factorial (n - 1)) in factorial 5
let add : Int -> Int -> Int = \\x : Int -> \\y : Int -> x + y
parseInt "42"
toString 100
discard 42
show (42 + 3)
[1, 2, 3]
(1, "hi", true)
{a = 1, b = true}
Just 42
Left "error"
map filter foldl
length reverse take drop zip
split join trim replace strLength
head tail null fst snd
input
print "Hello"
readFile "path"
writeFile "path" "content"
args
do { print "A"; print "B"; 42 }
import TextAnalysis
let text = case args of [] -> "Kai examples should stay practical, typed, and honest." | path :: _ -> readFile path
let summary = summarize text
print ("Preview: " ++ summary.preview)
case summary.firstLongWord of Just word -> print ("First long word: " ++ word) | Nothing -> print "First long word: none"
let validateNames : [String] -> Either String [String] = \\cliArgs -> if null cliArgs then Left "Usage..." else Right cliArgs
letrec greetAll : [String] -> Unit = \\names -> case names of [] -> print "All greetings sent." | name :: rest -> do { print ("Hello, " ++ name ++ "!"); greetAll rest }
case validateNames args of Left message -> print message | Right names -> greetAll names
let report = {count = length numbers, evenCount = length (filter even numbers), total = foldl (\\acc -> \\n -> acc + n) 0 numbers, labels = zip numbers (map (\\n -> if n > 20 then "high" else "steady") numbers)}
let tag = \\label -> \\value -> {label = label, value = value}
show (tag "total" (report.total))
show (tag "status" "ready")
let parseSecret : [String] -> Int = \\cliArgs -> case cliArgs of value :: _ -> (case parseInt value of Just n -> n | Nothing -> 42) | [] -> 42
let promptGuess : Int -> String = \\attempt -> do { print ("Attempt " ++ toString attempt ++ ": enter a guess"); input }
case parseInt guessText of Just guess -> ... | Nothing -> do { print "Please enter an integer."; loop secret attempt }
let outputPath = case args of path :: _ -> path | [] -> "kai_output.txt"
let content = join "\n" ["Kai writes files", "Kai reads them back", "Kai keeps scripts typed"]
do { writeFile outputPath content; print ("Wrote " ++ outputPath) }
print ("Read back: " ++ replace "\n" " | " (readFile outputPath))
case Right {ok = true, message = "loaded"} of Right {ok = true, message = _} -> "status: success" | Left _ -> "status: failure" | Right _ -> "status: unexpected"
case (42, "kai", true) of (_, name, true) -> "tuple for " ++ name | _ -> "tuple mismatch"
case [1, 2, 3, 4] of _ :: _ -> "list has values" | [] -> "list is empty"
1 + true
// Type error: TypeMismatch TInt TBool
if 5 then 1 else 2
// Type error: ExpectedBool TInt
Ints, bools, strings (with ++), arithmetic (with unary minus), comparisons, conditionals
First-class functions, closures, application
String literals, concatenation, print statements, multi-statement files
Static type inference with unification and occurs check
Variable bindings and recursive function definitions with letrec
Optional type annotations, parseInt/toString/show functions, interactive I/O, wildcards, sequencing
Lists, tuples, records, pattern matching, Maybe/Either error handling
List functions (map, filter, fold, zip), string functions (split, join, trim), 27 built-ins
Module system with imports, top-level let/letrec definitions, mutual recursion support
readFile, writeFile, command-line arguments, practical scripting capabilities
REPL, custom data types, stronger pattern matching, and essential scripting stdlib work
Formatter, linter, IDE support, package manager, HTTP/JSON, and deeper optimization work