Preface
Overview
import {
std { compare.Ordering, io.stdin },
random { Random, thread_rng },
};
func read_number(buffer: $String) -> Result<U32, ParseError> {
buffer.clear;
stdin().read_line($buffer).expect;
buffer.trim.parse
}
func main() {
let mut buffer = String.new;
print("Please enter a number: ");
let number = while_failing {
read_number($buffer)
} {
print("Input must be a number.");
};
let correct = 0.to(number).random(thread_rng());
print("Guess a number 0 to \(number): ");
loop continue!{
let guess = read_number($buffer).catch {
print("Input must be a number.");
continue!();
};
correct.compare(&guess).match {
Ordering.Greater -> print("Higher..."),
Ordering.Less -> print("Lower..."),
Ordering.Equal -> {
print("Correct!");
return!();
},
};
};
};
Inspirations
Major Inspirations
Language | Inspiration |
---|---|
Rust | philosophy, syntax, features |
Gleam | philosophy, syntax, features |
Smalltalk | philosophy, features |
Swift | syntax, ergonomics |
Gleam was only discovered by me after significant design work for Sonance was already complete. Still, they two languages are very similar! That is why Gleam is listed as a major inspiration.
Minor Inspirations
Strings
Escape Codes
See Rust lol.
String Interpolation
Interpolation can be done with a special escape sequence \(...)
where the ...
is an arbitrary expression.
print("\(a) plus \(b) is \(a + b)");
Multiline Strings
Both after the opening quote and before closing quote must be only whitespace, which is stripped.
Starting whitespace of the closing quote is commonly stripped from all middle lines, syntax error if a line has less starting whitespace.
Newlines can be escaped using \
at the end of the line.
let example = "
foo\
bar
";
assert_equal(example, "foobar");
Raw Strings
Raw strings are created by prefixing the opening quote and suffixing the closing quote with a set number of #
characters.
Within raw strings, normal special characters are interpreted literally, including sequences of lesser amounts of #
.
To use escape sequences, prefix the \
character with the same amount of #
as the opening and closing quotes.
let example ###"
"you can put whatever here"
##" not affected
###\n escape codes
###\(value) interpolation works
"###;
Functions
func add(x: U32, y: U32) -> U32 {
x + y
}
Modules
module my_module {}
File Module
module;
Imports
import {
library1.foo,
library2.bar,
};
Types
Custom Types
type MyType {
VariantA,
VariantB,
}
Records
type MyRecord(foo: U32, bar: Boolean);
Anonymous Records
fn sincos(x: F64) -> type(F64, F64) {
type(x.sin, x.cos)
}
Type Modules
module type MyType {
...
}
Type Aliases
type Alias = MyType;
Blocks
Example: scope
func scope<T>(body: block() -> T) -> T {
body!()
}
Example: Option<T>
condition
.then { print("was true") }
.else { print("was false") }
func then<T>(self: Boolean, body: block() -> T) -> Option<T> {
match(self) {
True -> Some(body!()),
False -> None,
}
}
func else<T>(self: Option<T>, body: block() -> T) -> T {
match(self) {
Some(value) -> value,
None -> body!(),
}
}
Example: while
let mut i = 1;
while { i < 6 } {
print(i);
i = i + 1;
}
func while(condition: block() -> Boolean, body: block()) {
loop {
condition!().then {
body!();
};
};
}
Labels
Backpassing
Function based
- Gleam's
use
expressions - Koka's
with
statement - Roc's "backpassing" (which unfortunately appears to be a removed feature)
Monad based
Uses With Containers
func maybe_sum(x: Option<U32>, y: Option<U32>) -> Option<U32> {
x.flat_map do(i) {
y.flat_map do(j) {
Some(i + j)
}
}
}
func maybe_sum(x: Option<U32>, y: Option<U32>) -> Option<U32> {
let i = x.flat_map?;
let j = y.flat_map?;
Some(i + j)
}
Backpassing match
Special Form
match(foo) {
True?,
False -> print("nope"),
};
print("yep");
Expression returns a tuple.
With values
match(foo) {
Pass(value)?,
Fail(error) -> print("oh no: \(error)"),
};
print("yippee: \(value)");
Traits
Trait Modules
module type MyType -> MyTrait {
...
}
Advanced Modules
Named Type Modules
module my_module MyType {}
Named Trait Modules
module my_module MyType -> MyTrait {}
Language Reference
Keywords
Context | Keyword | Description |
---|---|---|
Modules | module | Declare modules or implementations |
Modules | import | Import items from other modules |
Modules | export | Make item available to rest of current package |
Modules | public | Make item available to external packages |
Types | struct | Declare struct type |
Types | enum | Declare enum types |
Types | type | Alias types |
Types | trait | Declare traits |
Functions | func | Declare functions |
Functions | do | Declare arguments in a block literal |
Functions | block | Block type literal |
Patterns | let | Declare variables |
Patterns | mut | Make place mutable |
Patterns | set | Assign value to place |
Patterns | match | Pattern match an value |
Punctuation
Name | Symbol | Description |
---|---|---|
= | Assignment, labeled parameters | |
. | Pipeline | |
; | Statement ending | |
, | General purpose separator | |
: | Type ascription | |
() | Parameters, arguments, grouped expressions | |
{} | Code blocks | |
<> | Type generic | |
! | Label declaration, label call | |
? | Implicit argument, backpassing | |
-> | Return type ascription, match branches | |
& | Shared references | |
$ | Unique References |