Tons of work. Greater degree of consistency at this point. Main language is mostly reasonable.

This commit is contained in:
Pat Garrity 2024-01-28 22:01:12 -06:00
parent 218647484d
commit e9c6b3a39b
Signed by: pfm
GPG key ID: 5CA5D21BAB7F3A76
21 changed files with 735 additions and 120 deletions

30
arrays.md Normal file
View 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.

View file

@ -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)

View file

@ -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
``` ```

View file

@ -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.
``` ```
do 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() 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)
``` ```

View file

@ -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.

View file

@ -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
```

View file

@ -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
View 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
View 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.

View file

@ -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.

View file

@ -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
View 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>&#124;</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>&#124;&#124;</code> | Logical OR |

View file

@ -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
``` ```

View file

@ -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
View 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
View 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)

View file

@ -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)

View file

@ -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
``` ```

View file

@ -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
```

View file

@ -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")
```

View file

@ -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
```