Tons of work. Greater degree of consistency at this point. Main language is mostly reasonable.
This commit is contained in:
parent
218647484d
commit
e9c6b3a39b
21 changed files with 735 additions and 120 deletions
30
arrays.md
Normal file
30
arrays.md
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
# Arrays
|
||||||
|
|
||||||
|
Arrays are a standard Ava type. An array is a contiguous block of memory that
|
||||||
|
represents some grouping of a type.
|
||||||
|
|
||||||
|
```
|
||||||
|
let x: Array[Int32] := { 1, 2, 3 }
|
||||||
|
let zero: Array[Int32] := {}
|
||||||
|
let size: Int32 := size(x)
|
||||||
|
let arr: Array[Int32] := fill(512, 0)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Type Class Support
|
||||||
|
|
||||||
|
- `Monad`
|
||||||
|
- `Show`
|
||||||
|
- `Eq`
|
||||||
|
|
||||||
|
## NonEmptyList
|
||||||
|
|
||||||
|
The type `NonEmptyList` is a list which cannot be empty:
|
||||||
|
|
||||||
|
```
|
||||||
|
given A
|
||||||
|
record NonEmptyList: (head: A, tail: List[A])
|
||||||
|
```
|
||||||
|
|
||||||
|
## Indexing
|
||||||
|
|
||||||
|
Lists cannot be accessed by index.
|
|
@ -1,29 +0,0 @@
|
||||||
# Definitions
|
|
||||||
|
|
||||||
_Definitions_ are Ava constructs that may live at the top level within some
|
|
||||||
namespace. [Functions](functions.md) in particular may _also_ live within type
|
|
||||||
class (and instance) definitions.
|
|
||||||
|
|
||||||
## Syntax
|
|
||||||
|
|
||||||
All definitions adhere to the following syntax:
|
|
||||||
|
|
||||||
```
|
|
||||||
[export] <definition type> <name> <description> <body>
|
|
||||||
```
|
|
||||||
|
|
||||||
Each definition type ultimately controls the description and body. All
|
|
||||||
definition names adhere to standard [Name](names.md) rules.
|
|
||||||
|
|
||||||
## Supported Definition Types
|
|
||||||
|
|
||||||
TODO: This whole document... can go away? Need inventory of keywords.
|
|
||||||
|
|
||||||
- [`const`](constants.md)
|
|
||||||
- [`record`](records.md)
|
|
||||||
- [`type`](types.md)
|
|
||||||
- [`alias`](type-aliases.md)
|
|
||||||
- [`class`](type-classes.md)
|
|
||||||
- [`instance`](type-classes.md#instances)
|
|
||||||
- [`enum`](enumerations.md)
|
|
||||||
- [`fn`](functions.md)
|
|
|
@ -2,6 +2,22 @@
|
||||||
|
|
||||||
Enumerations are sum types.
|
Enumerations are sum types.
|
||||||
|
|
||||||
|
## Syntax
|
||||||
|
|
||||||
|
An enumeration must have at least one type member.
|
||||||
|
|
||||||
|
```
|
||||||
|
enum <name>
|
||||||
|
-- records or objects...
|
||||||
|
end enum
|
||||||
|
```
|
||||||
|
|
||||||
|
## Objects
|
||||||
|
|
||||||
|
An _object_ is a special type of singleton. Much like the `()` type, each object
|
||||||
|
is an instance of itself (and the only instance of itself). Objects are used to
|
||||||
|
represent enumeration cases that do not have any inputs.
|
||||||
|
|
||||||
## Example: The Option Type
|
## Example: The Option Type
|
||||||
|
|
||||||
```
|
```
|
||||||
|
@ -14,14 +30,12 @@ end enum
|
||||||
|
|
||||||
given A
|
given A
|
||||||
fn some: (a: A) => Some[A]
|
fn some: (a: A) => Some[A]
|
||||||
a => Some (a)
|
Some (a)
|
||||||
end fn
|
end fn
|
||||||
```
|
```
|
||||||
|
|
||||||
## Example: The Either Type
|
## Example: The Either Type
|
||||||
|
|
||||||
TODO: Describe import behavior! Does importing Either import Left/Right?
|
|
||||||
|
|
||||||
```
|
```
|
||||||
given L, R
|
given L, R
|
||||||
enum Either
|
enum Either
|
||||||
|
@ -30,12 +44,15 @@ enum Either
|
||||||
|
|
||||||
given R
|
given R
|
||||||
record Right (value: R)
|
record Right (value: R)
|
||||||
|
end enum
|
||||||
|
|
||||||
given L
|
given L
|
||||||
fn left: (left: L) => Either<L, Nothing> := l => Left(l)
|
fn left: (left: L) => Either[L, Nothing]
|
||||||
|
Left(left)
|
||||||
end fn
|
end fn
|
||||||
|
|
||||||
given R
|
given R
|
||||||
fn right: (right: R) => Either<Nothing, R> := Right(r)
|
fn right: (right: R) => Either[Nothing, R]
|
||||||
|
Right(right)
|
||||||
end fn
|
end fn
|
||||||
```
|
```
|
||||||
|
|
|
@ -5,18 +5,15 @@ that will produce a _value_ when evaluated.
|
||||||
|
|
||||||
## Syntax
|
## Syntax
|
||||||
|
|
||||||
Most non-[Definition](definitions.md) code is considered an expression.
|
Functions contain expressions. Expressions take the form of:
|
||||||
Expressions include:
|
|
||||||
|
|
||||||
- Literals
|
- Literal Values
|
||||||
- Variables
|
- Variable Definitions
|
||||||
|
- Variable References
|
||||||
- Function Calls
|
- Function Calls
|
||||||
- Control Expressions
|
- Control Structures
|
||||||
|
|
||||||
In general, using a Literal or a Variable for an expression wraps that value in
|
## Control Structures
|
||||||
a `pure` function that returns the value when evaluated.
|
|
||||||
|
|
||||||
## Control Expressions
|
|
||||||
|
|
||||||
### If Then
|
### If Then
|
||||||
|
|
||||||
|
@ -28,18 +25,76 @@ is evaluated. Otherwise the `else` expression is evaluated.
|
||||||
if <boolean expr> then <expr> else <expr>
|
if <boolean expr> then <expr> else <expr>
|
||||||
```
|
```
|
||||||
|
|
||||||
### Do Yield
|
### Match
|
||||||
|
|
||||||
TODO: This is incomplete
|
|
||||||
|
|
||||||
The `do/yield` expression allows for imperative composition of monadic
|
|
||||||
expressions.
|
|
||||||
|
|
||||||
```
|
```
|
||||||
|
match <expr>
|
||||||
|
case <pattern> => <expr>
|
||||||
|
end match
|
||||||
|
```
|
||||||
|
|
||||||
|
### Do/Return
|
||||||
|
|
||||||
|
The `do/return` expression allows for imperative composition of monadic
|
||||||
|
expressions. It works with any types that are members of `Monad` or `BiMonad`.
|
||||||
|
|
||||||
|
#### Do/Return for Monad
|
||||||
|
|
||||||
|
Each step of the `do` is defined by an expression that produces a Monad. The
|
||||||
|
syntax desugars to `fmap` calls, where `return` is a `map` call.
|
||||||
|
|
||||||
|
```
|
||||||
|
fn foo: () => Option[Int32]
|
||||||
|
1
|
||||||
|
end fn
|
||||||
|
|
||||||
|
fn bar: () => Option[Int32]
|
||||||
|
2
|
||||||
|
end fn
|
||||||
|
|
||||||
|
fn baz: () => Option[Int32]
|
||||||
|
3
|
||||||
|
end fn
|
||||||
|
|
||||||
|
let example: Option[Int32] :=
|
||||||
do
|
do
|
||||||
x <- foo()
|
x <- foo()
|
||||||
y <- bar()
|
y <- bar()
|
||||||
_ <- baz()
|
_ <- baz()
|
||||||
yield
|
return
|
||||||
x + y
|
x + y
|
||||||
|
end do
|
||||||
|
|
||||||
|
assert(example == Some(3))
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Do/Return for BiMonad
|
||||||
|
|
||||||
|
The `BiMonad` is right biased, where the "left" side is assumed to represent
|
||||||
|
some error case. The typical use case for this behavior is the `IO[E, A]` type.
|
||||||
|
|
||||||
|
```
|
||||||
|
fn foo: () => IO[String, Int32]
|
||||||
|
sync(1)
|
||||||
|
end fn
|
||||||
|
|
||||||
|
fn bar: () => IO[String, Int32]
|
||||||
|
sync(2)
|
||||||
|
end fn
|
||||||
|
|
||||||
|
fn baz: () => IO[String, Int32]
|
||||||
|
sync(3)
|
||||||
|
end fn
|
||||||
|
|
||||||
|
let program: IO[String, Int32] :=
|
||||||
|
do
|
||||||
|
x <- foo()
|
||||||
|
y <- bar()
|
||||||
|
_ <- baz()
|
||||||
|
return
|
||||||
|
x + y
|
||||||
|
end do
|
||||||
|
|
||||||
|
program ->
|
||||||
|
sum => assert(sum == 3)
|
||||||
```
|
```
|
||||||
|
|
13
functions.md
13
functions.md
|
@ -95,3 +95,16 @@ end fn
|
||||||
|
|
||||||
Note that this is equivalent to encoding a parameter as a synchronous effect and
|
Note that this is equivalent to encoding a parameter as a synchronous effect and
|
||||||
evaluating it to value when needed.
|
evaluating it to value when needed.
|
||||||
|
|
||||||
|
## Function Composition
|
||||||
|
|
||||||
|
```
|
||||||
|
given A, B, C
|
||||||
|
fn compose: (f: (B) => C, g: (A) => B) => (A) => C
|
||||||
|
x => f(g(x))
|
||||||
|
end fn
|
||||||
|
```
|
||||||
|
|
||||||
|
## Variable Length Argument Lists
|
||||||
|
|
||||||
|
This feature is explicitly not supported by Ava. Lists should be used instead.
|
||||||
|
|
|
@ -23,11 +23,6 @@ name := value
|
||||||
name: Type := value
|
name: Type := value
|
||||||
```
|
```
|
||||||
|
|
||||||
Value bindings are used for all such occurrences. This includes:
|
|
||||||
|
|
||||||
- [Defining Variables](variables.md)
|
|
||||||
- [Instantiating Records](records.md)
|
|
||||||
|
|
||||||
## Comments
|
## Comments
|
||||||
|
|
||||||
Comments are lines where the first non-whitespace characters are `--`. This was
|
Comments are lines where the first non-whitespace characters are `--`. This was
|
||||||
|
@ -52,7 +47,58 @@ definitions and have 3 `-` characters:
|
||||||
fn foo_bar: (x: String) => Int32
|
fn foo_bar: (x: String) => Int32
|
||||||
```
|
```
|
||||||
|
|
||||||
- Code documentation respects Markdown.
|
## Block Definitions
|
||||||
- TODO: Link syntax.
|
|
||||||
- TODO: Supported definitions (example for each)
|
All block definitions are closed by a companion `end` keyword that refers to the
|
||||||
- TODO: Parameter documentation
|
initating keyword.
|
||||||
|
|
||||||
|
```
|
||||||
|
fn foo: () => ()
|
||||||
|
()
|
||||||
|
end fn
|
||||||
|
|
||||||
|
given A
|
||||||
|
class Bar
|
||||||
|
fn foo2: () => ()
|
||||||
|
end class
|
||||||
|
|
||||||
|
instance Bar[A]
|
||||||
|
fn foo2: () => ()
|
||||||
|
()
|
||||||
|
end fn
|
||||||
|
end instance
|
||||||
|
|
||||||
|
enum Color
|
||||||
|
object Red
|
||||||
|
object Green
|
||||||
|
object Blue
|
||||||
|
end enum
|
||||||
|
|
||||||
|
fn control_if: () => ()
|
||||||
|
if 1 + 1 > 2 then
|
||||||
|
()
|
||||||
|
else if 2 + 2 > 4 then
|
||||||
|
()
|
||||||
|
else
|
||||||
|
()
|
||||||
|
end if
|
||||||
|
end fn
|
||||||
|
|
||||||
|
fn control_do: () => Option[Int32]
|
||||||
|
do
|
||||||
|
x <- Some(1)
|
||||||
|
y <- Some(2)
|
||||||
|
return x + y
|
||||||
|
end fn
|
||||||
|
|
||||||
|
fn control_match: () => Int32
|
||||||
|
match "foo"
|
||||||
|
case "foo" => 1
|
||||||
|
case _ => 0
|
||||||
|
end match
|
||||||
|
end fn
|
||||||
|
|
||||||
|
infix plus: (left: Int32, right: Int32) => Int32
|
||||||
|
left + right
|
||||||
|
end infix
|
||||||
|
```
|
||||||
|
|
|
@ -4,8 +4,9 @@ Example of defining `->` to do `map` for any functor:
|
||||||
|
|
||||||
```
|
```
|
||||||
given F[*] :: Functor, A, B
|
given F[*] :: Functor, A, B
|
||||||
infix -> (fa: F[A], f: (A) => B) => F[B] :=
|
infix ->: (fa: F[A], f: (A) => B) => F[B]
|
||||||
map (fa) (f)
|
map (fa) (f)
|
||||||
|
end infix
|
||||||
```
|
```
|
||||||
|
|
||||||
```
|
```
|
||||||
|
@ -31,3 +32,12 @@ Infix operators for numeric operations are defined for tuples of size one.
|
||||||
```
|
```
|
||||||
(12 - 2) / 2
|
(12 - 2) / 2
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Composition
|
||||||
|
|
||||||
|
```
|
||||||
|
given A, B, C
|
||||||
|
infix ∘: (f: B => C, g: A => B) => (A) => C
|
||||||
|
compose(f, g)
|
||||||
|
end infix
|
||||||
|
```
|
||||||
|
|
31
keywords.md
Normal file
31
keywords.md
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
# Keywords
|
||||||
|
|
||||||
|
- `type`
|
||||||
|
- `class`
|
||||||
|
- `alias`
|
||||||
|
- `const`
|
||||||
|
- `enum`
|
||||||
|
- `record`
|
||||||
|
- `object`
|
||||||
|
- `let`
|
||||||
|
- `mut`
|
||||||
|
- `export`
|
||||||
|
- `import`
|
||||||
|
- `namespace`
|
||||||
|
- `infix`
|
||||||
|
- `fn`
|
||||||
|
- `end`
|
||||||
|
- `match`
|
||||||
|
- `case`
|
||||||
|
- `if`
|
||||||
|
- `then`
|
||||||
|
- `else`
|
||||||
|
- `do`
|
||||||
|
- `return`
|
||||||
|
- `given`
|
||||||
|
- `true`
|
||||||
|
- `false`
|
||||||
|
|
||||||
|
TODO:
|
||||||
|
|
||||||
|
- Concurrency Stuff?
|
32
lists.md
Normal file
32
lists.md
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
# Lists
|
||||||
|
|
||||||
|
Lists are a standard Ava type. Specifically, `List[A]` represents a linked list.
|
||||||
|
|
||||||
|
```
|
||||||
|
let x: List[Int32] := { 1, 2, 3 }
|
||||||
|
let y := prepend(x, 0)
|
||||||
|
let z := append(x, { 4, 5 })
|
||||||
|
let w: Option[Int32] := head(x)
|
||||||
|
let tail: List[Int32] := tail(x)
|
||||||
|
let sz: List[Int32] := size(x)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Type Class Support
|
||||||
|
|
||||||
|
- `Monad`
|
||||||
|
- `Monoid`
|
||||||
|
- `Show`
|
||||||
|
- `Eq`
|
||||||
|
|
||||||
|
## NonEmptyList
|
||||||
|
|
||||||
|
The type `NonEmptyList` is a list which cannot be empty:
|
||||||
|
|
||||||
|
```
|
||||||
|
given A
|
||||||
|
record NonEmptyList: (head: A, tail: List[A])
|
||||||
|
```
|
||||||
|
|
||||||
|
## Indexing
|
||||||
|
|
||||||
|
Lists cannot be accessed by index.
|
17
names.md
17
names.md
|
@ -5,12 +5,13 @@ names, function names, etc.) follow the same rules.
|
||||||
|
|
||||||
Names are UTF-8 strings. The following values are _excluded_:
|
Names are UTF-8 strings. The following values are _excluded_:
|
||||||
|
|
||||||
- Any reserved keyword
|
- Any reserved keyword (in total)
|
||||||
|
- Any reserved symbol or operator (in total)
|
||||||
- Any whitespace character
|
- Any whitespace character
|
||||||
- `.`
|
- `.`
|
||||||
- `:`
|
- `"`
|
||||||
- `=`
|
- `,`
|
||||||
- `"` or `'`
|
- `\`
|
||||||
- `[` or `]`
|
- `[` or `]`
|
||||||
- `(` or `)`
|
- `(` or `)`
|
||||||
|
|
||||||
|
@ -20,3 +21,11 @@ Names are UTF-8 strings. The following values are _excluded_:
|
||||||
- Functions use `lower_snake_case`
|
- Functions use `lower_snake_case`
|
||||||
- Generic Types use `UpperCamelCase` but prefer single letters such as `A`.
|
- Generic Types use `UpperCamelCase` but prefer single letters such as `A`.
|
||||||
- Data Types, aliases, etc. use `UpperCamelCase`
|
- Data Types, aliases, etc. use `UpperCamelCase`
|
||||||
|
|
||||||
|
## Name Conflicts
|
||||||
|
|
||||||
|
- Variables may have the same names as functions.
|
||||||
|
- Functions/infix may _not_ share names. No overloaded functions.
|
||||||
|
- Type classes may declare members with the same name, but if some type has an
|
||||||
|
instance of each conflicting type class, names cannot be known without
|
||||||
|
qualification.
|
||||||
|
|
115
namespaces.md
115
namespaces.md
|
@ -9,14 +9,18 @@ Each namespace is an ordered, delimited, list of [names](names.md). Each name is
|
||||||
separated by the `.` character.
|
separated by the `.` character.
|
||||||
|
|
||||||
```
|
```
|
||||||
<name>[.<name>]*
|
namespace foo.bar.baz
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
[export] namespace <name>[.<name>]*
|
||||||
```
|
```
|
||||||
|
|
||||||
- At least one name MUST be specified.
|
- At least one name MUST be specified.
|
||||||
- CANNOT contain more than one `.` character in a row.
|
- CANNOT contain more than one `.` character in a row.
|
||||||
- CANNOT begin with `.` character.
|
- CANNOT begin with `.` character.
|
||||||
- CANNOT end with `.` character.
|
- CANNOT end with `.` character.
|
||||||
- CANNOT use a [Reserved Name](#reserved-names).
|
- CANNOT start with a [Reserved Name](#reserved-names).
|
||||||
|
|
||||||
### Examples
|
### Examples
|
||||||
|
|
||||||
|
@ -31,20 +35,49 @@ Any namespaces provided with a particular Ava distribution are considered
|
||||||
_reserved_. This means that, for example, the following namespaces cannot be
|
_reserved_. This means that, for example, the following namespaces cannot be
|
||||||
used:
|
used:
|
||||||
|
|
||||||
- `language`
|
- `ava`
|
||||||
- `collections`
|
- `collections`
|
||||||
|
|
||||||
## Language Namespace
|
## Ava Namespace
|
||||||
|
|
||||||
The `language` namespace is automatically imported into every Ava file.
|
The `Ava` namespace is automatically imported into every Ava file.
|
||||||
|
|
||||||
## Exports
|
## Exports
|
||||||
|
|
||||||
Each namespace MAY _export_ defintions using the `export` keyword. If some
|
- Each file MAY _export_ definitions using the `export` keyword.
|
||||||
definition is exported, it may be [imported](#imports) into another namespace.
|
- If the `export` keyword is used at the beginning of the namespace declaration,
|
||||||
Definitions are NOT exported by default -- it is an opt-in process. As noted in
|
all definitions in the file are exported.
|
||||||
the [Definitions](definitions.md) documentation, the `export` keyword may be
|
- Otherwise, definitions may be individually exported by prefixing them with the
|
||||||
used at the beginning of _any_ definition.
|
`export` keyword.
|
||||||
|
|
||||||
|
### Export Syntax
|
||||||
|
|
||||||
|
```
|
||||||
|
export fn foo: () => Int32
|
||||||
|
10
|
||||||
|
end fn
|
||||||
|
|
||||||
|
export enum Color
|
||||||
|
object Red
|
||||||
|
object Yellow
|
||||||
|
object Blue
|
||||||
|
end enum
|
||||||
|
|
||||||
|
export namespace foo.bar.baz
|
||||||
|
|
||||||
|
export class Something
|
||||||
|
fn foo: () => Int32
|
||||||
|
end class
|
||||||
|
```
|
||||||
|
|
||||||
|
### Exporting Enumerations
|
||||||
|
|
||||||
|
For some enumeration, if the `enum` is exported, that means that all members of
|
||||||
|
the enumeration are also exported.
|
||||||
|
|
||||||
|
### Exporting Type Classes
|
||||||
|
|
||||||
|
If some type class is exported, all enclosed functions are also exported.
|
||||||
|
|
||||||
## Imports
|
## Imports
|
||||||
|
|
||||||
|
@ -52,25 +85,67 @@ Imports immediately follow the namespace definition in each file. Each file may
|
||||||
have zero or more imports. Imports bring definitions from another namespace into
|
have zero or more imports. Imports bring definitions from another namespace into
|
||||||
scope.
|
scope.
|
||||||
|
|
||||||
### Syntax
|
### Import Syntax
|
||||||
|
|
||||||
Each import is a single, fully-qualified name. Imported names MAY be mapped to
|
Each import is a single, fully-qualified name. Imported names MAY be mapped to
|
||||||
some alternative name. An import may refer to a specific namespace or it may
|
some alternative name using the `as` keyword. An import may refer to a specific
|
||||||
refer to some specific definition within a namespace.
|
namespace or it may refer to some specific definition within a namespace.
|
||||||
|
|
||||||
TODO: Account for type classes. How can we easily import instances? One option
|
|
||||||
is to NOT do this. Ever. Just resolve EVERY possible `instance` during
|
|
||||||
compilation and make them available within the scope of the program. Global.
|
|
||||||
Very strict one-instance-per-thing side-effect, but could be useful.
|
|
||||||
|
|
||||||
```
|
```
|
||||||
import <namespace>[.<definition name>] [as <name>]
|
import <namespace>[.<definition name>|.*] [as <name>]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Importing Enumerations
|
||||||
|
|
||||||
|
Importing an enumeration does NOT import each member of the enumeration. Using
|
||||||
|
some example enumeration:
|
||||||
|
|
||||||
|
```
|
||||||
|
export enum Color
|
||||||
|
object Red
|
||||||
|
object Yellow
|
||||||
|
object Blue
|
||||||
|
end enum
|
||||||
|
```
|
||||||
|
|
||||||
|
The import and usage might be:
|
||||||
|
|
||||||
|
```
|
||||||
|
import foo.bar.baz.Color
|
||||||
|
|
||||||
|
let x: Color := Color.Red
|
||||||
|
```
|
||||||
|
|
||||||
|
Direct imports or `*` imports can bring members into direct scope:
|
||||||
|
|
||||||
|
```
|
||||||
|
import foo.bar.baz.Color
|
||||||
|
import foo.bar.baz.Color.*
|
||||||
|
|
||||||
|
let x: Color := Red
|
||||||
|
```
|
||||||
|
|
||||||
|
### Importing Type Classes
|
||||||
|
|
||||||
|
When a type class is imported, its functions (both defined and
|
||||||
|
instance-delegated) are made available and in scope for all types that satisfy
|
||||||
|
that type class. _All `instance`s for the imported type class are resolved and
|
||||||
|
made available_. Type class instances cannot be imported directly.
|
||||||
|
|
||||||
|
- Only one `instance` may exist per `class` per type.
|
||||||
|
- `instance` are globally resolved.
|
||||||
|
|
||||||
|
### Splat Imports
|
||||||
|
|
||||||
|
Splat imports, aka `*`, pull _everything_ from the given path into scope. This
|
||||||
|
means that all exported members are imported. Notably, this does NOT lift
|
||||||
|
enumeration members into scope.
|
||||||
|
|
||||||
### Examples
|
### Examples
|
||||||
|
|
||||||
```
|
```
|
||||||
import collections.NonEmptyList as NEL
|
import collections.NonEmptyList as NEL
|
||||||
import collections.Queue
|
import collections.Queue
|
||||||
import collections
|
import collections.*
|
||||||
|
import collections as colls
|
||||||
```
|
```
|
||||||
|
|
48
operators-symbols.md
Normal file
48
operators-symbols.md
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
# Operators & Symbols
|
||||||
|
|
||||||
|
## Language Level Symbols and Operators
|
||||||
|
|
||||||
|
These are reserved.
|
||||||
|
|
||||||
|
| Operator | Name |
|
||||||
|
| ------------------- | ---- |
|
||||||
|
| `:` | Bind Type to Name |
|
||||||
|
| `:=` | Bind Value to Name |
|
||||||
|
| `[...]` | Type Constructor |
|
||||||
|
| `(...)` | Tuple |
|
||||||
|
| `{...}` | List or Array |
|
||||||
|
| `--` | Comment |
|
||||||
|
| `---` | Docstring |
|
||||||
|
| `.` | Access Member or Numeric Literal. |
|
||||||
|
| `???` | Hole |
|
||||||
|
| `,` | Argument Separator |
|
||||||
|
| `=>` | Function Type Definition |
|
||||||
|
| `"..."` | String Literal |
|
||||||
|
| `*` | Type Constructor Argument |
|
||||||
|
| `\` | String Escape Sequence |
|
||||||
|
| `::` | Type Class Membership |
|
||||||
|
| `<-` | Do Binding |
|
||||||
|
| `_` | Anonymous Name |
|
||||||
|
| `@` | Object Metadata Reference |
|
||||||
|
| <code>|</code> | Type Union |
|
||||||
|
|
||||||
|
## Standard Library Operators (Infix)
|
||||||
|
|
||||||
|
These are _not_ reserved names, but are worth mentioning.
|
||||||
|
|
||||||
|
| Operator | Name |
|
||||||
|
| ------------------------- | ---- |
|
||||||
|
| `=` | Equals (Boolean) |
|
||||||
|
| `!=` | Not Equals (Boolean) |
|
||||||
|
| `+` | Addition |
|
||||||
|
| `-` | Subtraction |
|
||||||
|
| `/` | Division |
|
||||||
|
| `<` | Division |
|
||||||
|
| `>` | Division |
|
||||||
|
| `<=` | Division |
|
||||||
|
| `>=` | Division |
|
||||||
|
| `∘` | Function Composition |
|
||||||
|
| `∧` | Logical AND |
|
||||||
|
| `∨` | Logical OR |
|
||||||
|
| `&&` | Logical AND |
|
||||||
|
| <code>||</code> | Logical OR |
|
|
@ -11,6 +11,7 @@ match <expr>
|
||||||
case <pattern> => <expr>
|
case <pattern> => <expr>
|
||||||
case <pattern> => <expr>
|
case <pattern> => <expr>
|
||||||
...
|
...
|
||||||
|
end match
|
||||||
```
|
```
|
||||||
|
|
||||||
## The Default Case
|
## The Default Case
|
||||||
|
@ -21,9 +22,11 @@ to only match a partial set of possible values:
|
||||||
TODO: WIP gotta figure out functions.
|
TODO: WIP gotta figure out functions.
|
||||||
|
|
||||||
```
|
```
|
||||||
fn example: String => Int32 is
|
fn example: (str: String) => Int32
|
||||||
str => match str
|
match str
|
||||||
case "foo" => 1
|
case "foo" => 1
|
||||||
case "bar" => 2
|
case "bar" => 2
|
||||||
case _ => 3
|
case _ => 3
|
||||||
|
end match
|
||||||
|
end fn
|
||||||
```
|
```
|
||||||
|
|
32
records.md
32
records.md
|
@ -31,7 +31,8 @@ Records do _not_ need to be named.
|
||||||
Records may have generically typed data, and accept a type constructor:
|
Records may have generically typed data, and accept a type constructor:
|
||||||
|
|
||||||
```
|
```
|
||||||
record Foo[A, B] (x: A, y: B)
|
given A, B
|
||||||
|
record Foo (x: A, y: B)
|
||||||
```
|
```
|
||||||
|
|
||||||
## Instantiating Records
|
## Instantiating Records
|
||||||
|
@ -67,11 +68,7 @@ let foo := Foo("foo", 1)
|
||||||
let bar := foo.x
|
let bar := foo.x
|
||||||
```
|
```
|
||||||
|
|
||||||
Note that because records are just tuples, tuple syntax continues to work:
|
Tuple syntax is _not_ supported on records.
|
||||||
|
|
||||||
```
|
|
||||||
let baz: Int32 := foo._2
|
|
||||||
```
|
|
||||||
|
|
||||||
## Tuple Interactions
|
## Tuple Interactions
|
||||||
|
|
||||||
|
@ -95,7 +92,28 @@ let some_tuple := ("foo", 1)
|
||||||
let foo: Foo := some_tuple
|
let foo: Foo := some_tuple
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Records can be cast to tuples by extracting the tuple metadata from the record.
|
||||||
|
|
||||||
|
```
|
||||||
|
let foo := Foo("foo", 1)
|
||||||
|
let bar: (String, Int32) := @foo.tuple
|
||||||
|
```
|
||||||
|
|
||||||
|
TODO: Metdata is up in the air.
|
||||||
|
|
||||||
|
Records respect the tuple size metadata.
|
||||||
|
|
||||||
|
```
|
||||||
|
let size := @foo.size
|
||||||
|
```
|
||||||
|
|
||||||
|
Records provide field metadata.
|
||||||
|
|
||||||
|
```
|
||||||
|
let desc: RecordDescription := @foo.description
|
||||||
|
```
|
||||||
|
|
||||||
## Destructuring Records
|
## Destructuring Records
|
||||||
|
|
||||||
Records can be _destructured_ via [pattern matching](pattern-matching.md)
|
Records can be _destructured_ via [pattern matching](pattern-matching.md)
|
||||||
capabilities. This can take two possible forms.
|
capabilities.
|
||||||
|
|
158
standard-type-classes.md
Normal file
158
standard-type-classes.md
Normal file
|
@ -0,0 +1,158 @@
|
||||||
|
# Standard Type Classes
|
||||||
|
|
||||||
|
```
|
||||||
|
--- Associative binary operation.
|
||||||
|
--- **Associative**: `combine(x, combine(y, z)) = combine(combine(x, y), z)`
|
||||||
|
given A
|
||||||
|
class Semigroup
|
||||||
|
fn combine(x: A, y: A): A
|
||||||
|
end class
|
||||||
|
|
||||||
|
--- **Empty Identity**: `combine(x, empty()) = combine(empty(), x) = x`
|
||||||
|
given A :: Semigroup
|
||||||
|
class Monoid
|
||||||
|
fn empty() => A
|
||||||
|
end class
|
||||||
|
|
||||||
|
--- Type class for type constructors which can be mapped over.
|
||||||
|
---
|
||||||
|
--- ## Laws
|
||||||
|
---
|
||||||
|
--- **Composition**: `fa -> f -> g = fa -> (f ∘ g)`
|
||||||
|
--- **Identity**: `fa -> ((x) => x) = fa`
|
||||||
|
given F[*]
|
||||||
|
class Functor
|
||||||
|
--- Transform some wrapped data from one type to another, preserving the
|
||||||
|
--- wrapper.
|
||||||
|
---
|
||||||
|
--- @tparam A The type of input data.
|
||||||
|
--- @tparam B The type of output data.
|
||||||
|
--- @param fa The functor input.
|
||||||
|
--- @param f The function to transform data from `A` to `B`.
|
||||||
|
given [A, B]
|
||||||
|
fn map: (fa: F[A])(f: (A) => B) => F[B]
|
||||||
|
end class
|
||||||
|
|
||||||
|
-- Need Laws
|
||||||
|
given F[*] :: Functor
|
||||||
|
class Apply
|
||||||
|
given A, B
|
||||||
|
fn ap: (ff: F[(A) => B])(fa: F[A]) => F[B]
|
||||||
|
end class
|
||||||
|
|
||||||
|
-- Need Laws
|
||||||
|
given F[*] :: Apply
|
||||||
|
class Applicative
|
||||||
|
given A
|
||||||
|
fn pure: (value: A) => F[A]
|
||||||
|
|
||||||
|
fn unit: () => F[()]
|
||||||
|
pure(())
|
||||||
|
end fn
|
||||||
|
end class
|
||||||
|
|
||||||
|
--- Any Applicative satisfies Functor.
|
||||||
|
given F[*] :: Applicative
|
||||||
|
instance Functor[F]
|
||||||
|
given A, B
|
||||||
|
fn map: (fa: F[A])(f: (A) => B) => F[B]
|
||||||
|
ap(pure(f))(fa)
|
||||||
|
end fn
|
||||||
|
end instance
|
||||||
|
|
||||||
|
given F[*] :: Apply
|
||||||
|
class FlatMap
|
||||||
|
given A, B
|
||||||
|
fn fmap: (fa: F[A])(f: (A) => F[B]) => F[B]
|
||||||
|
|
||||||
|
given A
|
||||||
|
fn flatten: (ffa: F[F[A]]) => F[A]
|
||||||
|
fmap(ffa)((fa) => fa)
|
||||||
|
end fn
|
||||||
|
end class
|
||||||
|
|
||||||
|
given F[*] :: FlatMap, Applicative
|
||||||
|
class Monad
|
||||||
|
end class
|
||||||
|
|
||||||
|
--- Any Monad satisfies Functor.
|
||||||
|
--- Note for type class spec, must account for "override" precedence
|
||||||
|
given F[*] :: Applicative
|
||||||
|
instance Functor[F]
|
||||||
|
fn map: (fa: F[A])(f: (A) => B) => F[B]
|
||||||
|
fmap(fa)((a) => pure(f(a)))
|
||||||
|
end fn
|
||||||
|
end instance
|
||||||
|
|
||||||
|
given F[*, *]
|
||||||
|
class Bifunctor
|
||||||
|
def bimap[A, B, C, D](fab: F[A, B])(f: A => C, g: B => D): F[C, D]
|
||||||
|
|
||||||
|
given A, B, C, D
|
||||||
|
fn bimap(fab: F[A, B])(f: (A) => C, g: (B) => D) => F[C, D]
|
||||||
|
end class
|
||||||
|
|
||||||
|
given F[*] :: Functor
|
||||||
|
class CoFlatMap
|
||||||
|
given A, B
|
||||||
|
fn cofmap: (fa: F[A])(f: (F[A]) => B) => F[B]
|
||||||
|
|
||||||
|
given A
|
||||||
|
fn coflatten: (fa: F[A]) => F[F[A]]
|
||||||
|
cofmap(fa)((fa) => fa)
|
||||||
|
end fn
|
||||||
|
end class
|
||||||
|
|
||||||
|
given F[*] :: CoFlatMap
|
||||||
|
class CoMonad
|
||||||
|
given A
|
||||||
|
fn extract: (fa: F[A]) => A
|
||||||
|
end class
|
||||||
|
|
||||||
|
given A
|
||||||
|
class Show
|
||||||
|
fn show: (value: A) => String
|
||||||
|
end class
|
||||||
|
|
||||||
|
given A, B
|
||||||
|
class Eq
|
||||||
|
fn eq: (x: A, y: B) => Boolean
|
||||||
|
|
||||||
|
fn neq: (x: A, y: B) => Boolean
|
||||||
|
not(eq(x, y))
|
||||||
|
end fn
|
||||||
|
|
||||||
|
infix =: (x: A, y: B) => Boolean
|
||||||
|
eq(x, y)
|
||||||
|
end infix
|
||||||
|
|
||||||
|
infix !=: (x: A, y: B) => Boolean
|
||||||
|
neq(x, y)
|
||||||
|
end infix
|
||||||
|
end class
|
||||||
|
|
||||||
|
enum Comparison
|
||||||
|
object LessThan
|
||||||
|
object EqualTo
|
||||||
|
object GreaterThan
|
||||||
|
end enum
|
||||||
|
|
||||||
|
given A
|
||||||
|
class Compare
|
||||||
|
fn compare: (x: A, y: A) => Comparison
|
||||||
|
end class
|
||||||
|
|
||||||
|
given A
|
||||||
|
instance Eq[A, A]
|
||||||
|
fn eq: (x: A, y: A) => Boolean
|
||||||
|
match compare(x, y)
|
||||||
|
case EqualTo => true
|
||||||
|
case _ => false
|
||||||
|
end fn
|
||||||
|
end instance
|
||||||
|
|
||||||
|
given A
|
||||||
|
class HashCode
|
||||||
|
fn hash_code(data: A) => Int32
|
||||||
|
end class
|
||||||
|
```
|
20
standard-types.md
Normal file
20
standard-types.md
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
# Standard Types
|
||||||
|
|
||||||
|
`Byte`
|
||||||
|
`Boolean`
|
||||||
|
`Int8`
|
||||||
|
`UInt8`
|
||||||
|
`Int16`
|
||||||
|
`UInt16`
|
||||||
|
`Int32`
|
||||||
|
`UInt32`
|
||||||
|
`Int64`
|
||||||
|
`UInt64`
|
||||||
|
`Float32`
|
||||||
|
`Float64`
|
||||||
|
`BigInt`
|
||||||
|
`Decimal`
|
||||||
|
`String`
|
||||||
|
`(a, b, ...)` (Tuples)
|
||||||
|
`List[A]` (List of some type)
|
||||||
|
`Array[A]` (Array of some type)
|
|
@ -1,31 +1,33 @@
|
||||||
# Table of Contents
|
# Table of Contents
|
||||||
|
|
||||||
|
- [Keywords](keywords.md)
|
||||||
|
- [Operators & Symbols](operators-symbols.md)
|
||||||
- [Names](names.md)
|
- [Names](names.md)
|
||||||
- [Namespaces](namespaces.md)
|
- [Namespaces](namespaces.md)
|
||||||
- [Exports](namespaces.md#exports)
|
|
||||||
- [Imports](namespaces.md#imports)
|
|
||||||
- [Definitions](definitions.md)
|
|
||||||
- [General Syntax](general-syntax.md)
|
- [General Syntax](general-syntax.md)
|
||||||
- [Expressions](expressions.md)
|
- [Expressions](expressions.md)
|
||||||
|
- [Standard Types](standard-types.md)
|
||||||
- [Values](values.md)
|
- [Values](values.md)
|
||||||
- [Constants](constants.md)
|
- [Constants](constants.md)
|
||||||
|
- [Arrays](arrays.md)
|
||||||
|
- [Lists](lists.md)
|
||||||
- [Variables](variables.md)
|
- [Variables](variables.md)
|
||||||
- [Effects](effects.md)
|
- [Tuples](tuples.md)
|
||||||
- [Records](records.md)
|
- [Records](records.md)
|
||||||
|
- [Enumerations](enumerations.md)
|
||||||
- [Types](types.md)
|
- [Types](types.md)
|
||||||
- [Type Aliases](type-aliases.md)
|
- [Type Aliases](type-aliases.md)
|
||||||
- [Type Classes](type-classes.md)
|
- [Type Classes](type-classes.md)
|
||||||
- [Enumerations](enumerations.md)
|
|
||||||
- [Type Unions](type-unions.md)
|
- [Type Unions](type-unions.md)
|
||||||
|
- [Pattern Matching](pattern-matching.md)
|
||||||
- [Functions](functions.md)
|
- [Functions](functions.md)
|
||||||
|
- [Infix Operators](infix-operators.md)
|
||||||
|
- [Recursion](recursion.md)
|
||||||
- [Strings](strings.md)
|
- [Strings](strings.md)
|
||||||
- [Tuples](tuples.md)
|
|
||||||
- [Memory Management](memory-management.md)
|
- [Memory Management](memory-management.md)
|
||||||
- [Holes](holes.md)
|
- [Holes](holes.md)
|
||||||
- [Pattern Matching](pattern-matching.md)
|
|
||||||
- [Recursion](recursion.md)
|
|
||||||
- [Infix Operators](infix-operators.md)
|
|
||||||
- [Standard Library](standard-library.md)
|
|
||||||
- [Examples](examples.md)
|
- [Examples](examples.md)
|
||||||
- [Standard Types](standard-types.md)
|
- [Standard Type Classes](standard-type-classes.md)
|
||||||
- [Numeric Overflow](numeric-overflow.md)
|
- [Numeric Overflow](numeric-overflow.md)
|
||||||
|
- [Standard Library](standard-library.md)
|
||||||
|
- [Effects](effects.md)
|
||||||
|
|
24
tuples.md
24
tuples.md
|
@ -11,16 +11,6 @@ let x := ()
|
||||||
let y := ("foo")
|
let y := ("foo")
|
||||||
let z := ("foo", 1)
|
let z := ("foo", 1)
|
||||||
let w := ("foo", 1, true, 3.14)
|
let w := ("foo", 1, true, 3.14)
|
||||||
let a: Int32 := unwrap(1)
|
|
||||||
```
|
|
||||||
|
|
||||||
Unwrapping a tuple of size one is just the identity function:
|
|
||||||
|
|
||||||
```
|
|
||||||
given A
|
|
||||||
fn unwrap: (a: A) => A
|
|
||||||
a
|
|
||||||
end fn
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Type of a Standard Tuple
|
## Type of a Standard Tuple
|
||||||
|
@ -33,6 +23,10 @@ Consider the tuple `("foo", 1, true, 3.14)`. It has type
|
||||||
The type `()` has a single possible value, `()`. This is the empty tuple. It is
|
The type `()` has a single possible value, `()`. This is the empty tuple. It is
|
||||||
typically used as a token to indicate side-effects with no other useful output.
|
typically used as a token to indicate side-effects with no other useful output.
|
||||||
|
|
||||||
|
## Maximum Tuple Size
|
||||||
|
|
||||||
|
The largest tuple is of size `uint32_max` (a constant value).
|
||||||
|
|
||||||
## Accessing Tuple Members
|
## Accessing Tuple Members
|
||||||
|
|
||||||
Each tuple member is _indexed_ and can be directly accessed via a property of
|
Each tuple member is _indexed_ and can be directly accessed via a property of
|
||||||
|
@ -68,4 +62,14 @@ let z :=
|
||||||
match w
|
match w
|
||||||
case ("foo", _, x) => x
|
case ("foo", _, x) => x
|
||||||
case _ => false
|
case _ => false
|
||||||
|
end match
|
||||||
|
```
|
||||||
|
|
||||||
|
## Metadata
|
||||||
|
|
||||||
|
`size`: Type `UInt32`, denotes the tuple size.
|
||||||
|
|
||||||
|
```
|
||||||
|
let x: (Int32, Int32, Int32) := (1, 2, 3)
|
||||||
|
let y: UInt32 := @x.size
|
||||||
```
|
```
|
||||||
|
|
|
@ -1 +1,23 @@
|
||||||
# Type Aliases
|
# Type Aliases
|
||||||
|
|
||||||
|
An `alias` is an alternative name for some type. It is useful as either a local
|
||||||
|
rename or as a way to constrain types without overhead. An alias _cannot_ have a
|
||||||
|
type constructor.
|
||||||
|
|
||||||
|
The power of an alias comes from the fact that within the scope of the alias
|
||||||
|
definition, the alias and its bound type are treated as identical_.
|
||||||
|
|
||||||
|
```
|
||||||
|
alias Username := String
|
||||||
|
fn username: (candidate: String) => Either[InvalidUsername, Username]
|
||||||
|
-- do validation... and maybe it passes...
|
||||||
|
right(candidate)
|
||||||
|
end fn
|
||||||
|
|
||||||
|
instance Show[Username]
|
||||||
|
fn show: (value: Username) => String
|
||||||
|
value
|
||||||
|
end fn
|
||||||
|
end instance
|
||||||
|
end alias
|
||||||
|
```
|
||||||
|
|
34
values.md
34
values.md
|
@ -1 +1,35 @@
|
||||||
# Values
|
# Values
|
||||||
|
|
||||||
|
Values consist of literals and the results of expressions.
|
||||||
|
|
||||||
|
## Literals for Standard Types
|
||||||
|
|
||||||
|
`Boolean`: `let x: Boolean := true`
|
||||||
|
`Int8`: `let x: Int8 := 0`
|
||||||
|
`UInt8`: `let x: UInt8 := 0`
|
||||||
|
`Int16`: `let x: Int16 := 0`
|
||||||
|
`UInt16`: `let x: UInt16 := 0`
|
||||||
|
`Int32`: `let x: Int32 := 0`
|
||||||
|
`UInt32`: `let x: UInt32 := 0`
|
||||||
|
`Int64`: `let x: Int64 := 0`
|
||||||
|
`UInt64`: `let x: UInt64 := 0`
|
||||||
|
`Float32`: `let x: Float32 := 0.0`
|
||||||
|
`Float64`: `let x: Float64 := 0.0`
|
||||||
|
`BigInt`: `let x: BigInt := 9999999999999999999999999999999`
|
||||||
|
`Decimal`: `let x: Decimal := 9999999999999999999999999999999.9999999999999999`
|
||||||
|
`String`: `let x: String := "foo"`
|
||||||
|
`List[A]`: `let x: List[Int32] := {1, 2, 3}`
|
||||||
|
`Array[A]`: `let x: Array[Int32] := {1, 2, 3}`
|
||||||
|
|
||||||
|
### Numeric Literal Defaults
|
||||||
|
|
||||||
|
- If no type is specified, any integer is assumed to be `Int32`.
|
||||||
|
- If no type is specified, any floating point value is assumed to be `Float64`.
|
||||||
|
|
||||||
|
## Tuple Literals
|
||||||
|
|
||||||
|
The type will be inferred to `(Int32, Int32, String)`
|
||||||
|
|
||||||
|
```
|
||||||
|
let x := (1, 2, "foo")
|
||||||
|
```
|
||||||
|
|
17
variables.md
17
variables.md
|
@ -6,3 +6,20 @@
|
||||||
## Variable Names
|
## Variable Names
|
||||||
|
|
||||||
Please refer to [Names](names.md).
|
Please refer to [Names](names.md).
|
||||||
|
|
||||||
|
## Immutable Values
|
||||||
|
|
||||||
|
Most variables are immutable, and cannot be reassigned.
|
||||||
|
|
||||||
|
```
|
||||||
|
let x := 10
|
||||||
|
```
|
||||||
|
|
||||||
|
## Mutable Values
|
||||||
|
|
||||||
|
Mutation is supported within the scope of a function.
|
||||||
|
|
||||||
|
```
|
||||||
|
mut x := 10
|
||||||
|
x := 20
|
||||||
|
```
|
||||||
|
|
Loading…
Add table
Reference in a new issue