Introduction
Welcome to The Halcyon Book, the official documentation for the Halcyon programming language. Halcyon is a compiled, strongly typed, functional programming language. It is compiled to WebAssembly, a portable binary format that can run in the browser.
Installation
IDE Setup
Visual Studio Code
TODO
Helix
In your Helix config folder (~/.config/helix/
by default), create languages.toml
if it does not already exist.
Add a grammar and language entry for Halcyon:
[[grammar]]
name = "halcyon"
source = { git = "https://git.lgatlin.dev/logan/tree-sitter-halcyon.git", rev = "main" }
[[language]]
name = "halcyon"
scope = "source.hc"
file-types = ["hc"]
grammar = "halcyon"
comment-tokens = ["--"]
block-comment-tokens = { start = "(*", end = "*)" }
Next, fetch and build the grammar. If this is your first time building grammars this will take several minutes.
helix -g fetch
helix -g build
Finally, download the highlight queries to your runtime directory:
mkdir -p ~/.config/helix/runtime/queries/halcyon
wget https://git.lgatlin.dev/logan/tree-sitter-halcyon/raw/branch/main/queries/highlights.scm \
-O ~/.config/helix/runtime/queries/halcyon/highlights.scm
Hello World
Time to write your first Halcyon program.
Create a file named main.hc
containing the following:
<span class='hljs-keyword'>module</span> hello_world =
<span class='hljs-keyword'>do</span> <span class='hljs-title class_'>std</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>println</span> <span class='hljs-string'>"Hello World!"</span>
<span class='hljs-keyword'>end</span>
Langauge Reference
Here you will find a description of the major features of the Halcyon langauge.
Anatomy of a program
Lets examine a Halcyon program piece by piece. Here is a Fizz Buzz program:
<span class='hljs-keyword'>module</span> example =
<span class='hljs-keyword'>let</span> fizzbuzz = <span class='hljs-keyword'>fn</span> <span class='hljs-params'>number</span> <span class='hljs-params'>max</span> <span class='hljs-keyword'>=></span>
<span class='hljs-punctuation'>(</span><span class='hljs-keyword'>match</span> <span class='hljs-punctuation'>(</span>number <span class='hljs-operator'>%</span> <span class='hljs-variable constant_'>3</span><span class='hljs-punctuation'>,</span> number <span class='hljs-operator'>%</span> <span class='hljs-variable constant_'>5</span><span class='hljs-punctuation'>)</span> <span class='hljs-keyword'>with</span>
| <span class='hljs-punctuation'>(</span><span class='hljs-variable constant_'>0</span><span class='hljs-punctuation'>,</span> <span class='hljs-variable constant_'>0</span><span class='hljs-punctuation'>)</span> <span class='hljs-keyword'>=></span> <span class='hljs-string'>"FizzBuzz"</span>
| <span class='hljs-punctuation'>(</span><span class='hljs-variable constant_'>0</span><span class='hljs-punctuation'>,</span> _<span class='hljs-punctuation'>)</span> <span class='hljs-keyword'>=></span> <span class='hljs-string'>"Fizz"</span>
| <span class='hljs-punctuation'>(</span>_<span class='hljs-punctuation'>,</span> <span class='hljs-variable constant_'>0</span><span class='hljs-punctuation'>)</span> <span class='hljs-keyword'>=></span> <span class='hljs-string'>"Buzz"</span>
| <span class='hljs-punctuation'>(</span>_<span class='hljs-punctuation'>,</span> _<span class='hljs-punctuation'>)</span> <span class='hljs-keyword'>=></span> <span class='hljs-title class_'>format</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>integer</span> number<span class='hljs-punctuation'>)</span>
<span class='hljs-operator'>|></span> <span class='hljs-title class_'>std</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>println</span><span class='hljs-punctuation'>;</span>
<span class='hljs-keyword'>if</span> number <span class='hljs-operator'><</span> max <span class='hljs-keyword'>then</span>
<span class='hljs-title function_'>fizzbuzz</span> <span class='hljs-punctuation'>(</span>number <span class='hljs-operator'>+</span> <span class='hljs-variable constant_'>1</span><span class='hljs-punctuation'>)</span> max
<span class='hljs-keyword'>else</span>
<span class='hljs-punctuation'>(</span><span class='hljs-punctuation'>)</span>
<span class='hljs-keyword'>do</span> <span class='hljs-title function_'>fizzbuzz</span> <span class='hljs-variable constant_'>1</span> <span class='hljs-variable constant_'>30</span>
<span class='hljs-keyword'>end</span>
Modules
A Halcyon source file contains one or more modules.
<span class='hljs-keyword'>module</span> example =
<span class='hljs-comment'>(* ... *)</span>
<span class='hljs-keyword'>end</span>
Modules contain four kinds of statements:
let
defines a variabledo
executes an expression (like amain
function)type
defines a new type, or type alias (described later)import
imports a function from another language, such as JavaScript or C
A module acts as a namespace.
To access a value or type from another module, the ::
symbol is used.
For example, std::println
refers to the println
function in the std
module.
Functions
Functions are a kind of expression.
They are defined using the syntax fn [parameters] => [body]
.
Here, a function is defined with two parameters number
and max
.
<span class='hljs-keyword'>let</span> fizzbuzz = <span class='hljs-keyword'>fn</span> <span class='hljs-params'>number</span> <span class='hljs-params'>max</span> <span class='hljs-keyword'>=></span>
The body of a function is a single expression after the =>
operator.
The functions return value is the value of this expression, there is no return
keyword.
The syntax for function calls is significantly different from other languages. If the argument to a function is a literal (numbers, strings, booleans, arrays, structures, etc), no parenthesis are required.
<span class='hljs-keyword'>do</span> <span class='hljs-title class_'>std</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>println</span> <span class='hljs-string'>"Hello World!"</span>
If an argument is an expression, it must be wrapped in parenthesis.
<span class='hljs-keyword'>do</span> <span class='hljs-title function_'>add_integers</span> <span class='hljs-punctuation'>(</span><span class='hljs-variable constant_'>5</span> <span class='hljs-operator'>-</span> <span class='hljs-variable constant_'>1</span><span class='hljs-punctuation'>)</span> <span class='hljs-variable constant_'>4</span>
An alternative way to call a function is with the |>
operator.
This operator calls a function on the right with an argument on the left.
<span class='hljs-keyword'>do</span> <span class='hljs-string'>"Hello World!"</span> <span class='hljs-operator'>|></span> <span class='hljs-title class_'>std</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>println</span>
It is even possible to combine both syntax.
The |>
operator has a lower precedence than a regular function call, so the argument to the left of it will come last.
<span class='hljs-keyword'>do</span> <span class='hljs-string'>"World!"</span>
<span class='hljs-operator'>|></span> <span class='hljs-title class_'>string</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>concatenate</span> <span class='hljs-string'>"Hello "</span>
<span class='hljs-comment'>(* Equivalent to:
* string::concatenate "Hello " "World!" *)</span>
<span class='hljs-operator'>|></span> <span class='hljs-title class_'>std</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>println</span>
<span class='hljs-comment'>(* Prints "Hello World!" *)</span>
Match expressions
The match
expression is the most important control flow in Halcyon.
It is similar to, but much more powerful than switch
statements in other languages.
A match expression consists of an expression to match on (the discriminant), and a list of cases.
Here, the program is matching on the tuple (number % 3, number % 5)
:
<span class='hljs-punctuation'>(</span><span class='hljs-keyword'>match</span> <span class='hljs-punctuation'>(</span>number <span class='hljs-operator'>%</span> <span class='hljs-variable constant_'>3</span><span class='hljs-punctuation'>,</span> number <span class='hljs-operator'>%</span> <span class='hljs-variable constant_'>5</span><span class='hljs-punctuation'>)</span> <span class='hljs-keyword'>with</span>
| <span class='hljs-punctuation'>(</span><span class='hljs-variable constant_'>0</span><span class='hljs-punctuation'>,</span> <span class='hljs-variable constant_'>0</span><span class='hljs-punctuation'>)</span> <span class='hljs-keyword'>=></span> "FizzBuzz"
| <span class='hljs-punctuation'>(</span><span class='hljs-variable constant_'>0</span><span class='hljs-punctuation'>,</span> _<span class='hljs-punctuation'>)</span> <span class='hljs-keyword'>=></span> "Fizz"
| <span class='hljs-punctuation'>(</span>_<span class='hljs-punctuation'>,</span> <span class='hljs-variable constant_'>0</span><span class='hljs-punctuation'>)</span> <span class='hljs-keyword'>=></span> "Buzz"
| <span class='hljs-punctuation'>(</span>_<span class='hljs-punctuation'>,</span> _<span class='hljs-punctuation'>)</span> <span class='hljs-keyword'>=></span> format<span class='hljs-punctuation'>::</span>integer number<span class='hljs-punctuation'>)</span>
A match case has the syntax | [pattern] => [expression]
.
The discriminant is compared with each pattern in order.
The entire expression evaluates to the case of the first pattern matched.
For example, consider the case:
| <span class='hljs-punctuation'>(</span><span class='hljs-variable constant_'>0</span><span class='hljs-punctuation'>,</span> <span class='hljs-variable constant_'>0</span><span class='hljs-punctuation'>)</span> <span class='hljs-keyword'>=></span> "FizzBuzz"
The pattern (0, 0)
is matched only when the discriminant is equal to (0, 0)
.
However, this pattern:
| <span class='hljs-punctuation'>(</span><span class='hljs-variable constant_'>0</span><span class='hljs-punctuation'>,</span> _<span class='hljs-punctuation'>)</span> <span class='hljs-keyword'>=></span> "Fizz"
only requires the first value in the tuple to be 0
.
The _
symbol, or any identifier, is a 'wildcard' that matches anything.
This match expression evaluates to "FizzBuzz"
if number
is a multiple of 3, and 5,
"Fizz"
if number
is only a multiple of 3,
"Buzz"
if number
is only a multiple of 5,
and format::integer number
otherwise.
This is string is then printed.
<span class='hljs-operator'>|></span> std<span class='hljs-punctuation'>::</span>println<span class='hljs-punctuation'>;</span>
If expressions
The if
expression works exactly the same as in other lanuguages, with the exception that the else
clause is mandatory.
This is because if
is an expression, not a statement, and so it must evaluate to something in either case.
Here, the program recursively calls fizz_buzz
if number
is less than max
.
Otherwise, the function returns ()
(similar to void
or None
in other languages).
if number <span class='hljs-operator'><</span> max <span class='hljs-keyword'>then</span>
fizzbuzz <span class='hljs-punctuation'>(</span>number <span class='hljs-operator'>+</span> <span class='hljs-variable constant_'>1</span><span class='hljs-punctuation'>)</span> max
<span class='hljs-keyword'>else</span>
<span class='hljs-punctuation'>(</span><span class='hljs-punctuation'>)</span>
Comments
There are two kinds of comments, single line and block.
A single line comments begin with two dashes --
.
Block comments begin with (*
and end in *)
, and may be nested inside other block comments.
It is conventional to begin every line of a block comment with *
, but this is not required.
<span class='hljs-comment'>-- This is a line comment</span>
<span class='hljs-comment'>(*
* This is a block comment,
* it can span multiple lines<span class='hljs-comment'>
(*
* This is a nested block comment
*)</span>
*)</span>
Non-features
Mutable variables
Every variable in Halcyon is constant. Once a variable is defined, it cannot be changed.
Loops
Halcyon does not have for
or while
loops.
Instead, all looping is done through recursion.
The compiler performs tail call optimization to convert recursive functions into simple loops.
This means that your program will not overflow its stack no matter how deeply it recurses.
Tail call optimizization is only possible in certain circumstances. It is only done when the recursive call is the last operation performed in the function. The fizzbuzz example is tail recursive.
Exceptions and null
Halcyon does not have exceptions or null.
Functions that may fail instead return an opt
or result
.
These are covered more in-depth in their respective doc pages.
Operators Reference
The following is the full list of operators in Halcyon, in order of their precedence:
Symbol | Description |
---|---|
(unary) - -. | arithmetic negation |
(unary) not | logical negation |
* *. | multiplication |
/ /. | division |
% | modulus |
+ +. | addition |
- -. | subtraction |
(function call) | |
>> << | function composition |
xor | logical XOR |
or | logical OR |
|> | function pipe |
== != <= >= < > | comparison |
and | logical AND |
; |
Currently, the comparison operators are only defined for primitive types. Comparing other data types will cause a crash.
Operators are regular functions that are defined in the std
module.
An operator's function can be accessed by surrounding it in parenthesis, like ( + ) 1 2 == 1 + 2
Always put whitespace around an operator when it is in parenthesis.
(*)
is parsed as the beginning of a comment, while ( * )
is the multiplication operator.
Integer and Real Operators
Because operators are functions, the operators for integers and reals are different.
Integers | Reals |
---|---|
+ | +. |
- | -. |
* | *. |
/ | /. |
% |
The ;
Operator
The ;
simply returns the value to the right.
It is useful for chaining together function calls with side effects.
Example
<span class='hljs-keyword'>do</span> <span class='hljs-title class_'>std</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>println</span> <span class='hljs-string'>"old pond"</span><span class='hljs-punctuation'>;</span>
<span class='hljs-title class_'>std</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>println</span> <span class='hljs-string'>"frog leaps in"</span><span class='hljs-punctuation'>;</span>
<span class='hljs-title class_'>std</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>println</span> <span class='hljs-string'>"water's sound"</span><span class='hljs-punctuation'>;</span>
<span class='hljs-title class_'>std</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>println</span> <span class='hljs-string'>" - Bashō'"</span>
The |>
Operator
|>
is the pipe operator.
This operator calls a function on the right with an argument on the left.
The pipe operator helps create function "pipelines", where the return value of one function becomes the parameter of the next function.
Example
<span class='hljs-keyword'>do</span> <span class='hljs-title class_'>format</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>real</span> <span class='hljs-variable constant_'>3.14159</span>
<span class='hljs-comment'>(* Convert real to string *)</span>
<span class='hljs-operator'>|></span> <span class='hljs-title class_'>string</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>concatenate</span> <span class='hljs-string'>"pi = "</span>
<span class='hljs-comment'>(* Prepend "pi = " *)</span>
<span class='hljs-operator'>|></span> <span class='hljs-title class_'>std</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>println</span>
<span class='hljs-comment'>(* Prints "pi = 3.14159" *)</span>
The >> and << operator
The >>
and <<
operators perform function composition.
Given two functions f
and g
, f >> g
is equivalent to fn x => g(f(x))
.
The reverse operation f << g
is equivalent to fn x => f(g(x))
.
The Type System
Halcyon is a statically typed language with full type inference. Type inference means that the types of functions and variables do not need to be written, they can be guessed by the compiler. Compare a function which adds two integers written in C versus in Halcyon:
int add_integers(int x, int y) {
return x + y;
}
<span class='hljs-keyword'>let</span> add_integers = <span class='hljs-keyword'>fn</span> <span class='hljs-params'>x</span> <span class='hljs-params'>y</span> <span class='hljs-keyword'>=></span> x <span class='hljs-operator'>+</span> y
Type annotations can be added using :
, but they are not necessary.
It is an error for a type annotation to be different from the actual type.
<span class='hljs-keyword'>let</span> add_integers <span class='hljs-punctuation'>:</span> <span class='hljs-title class_'>std</span><span class='hljs-punctuation'>::</span><span class='hljs-type'>integer</span> <span class='hljs-operator'>-></span> <span class='hljs-title class_'>std</span><span class='hljs-punctuation'>::</span><span class='hljs-type'>integer</span> =
<span class='hljs-keyword'>fn</span> <span class='hljs-punctuation'>(</span>x <span class='hljs-punctuation'>:</span> <span class='hljs-title class_'>std</span><span class='hljs-punctuation'>::</span><span class='hljs-type'>integer</span><span class='hljs-punctuation'>)</span> <span class='hljs-punctuation'>(</span>y <span class='hljs-punctuation'>:</span> <span class='hljs-title class_'>std</span><span class='hljs-punctuation'>::</span><span class='hljs-type'>integer</span><span class='hljs-punctuation'>)</span> <span class='hljs-keyword'>=></span> x <span class='hljs-operator'>+</span> y
This book will often provide type annotations for clarity's sake, but this is not intended to imply they are best practice or required.
Primitive types
The following is a list of the primitive types, as well as their equivalents in C:
Halcyon type | C type |
---|---|
() or unit | void |
integer | int or long |
real | double |
boolean | bool |
glyph | wchar_t |
string | wchar_t[] |
<span class='hljs-keyword'>let</span> nothing <span class='hljs-punctuation'>:</span> <span class='hljs-type'>(</span><span class='hljs-type'>)</span> = <span class='hljs-punctuation'>(</span><span class='hljs-punctuation'>)</span>
<span class='hljs-keyword'>let</span> life <span class='hljs-punctuation'>:</span> <span class='hljs-title class_'>std</span><span class='hljs-punctuation'>::</span><span class='hljs-type'>integer</span> = <span class='hljs-variable constant_'>42</span>
<span class='hljs-keyword'>let</span> pi <span class='hljs-punctuation'>:</span> <span class='hljs-title class_'>std</span><span class='hljs-punctuation'>::</span><span class='hljs-type'>real</span> = <span class='hljs-variable constant_'>3.14159</span>
<span class='hljs-keyword'>let</span> yes <span class='hljs-punctuation'>:</span> <span class='hljs-title class_'>std</span><span class='hljs-punctuation'>::</span><span class='hljs-type'>boolean</span> = <span class='hljs-built_in'>true</span>
<span class='hljs-keyword'>let</span> grade <span class='hljs-punctuation'>:</span> <span class='hljs-title class_'>std</span><span class='hljs-punctuation'>::</span><span class='hljs-type'>glyph</span> = <span class='hljs-string'>'A'</span>
<span class='hljs-keyword'>let</span> greeting <span class='hljs-punctuation'>:</span> <span class='hljs-title class_'>std</span><span class='hljs-punctuation'>::</span><span class='hljs-type'>string</span> = <span class='hljs-string'>"Hello world!"</span>
Arrays
An array is a list of values of the same type, and that has a variable length. To define an array, use square brackets:
<span class='hljs-keyword'>let</span> numbers <span class='hljs-punctuation'>:</span> [<span class='hljs-title class_'>std</span><span class='hljs-punctuation'>::</span><span class='hljs-type'>integer</span>] = [<span class='hljs-variable constant_'>1</span><span class='hljs-punctuation'>,</span> <span class='hljs-variable constant_'>2</span><span class='hljs-punctuation'>,</span> <span class='hljs-variable constant_'>3</span><span class='hljs-punctuation'>,</span> <span class='hljs-variable constant_'>4</span>]
Tuples
A tuple is a list of values that may be different types, and has a fixed length. To define a tuple, use parenthesis:
<span class='hljs-keyword'>let</span> single_tuple = <span class='hljs-punctuation'>(</span><span class='hljs-string'>"alone"</span><span class='hljs-punctuation'>,</span><span class='hljs-punctuation'>)</span>
<span class='hljs-keyword'>let</span> grocery_list = <span class='hljs-punctuation'>(</span><span class='hljs-string'>"eggs"</span><span class='hljs-punctuation'>,</span> <span class='hljs-string'>"bacon"</span><span class='hljs-punctuation'>,</span> <span class='hljs-string'>"milk"</span><span class='hljs-punctuation'>)</span>
<span class='hljs-keyword'>let</span> favorite_numbers = <span class='hljs-punctuation'>(</span><span class='hljs-variable constant_'>42</span><span class='hljs-punctuation'>,</span> <span class='hljs-variable constant_'>2.718</span><span class='hljs-punctuation'>,</span> <span class='hljs-string'>'∞'</span><span class='hljs-punctuation'>)</span>
<span class='hljs-keyword'>let</span> list_of_lists = <span class='hljs-punctuation'>(</span>grocery_list<span class='hljs-punctuation'>,</span> favorite_numbers<span class='hljs-punctuation'>)</span>
Function types
A fundamental rule in Halcyon is that every function has a single parameter. This is achieved using a process called currying. Understanding this concept is extremely important, so lets work through an example. Consider this function:
<span class='hljs-keyword'>let</span> add_integers = <span class='hljs-keyword'>fn</span> <span class='hljs-params'>x</span> <span class='hljs-params'>y</span> <span class='hljs-params'>z</span> <span class='hljs-keyword'>=></span> x <span class='hljs-operator'>+</span> y <span class='hljs-operator'>+</span> z
The compiler will automatically transform add_integers
into the following:
<span class='hljs-keyword'>let</span> add_integers =
<span class='hljs-keyword'>fn</span> <span class='hljs-params'>x</span> <span class='hljs-keyword'>=></span>
<span class='hljs-keyword'>fn</span> <span class='hljs-params'>y</span> <span class='hljs-keyword'>=></span>
<span class='hljs-keyword'>fn</span> <span class='hljs-params'>z</span> <span class='hljs-keyword'>=></span> x <span class='hljs-operator'>+</span> y <span class='hljs-operator'>+</span> z
Let us see how the expression add_integer 1 2 3
is evaluated.
First, substitute the variable name for its definition:
<span class='hljs-punctuation'>(</span><span class='hljs-keyword'>fn</span> x <span class='hljs-keyword'>=></span> <span class='hljs-keyword'>fn</span> y <span class='hljs-keyword'>=></span> <span class='hljs-keyword'>fn</span> z <span class='hljs-keyword'>=></span> x <span class='hljs-operator'>+</span> y <span class='hljs-operator'>+</span> z<span class='hljs-punctuation'>)</span> <span class='hljs-variable constant_'>1</span> <span class='hljs-variable constant_'>2</span> <span class='hljs-variable constant_'>3</span>
Next, call the outermost function with the first argument 1
:
<span class='hljs-punctuation'>(</span><span class='hljs-keyword'>fn</span> y <span class='hljs-keyword'>=></span> <span class='hljs-keyword'>fn</span> z <span class='hljs-keyword'>=></span> <span class='hljs-variable constant_'>1</span> <span class='hljs-operator'>+</span> y <span class='hljs-operator'>+</span> z<span class='hljs-punctuation'>)</span> <span class='hljs-variable constant_'>2</span> <span class='hljs-variable constant_'>3</span>
Repeat with the next two arguments 2
and 3
:
<span class='hljs-punctuation'>(</span><span class='hljs-keyword'>fn</span> y <span class='hljs-keyword'>=></span> <span class='hljs-keyword'>fn</span> z <span class='hljs-keyword'>=></span> <span class='hljs-variable constant_'>1</span> <span class='hljs-operator'>+</span> y <span class='hljs-operator'>+</span> z<span class='hljs-punctuation'>)</span> <span class='hljs-variable constant_'>2</span> <span class='hljs-variable constant_'>3</span>
<span class='hljs-punctuation'>(</span><span class='hljs-keyword'>fn</span> z <span class='hljs-keyword'>=></span> <span class='hljs-variable constant_'>1</span> <span class='hljs-operator'>+</span> <span class='hljs-variable constant_'>2</span> <span class='hljs-operator'>+</span> z<span class='hljs-punctuation'>)</span> <span class='hljs-variable constant_'>3</span>
<span class='hljs-variable constant_'>1</span> <span class='hljs-operator'>+</span> <span class='hljs-variable constant_'>2</span> <span class='hljs-operator'>+</span> <span class='hljs-variable constant_'>3</span>
<span class='hljs-variable constant_'>6</span>
The type of a function is written as a -> b
, where a
is the parameter type, and b
is the return type.
The ->
operator, like =>
, is right associative.
This means that a -> b -> c
is interpreted as a -> (b -> c)
.
The type of add_integers
in the example above is:
integer -> integer -> integer -> integer
Advanced types
Some types must be explicitly defined and given a name before they may be used.
Structures
A structure is like a tuple with named values.
It is similar to a struct or class in other languages.
Unlike primitive types, identical structures with different names not the same type.
Structures are defined using type
statements:
<span class='hljs-keyword'>type</span> Vector2 = <span class='hljs-punctuation'>{</span> x <span class='hljs-punctuation'>:</span> <span class='hljs-title class_'>std</span><span class='hljs-punctuation'>::</span><span class='hljs-type'>real</span><span class='hljs-punctuation'>,</span> y <span class='hljs-punctuation'>:</span> <span class='hljs-title class_'>std</span><span class='hljs-punctuation'>::</span><span class='hljs-type'>real</span> <span class='hljs-punctuation'>}</span>
<span class='hljs-keyword'>let</span> origin <span class='hljs-punctuation'>:</span> <span class='hljs-type'>Vector2</span> = <span class='hljs-punctuation'>{</span>
x = <span class='hljs-variable constant_'>0.0</span><span class='hljs-punctuation'>,</span>
y = <span class='hljs-variable constant_'>0.0</span><span class='hljs-punctuation'>,</span>
<span class='hljs-punctuation'>}</span>
<span class='hljs-keyword'>let</span> x = origin.x
<span class='hljs-keyword'>let</span> y = origin.y
In rare cases, type inference for structures may fail. This is because some structures may be exactly the same except for their name. For this reason, it is best practice to write type annotations for structures.
Sum types
Sum types are similar to enums in other languages.
<span class='hljs-keyword'>type</span> Class = <span class='hljs-title function_'>Knight</span> | <span class='hljs-title function_'>Mage</span> | <span class='hljs-title function_'>Rogue</span>
<span class='hljs-keyword'>let</span> class_greeting = <span class='hljs-keyword'>fn</span> <span class='hljs-params'>class</span> <span class='hljs-keyword'>=></span> <span class='hljs-title class_'>std</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>println</span>
<span class='hljs-punctuation'>(</span><span class='hljs-keyword'>match</span> class <span class='hljs-keyword'>with</span>
| <span class='hljs-title function_'>Knight</span> <span class='hljs-keyword'>=></span> <span class='hljs-string'>"I am a knight"</span>
| <span class='hljs-title function_'>Mage</span> <span class='hljs-keyword'>=></span> <span class='hljs-string'>"I am a mage"</span>
| <span class='hljs-title function_'>Rogue</span> <span class='hljs-keyword'>=></span> <span class='hljs-string'>"I am a rogue"</span><span class='hljs-punctuation'>)</span>
<span class='hljs-keyword'>do</span>
<span class='hljs-title function_'>class_greeting</span> Knight<span class='hljs-punctuation'>;</span>
<span class='hljs-title function_'>class_greeting</span> Mage<span class='hljs-punctuation'>;</span>
<span class='hljs-title function_'>class_greeting</span> Rogue
A sum type may contain data attached to one of its variants.
Imagine you are writing a function safe_divide
that checks if the denominator is zero.
Using sum types, we can show that this function may fail to return a number:
<span class='hljs-keyword'>type</span> Result = <span class='hljs-title function_'>Ok</span> <span class='hljs-keyword'>of</span> <span class='hljs-title class_'>std</span><span class='hljs-punctuation'>::</span><span class='hljs-type'>real</span> | <span class='hljs-title function_'>DivisionError</span>
<span class='hljs-keyword'>let</span> safe_divide = <span class='hljs-keyword'>fn</span> <span class='hljs-params'>numerator</span> <span class='hljs-params'>denominator</span> <span class='hljs-keyword'>=></span>
<span class='hljs-keyword'>match</span> denominator <span class='hljs-keyword'>with</span>
| <span class='hljs-variable constant_'>0</span> <span class='hljs-keyword'>=></span> DivisionError
| _ <span class='hljs-keyword'>=></span> <span class='hljs-title function_'>Ok</span> <span class='hljs-punctuation'>(</span>numerator <span class='hljs-operator'>/.</span> denominator<span class='hljs-punctuation'>)</span>
The Result
type defines two constructors, Ok
and DivisionError
.
Because DivisionError
contains no data, it is actually just a constant with the type Result
.
The Ok
constructor does contain data, so it is a function with the type real -> Result
.
Sum types are extremely flexible; Halcyon uses them as a substitute for null pointers, exceptions, and sub-types.
A result type already exists in the standard library result
module, including lots of useful functions for working with results.
See also: the opt
module
Implicit Polymorphism
We discussed earlier that Halcyon has full type inference. What do you think the type of this function will be inferred to be?
<span class='hljs-keyword'>let</span> identity <span class='hljs-comment'>(* ? -> ? *)</span> = <span class='hljs-keyword'>fn</span> <span class='hljs-params'>a</span> <span class='hljs-keyword'>=></span> a
The function identity
simply returns whatever its parameter is.
There are no context clues forcing a
to be any type in particular, and so identity
is implicitly polymorphic.
In simple terms, this means that its argument may be any type:
<span class='hljs-keyword'>do</span>
<span class='hljs-title function_'>identity</span> <span class='hljs-variable constant_'>1</span><span class='hljs-punctuation'>;</span>
<span class='hljs-title function_'>identity</span> <span class='hljs-built_in'>false</span><span class='hljs-punctuation'>;</span>
<span class='hljs-title function_'>identity</span> <span class='hljs-string'>"foo"</span>
The exact type of identity
is '0 -> '0
, where '0
is a type variable.
Type variables are a placeholder type that gets replaced when a function is actually called.
A functions type may have any number of type variables.
<span class='hljs-keyword'>let</span> first = <span class='hljs-keyword'>fn</span> <span class='hljs-params'>a</span> <span class='hljs-params'>b</span> <span class='hljs-keyword'>=></span> a
<span class='hljs-keyword'>let</span> second = <span class='hljs-keyword'>fn</span> <span class='hljs-params'>a</span> <span class='hljs-params'>b</span> <span class='hljs-keyword'>=></span> b
<span class='hljs-keyword'>do</span> <span class='hljs-title class_'>std</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>println</span> <span class='hljs-punctuation'>(</span><span class='hljs-title function_'>first</span> <span class='hljs-string'>"foo"</span> <span class='hljs-variable constant_'>2</span><span class='hljs-punctuation'>)</span>
<span class='hljs-keyword'>do</span> <span class='hljs-title class_'>std</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>println</span> <span class='hljs-punctuation'>(</span><span class='hljs-title function_'>second</span> <span class='hljs-built_in'>false</span> <span class='hljs-string'>"bar"</span><span class='hljs-punctuation'>)</span>
Here, first
has the type '0 -> '1 -> '0
, while second
has the type '0 -> '1 -> '1
.
Explicit Polymorphism
Types can contain type variables just like functions. Polymorphic types are called type functions, and follow slightly different rules from regular types.
The standard library defines the opt
type, similar to the Result
type above except that it can contain any type, not just real
.
Let's see how it is implemented:
<span class='hljs-keyword'>module</span> opt =
<span class='hljs-keyword'>type</span> t = <span class='hljs-keyword'>fn</span> <span class='hljs-type'>a</span> <span class='hljs-keyword'>=></span> <span class='hljs-title function_'>Some</span> <span class='hljs-keyword'>of</span> <span class='hljs-type'>a</span> | <span class='hljs-title function_'>None</span>
<span class='hljs-keyword'>end</span>
Here, opt
, is not a type per se, but rather a function that returns a type.
The parameters to a type function (in this case a
) are other types.
When you use a polymorphic type, the compiler will infer the correct type parameter for you.
<span class='hljs-keyword'>let</span> safe_divide = <span class='hljs-keyword'>fn</span> <span class='hljs-params'>numerator</span> <span class='hljs-params'>denominator</span> <span class='hljs-keyword'>=></span>
<span class='hljs-keyword'>match</span> denominator <span class='hljs-keyword'>with</span>
| <span class='hljs-variable constant_'>0</span> <span class='hljs-keyword'>=></span> <span class='hljs-title class_'>opt</span><span class='hljs-punctuation'>::</span>None
| _ <span class='hljs-keyword'>=></span> <span class='hljs-title class_'>opt</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>Some</span> <span class='hljs-punctuation'>(</span>numerator <span class='hljs-operator'>/</span> denominator<span class='hljs-punctuation'>)</span>
<span class='hljs-comment'>(* safe_divide : integer -> (opt::t integer) *)</span>
Modules
Modules are how code is organized in Halcyon: all variables, functions, and types must be inside a module. There are a number of built-in modules supported by Halcyon. These are implicitly in scope in all Halcyon programs.
The following modules are planned, but remain unimplmented
std
std is a module that contains the 6 primitive types, as well as some functions that most Halcyon programs will need access to.
Primitives
integer
The 64 bit two's complement integer type. The maximum 64 bit signed integer is 9,223,372,036,854,775,807. Integer literals can be written in multiple ways
Literal | Representation |
---|---|
9_999 | Decimal number |
0b1111 | Binary number (prefixed with 0b) |
0o777 | Octal number (prefixed with 0o) |
0xFF | Hexadecimal number (prefixed with 0x) |
Base prefixes and hexadecimal digits are case insensitive.
Integer literals may have underscore _
characters in any position.
real
A 64 bit floating point number, similar to float
in C.
string
The string type supports UTF-8 encoded characters. Use "" for string literals. There are a number of supported escape sequences.
Escape Sequence | Name |
---|---|
\n | new line |
\r | carriage return |
\t | tab |
\b | back space |
\ | backslash |
\" | double quote |
\' | single quote |
\x7F | Byte character code (2 hex digits) |
\w7FFF | Word character code (4 hex digits) |
Examples
"abcdefghijklmnopqrstuvwxyz1234567890" (* valid *)
"Ͱऐቕ" (* valid *)
"🤓☝️" (* valid *)
"I love Halcyon\n It is awesome" (* valid *)
"I hate Halcyon\e It is not awesome" (* invalid *)
glyph
The character type. A glyph must contain only a single character or escape sequence. Use '' for glyph literals.
unit
A type used to represent nothing.
Similar to void
in C.
boolean
The boolean type is either true
or false
.
Functions
panic: () -> '0
Panic crashes the program intentionally.
Since it returns '0
, panic can be "returned" in any function without causing type issues.
assert: boolean -> ()
Crash the program if the parameter is false, otherwise do nothing and return unit.
Variations boolean -> boolean -> ()
Assert has several variations that have the same behavior. They crash if the condition is false, otherwise, they return unit.
Function | Condition |
---|---|
assert_eq | Equal |
assert_ne | Not Equal |
assert_ge | Greater or Equal |
assert_le | Less or Equal |
assert_gt | Greater |
assert_lt | Less |
println: string -> ()
Prints the passed string to the console.
list
list
is a type used to represent a linked list data structure.
Every list is either Pair and contains two values (head, tail) or is Nil, and contains no values
<span class='hljs-keyword'>type</span> t = <span class='hljs-keyword'>fn</span> <span class='hljs-type'>I</span> <span class='hljs-keyword'>=></span> <span class='hljs-punctuation'>(</span><span class='hljs-type'>Pair</span> <span class='hljs-type'>of</span> <span class='hljs-type'>I</span><span class='hljs-punctuation'>,</span> <span class='hljs-punctuation'>(</span><span class='hljs-type'>t</span> <span class='hljs-type'>I</span><span class='hljs-punctuation'>)</span><span class='hljs-punctuation'>)</span> | <span class='hljs-type'>Nil</span>
Functions
Nil: (list::t '0)
The constructor for an empty list item. This should only be located at the end of a list.
Example
<span class='hljs-keyword'>let</span> my_empty_list = <span class='hljs-title class_'>list</span><span class='hljs-punctuation'>::</span>Nil
Pair: ('0 * (list::t '0)) -> (list::t '0)
The constructor for a non-empty list item
Example
<span class='hljs-keyword'>let</span> my_list = <span class='hljs-title class_'>list</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>Pair</span> <span class='hljs-punctuation'>(</span><span class='hljs-string'>"item"</span><span class='hljs-punctuation'>,</span> <span class='hljs-title class_'>list</span><span class='hljs-punctuation'>::</span>Nil<span class='hljs-punctuation'>)</span>
push: '0 -> (list::t '0) -> (list::t '0)
Creates a copy of the passed list with the passed element appended to the end.
Example
<span class='hljs-keyword'>let</span> my_list = <span class='hljs-title class_'>list</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>Nil</span> <span class='hljs-punctuation'>(</span><span class='hljs-punctuation'>)</span>
<span class='hljs-comment'>(* my_list: Nil *)</span>
<span class='hljs-keyword'>let</span> my_new_list = <span class='hljs-title class_'>list</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>push</span> <span class='hljs-string'>"item"</span> my_list
<span class='hljs-comment'>(* my_new_list: "item" > Nil *)</span>
iterate: ('0 -> unit) -> (list::t '0) -> ()
Runs the passed operation on each element of the passed list, but doesn't create or return a new one.
Example
<span class='hljs-keyword'>let</span> my_list = <span class='hljs-title class_'>list</span><span class='hljs-punctuation'>::</span>Nil <span class='hljs-operator'>|></span> <span class='hljs-title class_'>list</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>push</span> <span class='hljs-string'>"Hello"</span> <span class='hljs-operator'>|></span> <span class='hljs-title class_'>list</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>push</span> <span class='hljs-string'>" World!"</span>
<span class='hljs-keyword'>let</span> <span class='hljs-punctuation'>(</span><span class='hljs-punctuation'>)</span> = <span class='hljs-title class_'>list</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>iterate</span> <span class='hljs-title class_'>std</span><span class='hljs-punctuation'>::</span>println my_list
<span class='hljs-comment'>(* prints "Hello World!" *)</span>
map: ('0 -> '1) -> (list::t '0) -> (list::t '1)
Creates and returns a new list by applying the passed operation to each element in the passed list.
Example
<span class='hljs-keyword'>let</span> my_list = <span class='hljs-title class_'>list</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>Nil</span> <span class='hljs-punctuation'>(</span><span class='hljs-punctuation'>)</span> <span class='hljs-operator'>|></span> <span class='hljs-title class_'>list</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>push</span> <span class='hljs-variable constant_'>3</span> <span class='hljs-operator'>|></span> <span class='hljs-title class_'>list</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>push</span> <span class='hljs-variable constant_'>4</span>
<span class='hljs-comment'>(* my_list: 3 > 4 > Nil *)</span>
<span class='hljs-keyword'>let</span> my_mapped_list = <span class='hljs-title class_'>list</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>map</span> <span class='hljs-punctuation'>(</span><span class='hljs-keyword'>fn</span> <span class='hljs-params'>a</span> <span class='hljs-keyword'>=></span> a <span class='hljs-operator'>*</span> <span class='hljs-variable constant_'>2</span><span class='hljs-punctuation'>)</span> my_list
<span class='hljs-comment'>(* my_mapped_list: 6 > 8 > Nil *)</span>
length: (list::t '0) -> integer
Returns the length of the passed list.
Example
<span class='hljs-keyword'>let</span> length = <span class='hljs-title class_'>list</span><span class='hljs-punctuation'>::</span>Nil <span class='hljs-operator'>|></span> <span class='hljs-title class_'>list</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>push</span> <span class='hljs-variable constant_'>0</span> <span class='hljs-operator'>|></span> <span class='hljs-title class_'>list</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>push</span> <span class='hljs-variable constant_'>1</span> <span class='hljs-operator'>|></span> <span class='hljs-title class_'>list</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>length</span>
<span class='hljs-keyword'>let</span> <span class='hljs-punctuation'>(</span><span class='hljs-punctuation'>)</span> = <span class='hljs-title class_'>format</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>integer</span> length <span class='hljs-operator'>|></span> <span class='hljs-title class_'>std</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>println</span>
<span class='hljs-comment'>(* prints 2 *)</span>
nth: integer -> (list::t '0) -> '0
Returns the value of the passed list item at the position of the passed index.
Example
<span class='hljs-keyword'>let</span> my_list = <span class='hljs-title class_'>list</span><span class='hljs-punctuation'>::</span>Nil <span class='hljs-operator'>|></span> <span class='hljs-title class_'>list</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>push</span> <span class='hljs-string'>"one"</span> <span class='hljs-operator'>|></span> <span class='hljs-title class_'>list</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>push</span> <span class='hljs-string'>"two"</span> <span class='hljs-operator'>|></span> <span class='hljs-title class_'>list</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>push</span> <span class='hljs-string'>"three"</span>
<span class='hljs-keyword'>let</span> <span class='hljs-punctuation'>(</span><span class='hljs-punctuation'>)</span> = <span class='hljs-title class_'>list</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>nth</span> <span class='hljs-variable constant_'>2</span> my_list <span class='hljs-operator'>|></span> <span class='hljs-title class_'>std</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>println</span>
<span class='hljs-comment'>(* prints "two" *)</span>
concatenate: (list::t '0) -> (list::t '0) -> (list::t '0)
Adds the second passed list to the end of the first passed list.
Example
<span class='hljs-keyword'>let</span> my_list = <span class='hljs-title class_'>list</span><span class='hljs-punctuation'>::</span>Nil <span class='hljs-operator'>|></span> <span class='hljs-title class_'>list</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>push</span> <span class='hljs-string'>"one"</span> <span class='hljs-operator'>|></span> <span class='hljs-title class_'>list</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>push</span> <span class='hljs-string'>"two"</span>
<span class='hljs-keyword'>let</span> my_second_list = <span class='hljs-title class_'>list</span><span class='hljs-punctuation'>::</span>Nil <span class='hljs-operator'>|></span> <span class='hljs-title class_'>list</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>push</span> <span class='hljs-string'>"three"</span> <span class='hljs-operator'>|></span> <span class='hljs-title class_'>list</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>push</span> <span class='hljs-string'>"four"</span>
<span class='hljs-keyword'>let</span> my_final_list = <span class='hljs-title class_'>list</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>concatenate</span> my_list my_second_list
<span class='hljs-comment'>(* my_list: "one" > "two" > Nil *)</span>
<span class='hljs-comment'>(* my_second_list: "three" > "four" > Nil *)</span>
<span class='hljs-comment'>(* my_final_list: "one" > "two" > "three" > "four" > Nil*)</span>
fold: ('0 -> '1 -> '0) -> '0 -> (list::t '1) -> '0
Reduces the passed list to a single element using the passed function.
Example
<span class='hljs-keyword'>let</span> my_list = <span class='hljs-title class_'>list</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>Nil</span> <span class='hljs-punctuation'>(</span><span class='hljs-punctuation'>)</span> <span class='hljs-operator'>|></span> <span class='hljs-title class_'>list</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>push</span> <span class='hljs-variable constant_'>1</span> <span class='hljs-operator'>|></span> <span class='hljs-title class_'>list</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>push</span> <span class='hljs-variable constant_'>2</span> <span class='hljs-operator'>|></span> <span class='hljs-title class_'>list</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>push</span> <span class='hljs-variable constant_'>3</span>
<span class='hljs-keyword'>let</span> <span class='hljs-punctuation'>(</span><span class='hljs-punctuation'>)</span> = <span class='hljs-title class_'>list</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>fold</span> <span class='hljs-punctuation'>(</span><span class='hljs-keyword'>fn</span> <span class='hljs-params'>a</span> <span class='hljs-params'>b</span> <span class='hljs-keyword'>=></span> <span class='hljs-keyword'>if</span> a <span class='hljs-operator'><</span> b <span class='hljs-keyword'>then</span> a <span class='hljs-keyword'>else</span> b<span class='hljs-punctuation'>)</span> <span class='hljs-variable constant_'>10</span> my_list <span class='hljs-operator'>|></span> <span class='hljs-title class_'>format</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>integer</span> <span class='hljs-operator'>|></span> <span class='hljs-title class_'>std</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>println</span>
<span class='hljs-comment'>(* prints 1 *)</span>
opt
opt
is a type that represents an optional value: every Option is either Some and contains a value, or None, and does not.
<span class='hljs-keyword'>type</span> t = <span class='hljs-keyword'>fn</span> <span class='hljs-type'>T</span> <span class='hljs-keyword'>=></span> <span class='hljs-title function_'>Some</span> <span class='hljs-keyword'>of</span> <span class='hljs-type'>T</span> | <span class='hljs-title function_'>None</span>
Functions
Some: '0 -> (opt::t '0)
Constructor for a Some option.
Example
# <span class='hljs-keyword'>module</span> demo =
<span class='hljs-keyword'>let</span> my_some = <span class='hljs-title class_'>opt</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>Some</span> <span class='hljs-punctuation'>(</span><span class='hljs-variable constant_'>12</span><span class='hljs-punctuation'>)</span>
# <span class='hljs-keyword'>end</span>
None: (opt::t '0)
Constructor for a None option.
Example
# <span class='hljs-keyword'>module</span> demo =
<span class='hljs-keyword'>let</span> my_none = <span class='hljs-title class_'>opt</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>None</span> <span class='hljs-punctuation'>(</span><span class='hljs-punctuation'>)</span>
# <span class='hljs-keyword'>end</span>
is_some: (opt::t '0) -> boolean
Returns true if the passed option is Some, otherwise returns false.
Example
# <span class='hljs-keyword'>module</span> demo =
<span class='hljs-keyword'>let</span> value = <span class='hljs-title class_'>opt</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>Some</span> <span class='hljs-punctuation'>(</span><span class='hljs-variable constant_'>12</span><span class='hljs-punctuation'>)</span> <span class='hljs-operator'>|></span> <span class='hljs-title class_'>opt</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>is_some</span>
<span class='hljs-comment'>(* value is true *)</span>
# <span class='hljs-keyword'>end</span>
is_none: (opt::t '0) -> std:boolean
Returns true if the passed option is None, otherwise false.
Example
# <span class='hljs-keyword'>module</span> demo =
<span class='hljs-keyword'>let</span> value = <span class='hljs-title class_'>opt</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>None</span> <span class='hljs-punctuation'>(</span><span class='hljs-punctuation'>)</span> <span class='hljs-operator'>|></span> <span class='hljs-title class_'>opt</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>is_none</span>
<span class='hljs-comment'>(* value is true *)</span>
# <span class='hljs-keyword'>end</span>
unwrap: (opt::t '0) -> '0
If the passed option is a Some, returns the enclosed value, otherwise panics.
Example
# <span class='hljs-keyword'>module</span> demo =
<span class='hljs-keyword'>let</span> value = <span class='hljs-title class_'>opt</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>Some</span> <span class='hljs-punctuation'>(</span><span class='hljs-variable constant_'>12</span><span class='hljs-punctuation'>)</span> <span class='hljs-operator'>|></span> <span class='hljs-title class_'>opt</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>unwrap</span>
<span class='hljs-comment'>(* value == 12 *)</span>
<span class='hljs-keyword'>let</span> other_value = <span class='hljs-title class_'>opt</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>None</span> <span class='hljs-punctuation'>(</span><span class='hljs-punctuation'>)</span> <span class='hljs-operator'>|></span> <span class='hljs-title class_'>opt</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>unwrap</span>
<span class='hljs-comment'>(* panics *)</span>
# <span class='hljs-keyword'>end</span>
map: ('0 -> '1) -> (opt::t '0) -> (opt::t '1)
If the passed option is a Some, returns a copy of the passed option with the passed function applied to its value. Otherwise, returns None.
Example
# <span class='hljs-keyword'>module</span> demo =
<span class='hljs-keyword'>let</span> my_opt = <span class='hljs-title class_'>opt</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>Some</span> <span class='hljs-punctuation'>(</span><span class='hljs-variable constant_'>2</span><span class='hljs-punctuation'>)</span>
<span class='hljs-keyword'>let</span> <span class='hljs-punctuation'>(</span><span class='hljs-punctuation'>)</span> = my_opt <span class='hljs-operator'>|></span> <span class='hljs-title class_'>opt</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>map</span> <span class='hljs-punctuation'>(</span><span class='hljs-keyword'>fn</span> <span class='hljs-params'>a</span> <span class='hljs-keyword'>=></span> a <span class='hljs-operator'>*</span> <span class='hljs-variable constant_'>2</span><span class='hljs-punctuation'>)</span> <span class='hljs-operator'>|></span> <span class='hljs-title class_'>opt</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>unwrap</span> <span class='hljs-operator'>|></span> <span class='hljs-title class_'>string</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>from_integer</span> <span class='hljs-operator'>|></span> <span class='hljs-title class_'>std</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>print_string</span>
<span class='hljs-comment'>(* prints 4 *)</span>
# <span class='hljs-keyword'>end</span>
iterate: ('0 -> '1) -> (opt::t '0) -> ()
If the passed option is a Some, runs passed function on the passed option, then returns unit. Otherwise, returns unit.
Example
# <span class='hljs-keyword'>module</span> demo =
<span class='hljs-keyword'>let</span> <span class='hljs-punctuation'>(</span><span class='hljs-punctuation'>)</span> = <span class='hljs-title class_'>opt</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>Some</span> <span class='hljs-punctuation'>(</span><span class='hljs-string'>"Teto"</span><span class='hljs-punctuation'>)</span> <span class='hljs-operator'>|></span> <span class='hljs-title class_'>opt</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>iterate</span> <span class='hljs-title class_'>std</span><span class='hljs-punctuation'>::</span>print_string
<span class='hljs-comment'>(* prints "Teto" *)</span>
# <span class='hljs-keyword'>end</span>
result
result
is a type that represents either success (Ok) or failure (Error).
Every result is either an Ok or an Error, both of which contain a value.
<span class='hljs-keyword'>type</span> result = <span class='hljs-keyword'>fn</span> <span class='hljs-type'>a</span> <span class='hljs-type'>b</span> <span class='hljs-keyword'>=></span> <span class='hljs-title function_'>Ok</span> <span class='hljs-keyword'>of</span> <span class='hljs-type'>a</span> | <span class='hljs-title function_'>Error</span> <span class='hljs-keyword'>of</span> <span class='hljs-type'>b</span>
Functions
Ok: '0 -> (result::t '0 '1)
Constructor for an Ok result.
Example
<span class='hljs-keyword'>let</span> my_OK = <span class='hljs-title class_'>result</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>Ok</span> <span class='hljs-punctuation'>(</span><span class='hljs-variable constant_'>2</span><span class='hljs-punctuation'>)</span>
Error: '1 -> (result::t '0 '1)
Constructor for an Error result.
Example
<span class='hljs-keyword'>let</span> my_Error = <span class='hljs-title class_'>result</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>Error</span> <span class='hljs-punctuation'>(</span><span class='hljs-variable constant_'>2</span><span class='hljs-punctuation'>)</span>
is_ok: (result::t '0 '1) -> boolean
Returns true if the passed result is Ok, otherwise returns false.
Example
<span class='hljs-keyword'>let</span> my_result = <span class='hljs-title class_'>result</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>Ok</span> <span class='hljs-punctuation'>(</span><span class='hljs-variable constant_'>2</span><span class='hljs-punctuation'>)</span>
<span class='hljs-keyword'>let</span> <span class='hljs-punctuation'>(</span><span class='hljs-punctuation'>)</span> =
<span class='hljs-keyword'>if</span> <span class='hljs-title class_'>result</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>is_ok</span> my_result <span class='hljs-keyword'>then</span>
<span class='hljs-title class_'>std</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>println</span> <span class='hljs-string'>"Ok!"</span>
<span class='hljs-keyword'>else</span>
<span class='hljs-title class_'>std</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>println</span> <span class='hljs-string'>"Error!"</span>
<span class='hljs-comment'>(* prints "Ok!" *)</span>
is_err: (result::t '0 '1) -> boolean
Returns true if the passed result is Error, otherwise returns false.
Example
<span class='hljs-keyword'>let</span> my_result = <span class='hljs-title class_'>result</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>Error</span> <span class='hljs-punctuation'>(</span><span class='hljs-variable constant_'>2</span><span class='hljs-punctuation'>)</span>
<span class='hljs-keyword'>let</span> <span class='hljs-punctuation'>(</span><span class='hljs-punctuation'>)</span> =
<span class='hljs-keyword'>if</span> <span class='hljs-title class_'>result</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>is_err</span> my_result <span class='hljs-keyword'>then</span>
<span class='hljs-title class_'>string</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>print</span> <span class='hljs-string'>"Error!"</span>
<span class='hljs-keyword'>else</span>
<span class='hljs-title class_'>string</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>print</span> <span class='hljs-string'>"Ok!"</span>
<span class='hljs-comment'>(* prints "Error!" *)</span>
unwrap_ok: (result::t '0 '1) -> '0
Returns the value contained in the passed Ok result. Panics if the result is Error.
Notes
It is recommended that you use pattern matching in most cases instead of this.
Example
<span class='hljs-keyword'>let</span> my_result = <span class='hljs-title class_'>result</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>Ok</span> <span class='hljs-punctuation'>(</span><span class='hljs-string'>"Hatsune Miku"</span><span class='hljs-punctuation'>)</span>
<span class='hljs-keyword'>let</span> <span class='hljs-punctuation'>(</span><span class='hljs-punctuation'>)</span> = my_result <span class='hljs-operator'>|></span> <span class='hljs-title class_'>result</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>unwrap_ok</span> <span class='hljs-operator'>|></span> <span class='hljs-title class_'>string</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>print</span>
<span class='hljs-comment'>(* prints "Hatsune Miku" *)</span>
unwrap_err: (result::t '0 '1) -> '1
Returns the value contained in the passed Error result. Panics if the result is Ok.
Notes
It is recommended that you use pattern matching in most cases instead of this.
Example
<span class='hljs-keyword'>let</span> my_result = <span class='hljs-title class_'>result</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>Error</span> <span class='hljs-punctuation'>(</span><span class='hljs-string'>"Kasane Teto"</span><span class='hljs-punctuation'>)</span>
<span class='hljs-keyword'>let</span> <span class='hljs-punctuation'>(</span><span class='hljs-punctuation'>)</span> = my_result <span class='hljs-operator'>|></span> <span class='hljs-title class_'>result</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>unwrap_err</span> <span class='hljs-operator'>|></span> <span class='hljs-title class_'>string</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>print</span>
<span class='hljs-comment'>(* prints "Kasane Teto" *)</span>
res_and: (result::t '0 '1) -> (result::t '0 '1) -> (result::t '0 '1)
If the first result passed is Ok, returns the second one. Otherwise, return the first result, which is an Error.
Example
<span class='hljs-keyword'>let</span> my_result = <span class='hljs-title class_'>result</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>Ok</span> <span class='hljs-punctuation'>(</span><span class='hljs-string'>"Akita Neru"</span><span class='hljs-punctuation'>)</span> <span class='hljs-operator'>|></span> <span class='hljs-title class_'>result</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>res_and</span> Error<span class='hljs-punctuation'>(</span><span class='hljs-string'>"Hatsune Miku"</span><span class='hljs-punctuation'>)</span>
<span class='hljs-keyword'>let</span> <span class='hljs-punctuation'>(</span><span class='hljs-punctuation'>)</span> = <span class='hljs-keyword'>match</span> my_result <span class='hljs-keyword'>with</span>
| result<span class='hljs-punctuation'>:</span><span class='hljs-type'>Ok</span> <span class='hljs-type'>of</span> <span class='hljs-type'>a</span> <span class='hljs-keyword'>=></span> <span class='hljs-title class_'>string</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>print</span> a
| result<span class='hljs-punctuation'>:</span><span class='hljs-type'>Error</span> <span class='hljs-type'>of</span> <span class='hljs-type'>b</span> <span class='hljs-keyword'>=></span> <span class='hljs-title class_'>string</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>print</span> b
<span class='hljs-comment'>(* prints "Hatsune Miku" *)</span>
<span class='hljs-keyword'>let</span> new_result = <span class='hljs-title class_'>result</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>Error</span> <span class='hljs-punctuation'>(</span><span class='hljs-string'>"Kasane Teto"</span><span class='hljs-punctuation'>)</span> <span class='hljs-operator'>|></span> <span class='hljs-title class_'>result</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>res_and</span> Error<span class='hljs-punctuation'>(</span><span class='hljs-string'>"Hatsune Miku"</span><span class='hljs-punctuation'>)</span>
<span class='hljs-keyword'>let</span> <span class='hljs-punctuation'>(</span><span class='hljs-punctuation'>)</span> = <span class='hljs-keyword'>match</span> new_result <span class='hljs-keyword'>with</span>
| <span class='hljs-title class_'>result</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>Ok</span> <span class='hljs-keyword'>of</span> a <span class='hljs-keyword'>=></span> <span class='hljs-title class_'>string</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>print</span> a
| <span class='hljs-title class_'>result</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>Error</span> <span class='hljs-keyword'>of</span> b <span class='hljs-keyword'>=></span> <span class='hljs-title class_'>std</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>print</span> b
<span class='hljs-comment'>(* prints "Kasane Teto" *)</span>
expect: string -> (result::t '0 '1) -> '0
Returns the enclosed result value if the passed result is Ok. If the passed result is an Error, prints the passed string, then panics.
Example
<span class='hljs-keyword'>let</span> <span class='hljs-punctuation'>(</span><span class='hljs-punctuation'>)</span> = <span class='hljs-title class_'>result</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>Ok</span> <span class='hljs-punctuation'>(</span><span class='hljs-string'>"Akita Neru"</span><span class='hljs-punctuation'>)</span> <span class='hljs-operator'>|></span> <span class='hljs-title class_'>result</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>expect</span> <span class='hljs-punctuation'>(</span><span class='hljs-string'>"Try doing it right next time"</span><span class='hljs-punctuation'>)</span> <span class='hljs-operator'>|></span> <span class='hljs-title class_'>string</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>print</span>
<span class='hljs-comment'>(* prints "Akita Neru" *)</span>
<span class='hljs-keyword'>let</span> <span class='hljs-punctuation'>(</span><span class='hljs-punctuation'>)</span> = <span class='hljs-title class_'>result</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>Error</span> <span class='hljs-punctuation'>(</span><span class='hljs-string'>"Akita Neru"</span><span class='hljs-punctuation'>)</span> <span class='hljs-operator'>|></span> <span class='hljs-title class_'>result</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>expect</span> <span class='hljs-punctuation'>(</span><span class='hljs-string'>"Try doing it right next time"</span><span class='hljs-punctuation'>)</span> <span class='hljs-operator'>|></span> <span class='hljs-title class_'>string</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>print</span>
<span class='hljs-comment'>(* prints "Try doing it right next time", then panics *)</span>
res_or: (result::t '0 '1) -> (result::t '0 '1) -> (result::t '0 '1)
Returns the first passed result if it is Ok, otherwise returns the second passed result.
Example
<span class='hljs-keyword'>let</span> <span class='hljs-punctuation'>(</span><span class='hljs-punctuation'>)</span> = <span class='hljs-title class_'>result</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>Ok</span> <span class='hljs-punctuation'>(</span><span class='hljs-string'>"Akita Neru"</span><span class='hljs-punctuation'>)</span> <span class='hljs-operator'>|></span> <span class='hljs-title class_'>result</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>res_or</span> Error <span class='hljs-punctuation'>(</span><span class='hljs-string'>"Kasane Teto"</span><span class='hljs-punctuation'>)</span> <span class='hljs-operator'>|></span> <span class='hljs-title class_'>result</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>unwrap_ok</span> <span class='hljs-operator'>|></span> <span class='hljs-title class_'>string</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>print</span>
<span class='hljs-comment'>(* prints "Akita Neru" *)</span>
<span class='hljs-keyword'>let</span> <span class='hljs-punctuation'>(</span><span class='hljs-punctuation'>)</span> = <span class='hljs-title class_'>result</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>Error</span> <span class='hljs-punctuation'>(</span><span class='hljs-string'>"Akita Neru"</span><span class='hljs-punctuation'>)</span> <span class='hljs-operator'>|></span> <span class='hljs-title class_'>result</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>res_or</span> Error <span class='hljs-punctuation'>(</span><span class='hljs-string'>"Kasane Teto"</span><span class='hljs-punctuation'>)</span> <span class='hljs-operator'>|></span> <span class='hljs-title class_'>result</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>unwrap_err</span> <span class='hljs-operator'>|></span> <span class='hljs-title class_'>string</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>print</span>
<span class='hljs-comment'>(* prints "Kasane Teto" *)</span>
<span class='hljs-keyword'>let</span> <span class='hljs-punctuation'>(</span><span class='hljs-punctuation'>)</span> = <span class='hljs-title class_'>result</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>Error</span> <span class='hljs-punctuation'>(</span><span class='hljs-string'>"Akita Neru"</span><span class='hljs-punctuation'>)</span> <span class='hljs-operator'>|></span> <span class='hljs-title class_'>result</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>res_or</span> Ok <span class='hljs-punctuation'>(</span><span class='hljs-string'>"Kasane Teto"</span><span class='hljs-punctuation'>)</span> <span class='hljs-operator'>|></span> <span class='hljs-title class_'>result</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>unwrap_ok</span> <span class='hljs-operator'>|></span> <span class='hljs-title class_'>string</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>print</span>
<span class='hljs-comment'>(* prints "Kasane Teto" *)</span>
unwrap_or: (result::t '0 '1) -> '0 -> '0
Returns the value enclosed in the first passed result if its Ok, otherwise return the second passed value.
Example
<span class='hljs-keyword'>let</span> <span class='hljs-punctuation'>(</span><span class='hljs-punctuation'>)</span> = <span class='hljs-title class_'>result</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>Ok</span> <span class='hljs-punctuation'>(</span><span class='hljs-string'>"Hatsune Miku"</span><span class='hljs-punctuation'>)</span> <span class='hljs-operator'>|></span> <span class='hljs-title class_'>result</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>unwrap_or</span> <span class='hljs-string'>"Kasane Teto"</span> <span class='hljs-operator'>|></span> <span class='hljs-title class_'>string</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>print</span>
<span class='hljs-comment'>(* prints "Hatsune Miku" *)</span>
<span class='hljs-keyword'>let</span> <span class='hljs-punctuation'>(</span><span class='hljs-punctuation'>)</span> = <span class='hljs-title class_'>result</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>Error</span> <span class='hljs-punctuation'>(</span><span class='hljs-string'>"Hatsune Miku"</span><span class='hljs-punctuation'>)</span> <span class='hljs-operator'>|></span> <span class='hljs-title class_'>result</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>unwrap_or</span> <span class='hljs-string'>"Kasane Teto"</span> <span class='hljs-operator'>|></span> <span class='hljs-title class_'>string</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>print</span>
<span class='hljs-comment'>(* prints "Kasane Teto" *)</span>
and_then: (result::t '0 '1) -> ('0 -> '1) -> (result::t '0 '1)
If the passed result is Ok, returns a new result with an enclosed value equal to the passed result's enclosed value with the passed function appplied to it. Otherwise, returns the passed Error.
Example
<span class='hljs-keyword'>let</span> <span class='hljs-punctuation'>(</span><span class='hljs-punctuation'>)</span> = <span class='hljs-title class_'>result</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>Ok</span> <span class='hljs-punctuation'>(</span><span class='hljs-string'>"Kasane Teto"</span><span class='hljs-punctuation'>)</span> <span class='hljs-operator'>|></span> <span class='hljs-title class_'>result</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>and_then</span> <span class='hljs-punctuation'>(</span><span class='hljs-keyword'>fn</span> <span class='hljs-params'>a</span> <span class='hljs-keyword'>=></span> string<span class='hljs-punctuation'>:</span>concatenate a <span class='hljs-string'>" is my favorite"</span><span class='hljs-punctuation'>)</span> <span class='hljs-operator'>|></span> <span class='hljs-title class_'>result</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>unwrap_ok</span> <span class='hljs-operator'>|></span> <span class='hljs-title class_'>string</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>print</span>
<span class='hljs-comment'>(* prints "Kasane Teto is my favorite" *)</span>
<span class='hljs-keyword'>let</span> <span class='hljs-punctuation'>(</span><span class='hljs-punctuation'>)</span> = <span class='hljs-title class_'>result</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>Error</span> <span class='hljs-punctuation'>(</span><span class='hljs-string'>"Kasane Teto"</span><span class='hljs-punctuation'>)</span> <span class='hljs-operator'>|></span> <span class='hljs-title class_'>result</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>and_then</span> <span class='hljs-punctuation'>(</span><span class='hljs-keyword'>fn</span> <span class='hljs-params'>a</span> <span class='hljs-keyword'>=></span> string<span class='hljs-punctuation'>:</span>concatenate a <span class='hljs-string'>" is my favorite"</span><span class='hljs-punctuation'>)</span> <span class='hljs-operator'>|></span> <span class='hljs-title class_'>result</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>unwrap_err</span> <span class='hljs-operator'>|></span> <span class='hljs-title class_'>string</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>print</span>
<span class='hljs-comment'>(* prints "Kasane Teto" *)</span>
format
format
is a module that provides functions for converting other types to strings.
Functions
integer: integer -> string
Returns the passed integer as a string.
Example
<span class='hljs-keyword'>do</span> <span class='hljs-title class_'>format</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>integer</span> <span class='hljs-variable constant_'>5</span>
<span class='hljs-operator'>|></span> <span class='hljs-title class_'>string</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>print</span>
<span class='hljs-comment'>(* prints "5" *)</span>
real: real -> string
Returns the passed real as a string.
Example
<span class='hljs-keyword'>do</span> <span class='hljs-title class_'>format</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>real</span> <span class='hljs-variable constant_'>5.4</span>
<span class='hljs-operator'>|></span> <span class='hljs-title class_'>string</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>print</span>
<span class='hljs-comment'>(* prints "5.4" *)</span>
boolean: boolean -> string
Returns the passed boolean as a string.
Example
<span class='hljs-keyword'>do</span> <span class='hljs-title class_'>format</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>boolean</span> <span class='hljs-built_in'>true</span>
<span class='hljs-operator'>|></span> <span class='hljs-title class_'>string</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>print</span>
<span class='hljs-comment'>(* prints "true" *)</span>
unit: unit -> string
Returns unit as a string.
Example
<span class='hljs-keyword'>do</span> <span class='hljs-title class_'>format</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>unit</span> <span class='hljs-punctuation'>(</span><span class='hljs-punctuation'>)</span>
<span class='hljs-operator'>|></span> <span class='hljs-title class_'>string</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>print</span>
<span class='hljs-comment'>(* prints "()" *)</span>
btree
btree
is a type that represents a binary tree.
Every btree is either a Node that contains a value and two children (Node or Nil), or it is Nil and contans no values.
<span class='hljs-keyword'>type</span> t = <span class='hljs-keyword'>fn</span> <span class='hljs-type'>I</span> <span class='hljs-keyword'>=></span> <span class='hljs-punctuation'>(</span><span class='hljs-type'>Node</span> <span class='hljs-type'>of</span> <span class='hljs-type'>I</span><span class='hljs-punctuation'>,</span> <span class='hljs-punctuation'>(</span><span class='hljs-type'>t</span> <span class='hljs-type'>I</span><span class='hljs-punctuation'>)</span><span class='hljs-punctuation'>,</span> <span class='hljs-punctuation'>(</span><span class='hljs-type'>t</span> <span class='hljs-type'>I</span><span class='hljs-punctuation'>)</span><span class='hljs-punctuation'>)</span> | <span class='hljs-type'>Nil</span>
Functions
Nil: unit -> (btree '0)
The constructor for a Nil btree. This is used to represent an empty child.
Example
# <span class='hljs-keyword'>module</span> demo =
<span class='hljs-keyword'>let</span> my_empty_tree = <span class='hljs-title class_'>btree</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>Nil</span><span class='hljs-punctuation'>(</span><span class='hljs-punctuation'>)</span>
# <span class='hljs-keyword'>end</span>
Node: '0 * btree '0 * btree '0 -> btree '0
The constructor for a Node btree.
Example
# <span class='hljs-keyword'>module</span> demo =
<span class='hljs-keyword'>let</span> my_tree = <span class='hljs-title function_'>btree</span><span class='hljs-punctuation'>:</span>Node <span class='hljs-punctuation'>(</span><span class='hljs-variable constant_'>1</span><span class='hljs-punctuation'>,</span> <span class='hljs-title class_'>btree</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>Nil</span><span class='hljs-punctuation'>(</span><span class='hljs-punctuation'>)</span><span class='hljs-punctuation'>,</span> <span class='hljs-title class_'>btree</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>Nil</span><span class='hljs-punctuation'>(</span><span class='hljs-punctuation'>)</span><span class='hljs-punctuation'>)</span>
<span class='hljs-comment'>(* my_tree == 1
* / \
* nil nil
*)</span>
# <span class='hljs-keyword'>end</span>
insert: '0 -> ('0 -> '0 -> boolean) -> (btree '0) -> (btree '0)
Returns a copy of the passed tree with the passed value inserted according to the passed operation.
Notes
insert
checks if the function is true with the passed value and the current tree value, if it is, it will attempt to insert the passed value as the left child. Otherwise, it will attempt to insert the passed value as the right child. This process is repeateded recursively until a Node
has a Nil
child in the appropriate position.
Example
# <span class='hljs-keyword'>module</span> demo =
<span class='hljs-keyword'>let</span> my_tree = <span class='hljs-title function_'>btree</span><span class='hljs-punctuation'>:</span>Node <span class='hljs-punctuation'>(</span><span class='hljs-variable constant_'>5</span><span class='hljs-punctuation'>,</span> <span class='hljs-title class_'>btree</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>Nil</span><span class='hljs-punctuation'>(</span><span class='hljs-punctuation'>)</span><span class='hljs-punctuation'>,</span> <span class='hljs-title class_'>btree</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>Nil</span><span class='hljs-punctuation'>(</span><span class='hljs-punctuation'>)</span><span class='hljs-punctuation'>)</span>
<span class='hljs-keyword'>let</span> my_new_tree = <span class='hljs-title function_'>btree</span><span class='hljs-punctuation'>:</span>insert <span class='hljs-variable constant_'>2</span> <span class='hljs-punctuation'>(</span><span class='hljs-keyword'>fn</span> <span class='hljs-params'>a</span> <span class='hljs-params'>b</span> <span class='hljs-keyword'>=></span> a <span class='hljs-operator'><</span> b<span class='hljs-punctuation'>)</span> my_tree
<span class='hljs-comment'>(* my_new_tree == 5
* / \
* 2
*)</span>
<span class='hljs-keyword'>let</span> my_newer_tree = <span class='hljs-title function_'>btree</span><span class='hljs-punctuation'>:</span>insert <span class='hljs-variable constant_'>7</span> <span class='hljs-punctuation'>(</span><span class='hljs-keyword'>fn</span> <span class='hljs-params'>a</span> <span class='hljs-params'>b</span> <span class='hljs-keyword'>=></span> a <span class='hljs-operator'><</span> b<span class='hljs-punctuation'>)</span> my_new_tree
<span class='hljs-comment'>(* my_newer_tree == 5
* / \
* 2 7
* / \ / \
*)</span>
<span class='hljs-keyword'>let</span> my_newest_tree = <span class='hljs-title function_'>btree</span><span class='hljs-punctuation'>:</span>insert <span class='hljs-variable constant_'>9</span> <span class='hljs-punctuation'>(</span><span class='hljs-keyword'>fn</span> <span class='hljs-params'>a</span> <span class='hljs-params'>b</span> <span class='hljs-keyword'>=></span> a <span class='hljs-operator'><</span> b<span class='hljs-punctuation'>)</span> my_newer_tree
<span class='hljs-comment'>(* my_newest_tree == 5
* / \
* 2 7
* / \ / \
* 9
*)</span>
# <span class='hljs-keyword'>end</span>
iterate_tree_df: ('0 -> unit) -> (btree '0) -> unit
Runs the passed function on each element in the tree depth-first, then returns unit.
Example
# <span class='hljs-keyword'>module</span> demo =
<span class='hljs-keyword'>let</span> lt = <span class='hljs-keyword'>fn</span> <span class='hljs-params'>a</span> <span class='hljs-params'>b</span> <span class='hljs-keyword'>=></span> a <span class='hljs-operator'><</span> b
<span class='hljs-keyword'>let</span> my_tree = <span class='hljs-title class_'>btree</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>Nil</span> <span class='hljs-punctuation'>(</span><span class='hljs-punctuation'>)</span> <span class='hljs-operator'>|></span> <span class='hljs-variable constant_'>5</span> lt <span class='hljs-operator'>|></span> <span class='hljs-variable constant_'>2</span> lt <span class='hljs-operator'>|></span> <span class='hljs-variable constant_'>7</span> lt <span class='hljs-operator'>|></span> <span class='hljs-variable constant_'>8</span> lt <span class='hljs-operator'>|></span> <span class='hljs-variable constant_'>3</span> lt <span class='hljs-operator'>|></span> <span class='hljs-variable constant_'>1</span> lt
<span class='hljs-keyword'>let</span> <span class='hljs-punctuation'>(</span><span class='hljs-punctuation'>)</span> = <span class='hljs-title class_'>btree</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>iterate_tree_df</span> <span class='hljs-punctuation'>(</span><span class='hljs-keyword'>fn</span> <span class='hljs-params'>a</span> <span class='hljs-keyword'>=></span> string<span class='hljs-punctuation'>:</span>from_int <span class='hljs-operator'>|></span> <span class='hljs-title function_'>std</span><span class='hljs-punctuation'>:</span>print_string<span class='hljs-punctuation'>)</span> my_tree
<span class='hljs-comment'>(* my_tree == 5
* / \
* 2 7
* / \ / \
* 1 3 8
*)</span>
<span class='hljs-comment'>(* prints 123578 *)</span>
# <span class='hljs-keyword'>end</span>
iterate_tree_bf: ('0 -> unit) -> (btree '0) -> unit
Runs the passed function on each element in the tree breadth-first, then returns unit.
Example
# <span class='hljs-keyword'>module</span> demo =
<span class='hljs-keyword'>let</span> lt = <span class='hljs-keyword'>fn</span> <span class='hljs-params'>a</span> <span class='hljs-params'>b</span> <span class='hljs-keyword'>=></span> a <span class='hljs-operator'><</span> b
<span class='hljs-keyword'>let</span> my_tree = <span class='hljs-title class_'>btree</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>Nil</span> <span class='hljs-punctuation'>(</span><span class='hljs-punctuation'>)</span> <span class='hljs-operator'>|></span> <span class='hljs-variable constant_'>5</span> lt <span class='hljs-operator'>|></span> <span class='hljs-variable constant_'>2</span> lt <span class='hljs-operator'>|></span> <span class='hljs-variable constant_'>7</span> lt <span class='hljs-operator'>|></span> <span class='hljs-variable constant_'>8</span> lt <span class='hljs-operator'>|></span> <span class='hljs-variable constant_'>3</span> lt <span class='hljs-operator'>|></span> <span class='hljs-variable constant_'>1</span> lt
<span class='hljs-keyword'>let</span> <span class='hljs-punctuation'>(</span><span class='hljs-punctuation'>)</span> = <span class='hljs-title class_'>btree</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>iterate_tree_bf</span> <span class='hljs-punctuation'>(</span><span class='hljs-keyword'>fn</span> <span class='hljs-params'>a</span> <span class='hljs-keyword'>=></span> <span class='hljs-title class_'>string</span><span class='hljs-punctuation'>::</span>from_int <span class='hljs-operator'>|></span> <span class='hljs-title class_'>std</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>print_string</span><span class='hljs-punctuation'>)</span> my_tree
<span class='hljs-comment'>(* my_tree == 5
* / \
* 2 7
* / \ / \
* 1 3 8
*)</span>
<span class='hljs-comment'>(* prints 521378 *)</span>
# <span class='hljs-keyword'>end</span>
map_tree: ('0 -> '1) -> (btree '0) -> (btree '1)
Returns a copy of the passed tree with the passed function applied to each element.
Examples
# <span class='hljs-keyword'>module</span> demo =
<span class='hljs-keyword'>let</span> lt = <span class='hljs-keyword'>fn</span> <span class='hljs-params'>a</span> <span class='hljs-params'>b</span> <span class='hljs-keyword'>=></span> a <span class='hljs-operator'><</span> b
<span class='hljs-keyword'>let</span> my_tree = <span class='hljs-title class_'>btree</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>Nil</span> <span class='hljs-punctuation'>(</span><span class='hljs-punctuation'>)</span> <span class='hljs-operator'>|></span> <span class='hljs-variable constant_'>5</span> lt <span class='hljs-operator'>|></span> <span class='hljs-variable constant_'>2</span> lt <span class='hljs-operator'>|></span> <span class='hljs-variable constant_'>7</span> lt <span class='hljs-operator'>|></span> <span class='hljs-variable constant_'>8</span> lt <span class='hljs-operator'>|></span> <span class='hljs-variable constant_'>3</span> lt <span class='hljs-operator'>|></span> <span class='hljs-variable constant_'>1</span> lt
<span class='hljs-comment'>(* my_tree == 5
* / \
* 2 7
* / \ / \
* 1 3 8
*)</span>
<span class='hljs-keyword'>let</span> my_mapped_tree = <span class='hljs-title function_'>btree</span><span class='hljs-punctuation'>:</span>map_tree <span class='hljs-punctuation'>(</span><span class='hljs-keyword'>fn</span> <span class='hljs-params'>a</span> <span class='hljs-keyword'>=></span> a <span class='hljs-operator'>*</span> <span class='hljs-variable constant_'>2</span><span class='hljs-punctuation'>)</span> my_tree
<span class='hljs-comment'>(* my_mapped_tree == 10
* / \
* 4 14
* / \ / \
* 2 6 16
*)</span>
# <span class='hljs-keyword'>end</span>
string
string
is a module that provides functions for operating on strings
Functions
print: string -> std:unit
Prints the passed string to the console.
Example
# <span class='hljs-keyword'>module</span> demo =
<span class='hljs-keyword'>let</span> <span class='hljs-punctuation'>(</span><span class='hljs-punctuation'>)</span> = <span class='hljs-title class_'>string</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>print</span> <span class='hljs-string'>"Hi"</span>
<span class='hljs-comment'>(* Prints "Hi" *)</span>
# <span class='hljs-keyword'>end</span>
length: string -> integer
Returns the length of the passed string.
Example
# <span class='hljs-keyword'>module</span> demo =
<span class='hljs-keyword'>let</span> my_int = <span class='hljs-title class_'>string</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>length</span> <span class='hljs-string'>"Hello"</span>
<span class='hljs-comment'>(* my_int == 5 *)</span>
# <span class='hljs-keyword'>end</span>
concatenate: string -> string -> string
Adds the second string to the end of the first.
Example
# <span class='hljs-keyword'>module</span> demo =
<span class='hljs-keyword'>let</span> <span class='hljs-punctuation'>(</span><span class='hljs-punctuation'>)</span> = <span class='hljs-title class_'>string</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>concatenate</span> <span class='hljs-string'>"Kasane"</span> <span class='hljs-string'>" Teto"</span> <span class='hljs-operator'>|></span> <span class='hljs-title class_'>string</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>print</span>
<span class='hljs-comment'>(* prints "Kasane Teto" *)</span>
# <span class='hljs-keyword'>end</span>
integer
integer
is a module that provides functions for operating on integers.
Functions
abs: integer -> integer
Returns the absolute value of the passed integer.
Example
# <span class='hljs-keyword'>module</span> demo =
<span class='hljs-keyword'>let</span> five = <span class='hljs-title class_'>integer</span><span class='hljs-punctuation'>::</span>abs <span class='hljs-operator'>-</span><span class='hljs-variable constant_'>5</span>
<span class='hljs-keyword'>let</span> alsofive = <span class='hljs-title class_'>integer</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>abs</span> <span class='hljs-variable constant_'>5</span>
# <span class='hljs-keyword'>end</span>
pow: integer -> integer -> integer
Returns the first passed integer to the power of the second passed integer.
Example
# <span class='hljs-keyword'>module</span> demo =
<span class='hljs-keyword'>let</span> four = <span class='hljs-title class_'>integer</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>pow</span> <span class='hljs-variable constant_'>2</span> <span class='hljs-variable constant_'>2</span>
<span class='hljs-keyword'>let</span> eight = <span class='hljs-title class_'>integer</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>pow</span> <span class='hljs-variable constant_'>2</span> <span class='hljs-variable constant_'>3</span>
# <span class='hljs-keyword'>end</span>
real
real
is a module that provides functions for operating on reals.
Functions
abs: real -> real
Returns the absolute value of the passed real.
Example
<span class='hljs-keyword'>let</span> fourpointfive = <span class='hljs-title class_'>real</span><span class='hljs-punctuation'>::</span>abs <span class='hljs-operator'>-</span><span class='hljs-variable constant_'>4.5</span>
<span class='hljs-keyword'>let</span> alsofourpointfive = <span class='hljs-title class_'>real</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>abs</span> <span class='hljs-variable constant_'>4.5</span>
truncate: real -> real
Truncates the passed real by removing the decimal component.
Example
<span class='hljs-keyword'>let</span> four = <span class='hljs-title class_'>real</span><span class='hljs-punctuation'>::</span><span class='hljs-title function_'>truncate</span> <span class='hljs-variable constant_'>4.5</span>
Appendix
The following sections contain reference material that may make your development experience more halcyon.
Halcyon
- calm; peaceful; tranquil.
- happy; blissful; carefree.
- prosperous; wealthy.
Appendix A: Keywords
The following list contains keywords that are reserved for current or future use by the Halcyon language. As such, they cannot be used as identifiers.
Keywords Currently in Use
The following is a list of keywords currently in use, with their functionality described.
Keyword | Use | Example |
---|---|---|
module , end | Declares the beginning and end of a module respectively | module demo = ... end |
import | Imports a function from another language, such as JavaScript or C | |
let | Defines a variable | let myint = 5 |
do | Executes an expression (like a main function) | do string::print "Hi" |
type | Defines a new type, or type alias | type twoints = (std::int, std::int) |
match , with | Matches a discriminant with one or more patterns | match myint with |4 => ... |5 => ... |
if ,then ,else | Evaluates to a value based on a boolean expression | if myint == 5 then ... else ... |
fn | Declares a function | let myfn = fn a => a + 1 |
of | Denotes types that a constructor name contains | type result = fn A B => Ok of A | Error of B |
in | Limits a variable's scope to the next expression | let myint = 5 in let mynewint = myint + 1 |
Appendix B: Operators and Symbols
This appendix contains a glossary of Halcyon's syntax, including operators and other symbols.
Operators
Symbol | Description |
---|---|
(unary) - -. | arithmetic negation |
(unary) not | logical negation |
* *. | multiplication |
/ /. | division |
% | modulus |
+ +. | addition |
- -. | subtraction |
(function call) | |
>> << | function composition |
xor | logical XOR |
or | logical OR |
|> | function pipe |
== != <= >= < > | comparison |
and | logical AND |
; |
Non-operator Symbols
The following list contains all symbols that don’t function as operators; that is, they don’t behave like a function.
Symbol | Description |
---|---|
ident : type | Type constraint |
() | Unit literal/Empty tuple |
ident : () | Alias for std::unit |
(expr,) | Single element tuple |
(expr, ...) | Tuple expression |
(type,...) | Tuple type |
[type] | Array type |
[expr, ...] | Array literal |
ident::ident | Module path |
ident = expr | Assignment |
{ident,...} | Struct type |
{expr,...} | Struct literal |
ident.ident | Struct field access |
pat | pat | Pattern alternatives |
type | type | Sum type alternatives |
pat => expr | Part of match arm syntax |
signature => expr | Part of function syntax |
_ | Wildcard pattern match |
_ | “Ignored” pattern binding |
-- | Line comment |
(*...*) | Block Comment |