diff --git a/arrays.md b/arrays.md new file mode 100644 index 0000000..258bdab --- /dev/null +++ b/arrays.md @@ -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. diff --git a/definitions.md b/definitions.md deleted file mode 100644 index b84e758..0000000 --- a/definitions.md +++ /dev/null @@ -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] -``` - -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) diff --git a/enumerations.md b/enumerations.md index 44bd92d..ec40802 100644 --- a/enumerations.md +++ b/enumerations.md @@ -2,6 +2,22 @@ Enumerations are sum types. +## Syntax + +An enumeration must have at least one type member. + +``` +enum + -- 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 => Left(l) +fn left: (left: L) => Either[L, Nothing] + Left(left) end fn given R -fn right: (right: R) => Either := Right(r) +fn right: (right: R) => Either[Nothing, R] + Right(right) end fn ``` diff --git a/expressions.md b/expressions.md index 35a8c50..fd1c702 100644 --- a/expressions.md +++ b/expressions.md @@ -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 then else ``` -### 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 + case => +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) ``` diff --git a/functions.md b/functions.md index 997d53c..f064796 100644 --- a/functions.md +++ b/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. diff --git a/general-syntax.md b/general-syntax.md index 151205a..4ac691b 100644 --- a/general-syntax.md +++ b/general-syntax.md @@ -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 +``` diff --git a/infix-operators.md b/infix-operators.md index 3687078..24e9cfb 100644 --- a/infix-operators.md +++ b/infix-operators.md @@ -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 +``` diff --git a/keywords.md b/keywords.md new file mode 100644 index 0000000..34d0114 --- /dev/null +++ b/keywords.md @@ -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? diff --git a/lists.md b/lists.md new file mode 100644 index 0000000..f5448a3 --- /dev/null +++ b/lists.md @@ -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. diff --git a/names.md b/names.md index f0ef499..b94c3bd 100644 --- a/names.md +++ b/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. diff --git a/namespaces.md b/namespaces.md index 88d2f80..00d42a4 100644 --- a/namespaces.md +++ b/namespaces.md @@ -9,14 +9,18 @@ Each namespace is an ordered, delimited, list of [names](names.md). Each name is separated by the `.` character. ``` -[.]* +namespace foo.bar.baz +``` + +``` +[export] namespace [.]* ``` - 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 [.] [as ] +import [.|.*] [as ] ``` +### 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 ``` diff --git a/operators-symbols.md b/operators-symbols.md new file mode 100644 index 0000000..75e48c3 --- /dev/null +++ b/operators-symbols.md @@ -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 | +| | | 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 | +| || | Logical OR | diff --git a/pattern-matching.md b/pattern-matching.md index c0eddac..4d65b82 100644 --- a/pattern-matching.md +++ b/pattern-matching.md @@ -11,6 +11,7 @@ match case => case => ... +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 ``` diff --git a/records.md b/records.md index dc71430..2777877 100644 --- a/records.md +++ b/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. diff --git a/standard-type-classes.md b/standard-type-classes.md new file mode 100644 index 0000000..2b6121a --- /dev/null +++ b/standard-type-classes.md @@ -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 +``` diff --git a/standard-types.md b/standard-types.md new file mode 100644 index 0000000..8ba3fd4 --- /dev/null +++ b/standard-types.md @@ -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) diff --git a/table-of-contents.md b/table-of-contents.md index 78d84b7..298bcd1 100644 --- a/table-of-contents.md +++ b/table-of-contents.md @@ -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) diff --git a/tuples.md b/tuples.md index d44983b..4bcdecf 100644 --- a/tuples.md +++ b/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 ``` diff --git a/type-aliases.md b/type-aliases.md index d9dd816..3a1469e 100644 --- a/type-aliases.md +++ b/type-aliases.md @@ -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 +``` diff --git a/values.md b/values.md index 89a9695..360cc95 100644 --- a/values.md +++ b/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") +``` diff --git a/variables.md b/variables.md index bd062b0..7ced8c3 100644 --- a/variables.md +++ b/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 +```