Appearance
Values & Functions
At the top level, AIVI keeps values and functions separate:
valuedeclares a named constant expressionfuncdeclares a named pure function
That split keeps intent obvious in larger modules and matches the current surface language directly.
Values
A value binds a name to a single expression:
aivi
value answer : Int = 42
value greeting : Text = "Hello"
value isReady : Bool = TrueType annotations are optional when the compiler can infer them, but they are useful in public modules and documentation.
Values can refer to earlier values:
aivi
value width : Int = 24
value height : Int = 20
value cellCount : Int = width * heightValues can also hold records and lists:
aivi
type BoardSize = {
width: Int,
height: Int
}
value boardSize : BoardSize = {
width: 24,
height: 20
}
value checkpoints : List Int = [
4,
8,
12
]Functions
A func declaration names a pure function:
aivi
type Int -> Int -> Int
func add = x y =>
x + y
value total = add 3 4Function signatures live on a preceding type line, and the func header keeps parameters unannotated.
aivi
type Text -> Text
func greet = name =>
"Hello, {name}!"
value greetingText = greet "Ada"Multiple parameters
Parameters are separated by spaces, not commas:
aivi
type Int -> Int -> Int -> Bool
func between = low high n =>
n >= low and n <= high
value scoreAllowed = between 0 100 42Multi-line bodies
Function bodies are still just expressions, so multi-line definitions usually lean on pipes:
aivi
type Int -> Text
func describeScore = . >= 50
T|> "good"
F|> "keep going"
value scoreLabel = describeScore 88Unary subject sugar
When a unary function starts from its argument directly, you can omit the explicit parameter and use . as the implicit subject:
aivi
type Text -> Text
func trimStatus = .
||> " ready " -> "ready"
||> _ -> .The same shorthand works for subject projections and text interpolation:
aivi
type GameState -> Text
func statusLineFor = .status
type Int -> Text
func scoreLineFor = "Score: {.}"If the unary input is intentionally ignored, write _ => ... explicitly:
aivi
type Int -> Text
func constantLabel = _ =>
"ready"Calling functions
Call a function by writing the function name followed by its arguments:
aivi
type Int -> Int -> Int
func area = width height =>
width * height
value roomArea = area 5 8If an argument is itself an expression, wrap it in parentheses:
aivi
type Int -> Int -> Int
func area = width height =>
width * height
value adjustedArea = area (2 + 3) (4 * 2)That includes negative literals in call position, for example abs (-3) rather than abs -3.
Partial application
Functions can be partially applied. Supplying fewer arguments returns another function:
aivi
type Int -> Int -> Int
func multiply = left right =>
left * right
value double = multiply 2
value ten = double 5Named helpers instead of inline lambdas
For examples and playground-friendly snippets, prefer a named helper over an inline anonymous function:
aivi
type Text -> Text
func trimStatus = .
||> " ready " -> "ready"
||> _ -> .
type Text -> Text
func decorateStatus = status =>
"[{status}]"
value shownStatus = " ready "
|> trimStatus
|> decorateStatusThat style gives each step a reusable name and stays inside the current language surface.
Structural patches
Use <| to produce an updated value without mutating the original:
aivi
type User = {
name: Text,
isAdmin: Bool
}
value user : User = {
name: "Ada",
isAdmin: False
}
value promoted : User =
user <| {
name: "Grace",
isAdmin: True,
}patch { ... } builds a reusable same-shape update function:
aivi
value promote : (User -> User) =
patch {
isAdmin: True,
}Selectors are relative to the current focus:
- record roots accept either
fieldor.<field>; nested field steps still use dots, as inprofile.name [*]traversesListelements orMapvalues[predicate]filtersListelements["key"]or[.key == "id-1"]selectsMapentries
Inside patch predicates, use dot-prefixed projections such as .active, .price, .key, and .value.
The current checked slice also accepts constructor focus through Some, Ok, Err, Valid, Invalid, and same-module constructors with exactly one payload field.
:= stores a function value as data instead of applying it during patch execution.
aivi
type Int -> Int
func increment = n =>
n + 1
type Counter = {
step: Int -> Int
}
value keepCounter : (Counter -> Counter) =
patch {
step: := increment,
}Structural removal syntax (field: -) removes a field from the result type. See Record Patterns § Patch removal for details.
Type annotations
Both value and func use : for type annotations:
aivi
value count : Int = 0
type Int -> Int
func negate = n =>
0 - nSummary
| Form | Example |
|---|---|
| Value | value answer : Int = 42 |
| Function | type Int -> Int -> Int / func add = x y => x + y |
| Function call | add 3 4 |
| Partial application | value double = multiply 2 |
| Patch apply | `value promoted = user < |