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.
|
||||
|
||||
## 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
|
||||
|
||||
```
|
||||
|
@ -14,14 +30,12 @@ end enum
|
|||
|
||||
given A
|
||||
fn some: (a: A) => Some[A]
|
||||
a => Some (a)
|
||||
Some (a)
|
||||
end fn
|
||||
```
|
||||
|
||||
## Example: The Either Type
|
||||
|
||||
TODO: Describe import behavior! Does importing Either import Left/Right?
|
||||
|
||||
```
|
||||
given L, R
|
||||
enum Either
|
||||
|
@ -30,12 +44,15 @@ enum Either
|
|||
|
||||
given R
|
||||
record Right (value: R)
|
||||
end enum
|
||||
|
||||
given L
|
||||
fn left: (left: L) => Either<L, Nothing> := l => Left(l)
|
||||
fn left: (left: L) => Either[L, Nothing]
|
||||
Left(left)
|
||||
end fn
|
||||
|
||||
given R
|
||||
fn right: (right: R) => Either<Nothing, R> := Right(r)
|
||||
fn right: (right: R) => Either[Nothing, R]
|
||||
Right(right)
|
||||
end fn
|
||||
```
|
||||
|
|
|
@ -5,18 +5,15 @@ that will produce a _value_ when evaluated.
|
|||
|
||||
## Syntax
|
||||
|
||||
Most non-[Definition](definitions.md) code is considered an expression.
|
||||
Expressions include:
|
||||
Functions contain expressions. Expressions take the form of:
|
||||
|
||||
- Literals
|
||||
- Variables
|
||||
- Literal Values
|
||||
- Variable Definitions
|
||||
- Variable References
|
||||
- Function Calls
|
||||
- Control Expressions
|
||||
- Control Structures
|
||||
|
||||
In general, using a Literal or a Variable for an expression wraps that value in
|
||||
a `pure` function that returns the value when evaluated.
|
||||
|
||||
## Control Expressions
|
||||
## Control Structures
|
||||
|
||||
### If Then
|
||||
|
||||
|
@ -28,18 +25,76 @@ is evaluated. Otherwise the `else` expression is evaluated.
|
|||
if <boolean expr> then <expr> else <expr>
|
||||
```
|
||||
|
||||
### Do Yield
|
||||
|
||||
TODO: This is incomplete
|
||||
|
||||
The `do/yield` expression allows for imperative composition of monadic
|
||||
expressions.
|
||||
### Match
|
||||
|
||||
```
|
||||
do
|
||||
x <- foo()
|
||||
y <- bar()
|
||||
_ <- baz()
|
||||
yield
|
||||
x + y
|
||||
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
|
||||
x <- foo()
|
||||
y <- bar()
|
||||
_ <- baz()
|
||||
return
|
||||
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
|
||||
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
|
||||
```
|
||||
|
||||
Value bindings are used for all such occurrences. This includes:
|
||||
|
||||
- [Defining Variables](variables.md)
|
||||
- [Instantiating Records](records.md)
|
||||
|
||||
## Comments
|
||||
|
||||
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
|
||||
```
|
||||
|
||||
- Code documentation respects Markdown.
|
||||
- TODO: Link syntax.
|
||||
- TODO: Supported definitions (example for each)
|
||||
- TODO: Parameter documentation
|
||||
## Block Definitions
|
||||
|
||||
All block definitions are closed by a companion `end` keyword that refers to the
|
||||
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
|
||||
infix -> (fa: F[A], f: (A) => B) => F[B] :=
|
||||
map (fa) (f)
|
||||
infix ->: (fa: F[A], f: (A) => B) => F[B]
|
||||
map (fa) (f)
|
||||
end infix
|
||||
```
|
||||
|
||||
```
|
||||
|
@ -31,3 +32,12 @@ Infix operators for numeric operations are defined for tuples of size one.
|
|||
```
|
||||
(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_:
|
||||
|
||||
- Any reserved keyword
|
||||
- Any reserved keyword (in total)
|
||||
- Any reserved symbol or operator (in total)
|
||||
- Any whitespace character
|
||||
- `.`
|
||||
- `:`
|
||||
- `=`
|
||||
- `"` or `'`
|
||||
- `"`
|
||||
- `,`
|
||||
- `\`
|
||||
- `[` or `]`
|
||||
- `(` or `)`
|
||||
|
||||
|
@ -20,3 +21,11 @@ Names are UTF-8 strings. The following values are _excluded_:
|
|||
- Functions use `lower_snake_case`
|
||||
- Generic Types use `UpperCamelCase` but prefer single letters such as `A`.
|
||||
- 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.
|
||||
|
||||
```
|
||||
<name>[.<name>]*
|
||||
namespace foo.bar.baz
|
||||
```
|
||||
|
||||
```
|
||||
[export] namespace <name>[.<name>]*
|
||||
```
|
||||
|
||||
- At least one name MUST be specified.
|
||||
- CANNOT contain more than one `.` character in a row.
|
||||
- CANNOT begin with `.` character.
|
||||
- CANNOT end with `.` character.
|
||||
- CANNOT use a [Reserved Name](#reserved-names).
|
||||
- CANNOT start with a [Reserved Name](#reserved-names).
|
||||
|
||||
### 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
|
||||
used:
|
||||
|
||||
- `language`
|
||||
- `ava`
|
||||
- `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
|
||||
|
||||
Each namespace MAY _export_ defintions using the `export` keyword. If some
|
||||
definition is exported, it may be [imported](#imports) into another namespace.
|
||||
Definitions are NOT exported by default -- it is an opt-in process. As noted in
|
||||
the [Definitions](definitions.md) documentation, the `export` keyword may be
|
||||
used at the beginning of _any_ definition.
|
||||
- Each file MAY _export_ definitions using the `export` keyword.
|
||||
- If the `export` keyword is used at the beginning of the namespace declaration,
|
||||
all definitions in the file are exported.
|
||||
- Otherwise, definitions may be individually exported by prefixing them with the
|
||||
`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
|
||||
|
||||
|
@ -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
|
||||
scope.
|
||||
|
||||
### Syntax
|
||||
### Import Syntax
|
||||
|
||||
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
|
||||
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.
|
||||
some alternative name using the `as` keyword. An import may refer to a specific
|
||||
namespace or it may refer to some specific definition within a namespace.
|
||||
|
||||
```
|
||||
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
|
||||
|
||||
```
|
||||
import collections.NonEmptyList as NEL
|
||||
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>
|
||||
...
|
||||
end match
|
||||
```
|
||||
|
||||
## The Default Case
|
||||
|
@ -21,9 +22,11 @@ to only match a partial set of possible values:
|
|||
TODO: WIP gotta figure out functions.
|
||||
|
||||
```
|
||||
fn example: String => Int32 is
|
||||
str => match str
|
||||
fn example: (str: String) => Int32
|
||||
match str
|
||||
case "foo" => 1
|
||||
case "bar" => 2
|
||||
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:
|
||||
|
||||
```
|
||||
record Foo[A, B] (x: A, y: B)
|
||||
given A, B
|
||||
record Foo (x: A, y: B)
|
||||
```
|
||||
|
||||
## Instantiating Records
|
||||
|
@ -67,11 +68,7 @@ let foo := Foo("foo", 1)
|
|||
let bar := foo.x
|
||||
```
|
||||
|
||||
Note that because records are just tuples, tuple syntax continues to work:
|
||||
|
||||
```
|
||||
let baz: Int32 := foo._2
|
||||
```
|
||||
Tuple syntax is _not_ supported on records.
|
||||
|
||||
## Tuple Interactions
|
||||
|
||||
|
@ -95,7 +92,28 @@ let some_tuple := ("foo", 1)
|
|||
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
|
||||
|
||||
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
|
||||
|
||||
- [Keywords](keywords.md)
|
||||
- [Operators & Symbols](operators-symbols.md)
|
||||
- [Names](names.md)
|
||||
- [Namespaces](namespaces.md)
|
||||
- [Exports](namespaces.md#exports)
|
||||
- [Imports](namespaces.md#imports)
|
||||
- [Definitions](definitions.md)
|
||||
- [General Syntax](general-syntax.md)
|
||||
- [Expressions](expressions.md)
|
||||
- [Standard Types](standard-types.md)
|
||||
- [Values](values.md)
|
||||
- [Constants](constants.md)
|
||||
- [Arrays](arrays.md)
|
||||
- [Lists](lists.md)
|
||||
- [Variables](variables.md)
|
||||
- [Effects](effects.md)
|
||||
- [Tuples](tuples.md)
|
||||
- [Records](records.md)
|
||||
- [Enumerations](enumerations.md)
|
||||
- [Types](types.md)
|
||||
- [Type Aliases](type-aliases.md)
|
||||
- [Type Classes](type-classes.md)
|
||||
- [Enumerations](enumerations.md)
|
||||
- [Type Unions](type-unions.md)
|
||||
- [Pattern Matching](pattern-matching.md)
|
||||
- [Functions](functions.md)
|
||||
- [Infix Operators](infix-operators.md)
|
||||
- [Recursion](recursion.md)
|
||||
- [Strings](strings.md)
|
||||
- [Tuples](tuples.md)
|
||||
- [Memory Management](memory-management.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)
|
||||
- [Standard Types](standard-types.md)
|
||||
- [Standard Type Classes](standard-type-classes.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 z := ("foo", 1)
|
||||
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
|
||||
|
@ -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
|
||||
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
|
||||
|
||||
Each tuple member is _indexed_ and can be directly accessed via a property of
|
||||
|
@ -68,4 +62,14 @@ let z :=
|
|||
match w
|
||||
case ("foo", _, x) => x
|
||||
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
|
||||
|
||||
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 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
|
||||
|
||||
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