ava/2026/a-slice-of-ava.md

4.6 KiB

A Slice of Ava

-- Modules are used to organize and distribute code.
module example

--{
Some syntax examples here:
    - Multi-line comments
    - `[]` used for complex type constructors (declaration)
    - `[]` used for complex type constructors (constructing the type)
    - `given` used to declare type constructors
    - `begin` used to start a block declaration
    - `class` used to denote a type class declaration
    - `,` (the comma character) used to distinguish enumerated elements
    - `fn` used to declare a function
    - `:` used to assign a type to some name
    - `->` used to define function types
    - `()` used for grouping
    - `end` used to signify the end of a block declaration.

These will appear over and over throughout this example.

Functions fundamentally accept one input and one output. The `->` syntax and
`()` application syntax work together:
    - `->` is left-associative
    - `(p1, p2, ... pk)` enumerates function arguments and provides a natural
      facade over single-argument functions.
    - partial function application is supported

Given some function `ex: A -> B -> C -> D`:
    - `ex(a, b)` produces a function `C -> D`
    - `ex(a, b, c)` produces a value of type `D`
    - `ex(a)(b)` first produces a function `B -> C -> D` which is then evaluted
      to produce a function `C -> D`.
}--
given F[*]
begin class Functor
    --{
    This is an example of function documentation.

    @given A The type of data being transformed.
    @given B The type of data being emitted.
    @param F[A] The input data.
    @param (A -> B) The transformation function.
    @return The transformed data.
    }--
    given A, B
    fn map: F[A] -> (A -> B) -> F[B]
end class

-- Boolean: The type for Boolean values in Ava
given A
begin class Eq
    fn eqv: A -> A -> Boolean
end class

--{
This section introduces new syntax:
    - `instance` used to declare a type class instance
    - `of` used to denote the type class being implemented
    - `for` used to denote the list of type arguments that satisfy the type
      class declaration.
    - `{}` used to express a function implementation.
    - pattern matching used to provide names to function arguments.
    - `=>` used to connect the matched pattern of a function implementation to
      the code body of the function.
    - `.` used to traverse hierarchical elements.

In this case, `.` is used to:
    - access the `list` module from the `std` module
    - access the `map` function from the `list` module
}--
begin instance of Functor for List
    given A, B
    begin fn map: List[A] -> (A -> B) -> List[B]
        { list, f => std.list.map(list, f) }
    end fn
end instance

--{
Record definitions in Ava are collections of named, typed, parameters.
    - Int32: The type for 32-bit integers in Ava.
}--
begin record Foo
    x: Int32,
    y: Int32,
end record

--{
More unique syntax:
    - Record names are types: `Foo`, in this case.
    - Infix functions: `==`, `&&`
      (These are part of the standard library).
}--
begin instance of Eq for Foo
    begin fn eqv: Foo -> Foo -> Boolean
        { foo1, foo2 => (foo1.x == foo2.x) && (foo1.y == foo2.y) }
    end fn
end instance

--{
This function begins to use what we have previously declared to do something
real.
    - `where` to express a type class dependency for some type
    - `requires` to express that the named type requires an instance of some type class.
    - `.` used to access `map` from the type class instance for Functor
    - `.` used to access `eqv` from the type class instance for Eq
    - `{}` used to define an _inline anonymous function_.

Note that type classes implicitly make their functions available to call for
some type that satisfies the first argument of the type class function. Type
classes can _also_ expose their functions by accessing the class directly.
}--
given F[*], A
where F requires Functor
where A requires Eq
begin fn ex1: F[A] -> A -> C[Boolean]
    { f, aa => f.map({ a => Eq[A].eqv(a, aa) }) }
end fn

-- `const` used to denote constant values at the top level.
const MagicNumber: Int32 = 2

--{
    - `def` used to declare arbitrary expressions
    - `let` used to assign (immutable) data to names
    - Constructing record instances by using the natural order
    - Constructing record instances by using named parameters
    - `[]` for first class list syntax.
    - Invoking a function.

`def` is not evaluated until it is invoked, and it is reevaluated every time it
is invoked.
}--
begin def demo: List[Boolean]
    let foo1 = Foo(1, MagicNumber)
    let foo2 = Foo(1, 3)
    let foo3 = Foo(x = 1, y = MagicNumbe)
    let stuff = [foo1, foo2]
    ex1(stuff, foo3)
end def