143 lines
4.6 KiB
Markdown
143 lines
4.6 KiB
Markdown
# 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
|
|
```
|