# Syntax
https://tour.gleam.run/everything/
## Comments
- `//`
- [Documentation](https://tour.gleam.run/functions/documentation-comments/)
- `///` is for documenting types and functions and comes before the subject
- `////` is for documenting modules and comes at the top of the module
## `import`
https://tour.gleam.run/basics/unqualified-imports/
- `import <path>`
- Unqualified imports are done via `import <path>.{<stuff>}`
- Need to use `type` for any types that are imported (this does not apply to variants of types!)
- Put one's own code in a [`<packagename>.gleam` and/or `src/<packagename>/` directory](https://gleam.run/writing-gleam/)
- Can import from each other as appropriate
- [For anything not meant for public consumption but needs to be public for testing](https://gleam.run/writing-gleam/), put in a `src/<packagename>/internal` directory
## Equality
https://tour.gleam.run/basics/equality/
- `==`
- `!=`
## `Int`
https://tour.gleam.run/basics/ints/
### Arithmetic
- `+`
- `-`
- `/`
- `*`
- `%`
### Comparisons
- `>`
- `<`
- `>=`
- `<=`
### Format
Can use `_` as a separator.
#### Prefixes
- `0b`
- `0o`
- `0x`
## `Float`
https://tour.gleam.run/basics/floats/
### Arithmetic
- `+.`
- `-.`
- `/.`
- `*.`
### Comparisons
- `>.`
- `<.`
- `>=.`
- `<=.`
### Format
Can use `_` as a separator.
Scientific notation via `<base>e<power>`
## `String`
https://tour.gleam.run/basics/strings/
### Operators
- `<>` for concatenation
### Format
- `"<content>"`
- `\"`
- `\\`
- `\f`
- `\n`
- `\r`
- `\t`
- `\us{<codepoint>}`
## `Bool`
https://tour.gleam.run/basics/bools/
### Format
- `True`
- `False`
### Operators
- `||` (short-circuits)
- `&&` (short-circuits)
- `!`
## Assignment
https://tour.gleam.run/basics/assignments/
- `let <snake_case> = <assign>` (immutable)
- `_<name>` for discarding
- `let <snake_case>: <type> = <assign>` for explicit type annotation
- Destructuring in the assignment is allowed
- You can rebind to the same name
- `let assert <pattern> = <expression>` will [crash the program if the pattern doesn't match](https://tour.gleam.run/advanced-features/let-assert/)
## Blocks
https://tour.gleam.run/basics/blocks/
- `{expressions}` creates a new scope and are evaluated earlier than operators (i.e. used over parentheses as in other languages)
## `List`
https://tour.gleam.run/basics/lists/
- `[<items>]` separated by commas (a trailing comma is okay)
- `[<items>, ..<variable>]` to (immutably) prepend
- Single-linked list
## `const`
https://tour.gleam.run/basics/constants/
- `const <literal>` at the module scope
## `fn`
https://tour.gleam.run/functions/functions/
- `fn <name>(<param>: <type>) -> <return type> { <body> }`; type annotations on parameters and the return type are optional
- The last expression is the return value
- Prefix `pub` to make a function public
- `fn(<params>)` is for declaring [anonymous functions](https://tour.gleam.run/functions/anonymous-functions/); syntax is otherwise the same as named functions
- Typing functions is the same as the anonymous function syntax
- `<name>(<params>, _, <params>)` is for [function captures](https://tour.gleam.run/functions/function-captures/)
- Shorthand for `fn(a) {<name>(<params>, a, <params>)}`
- Only works for a single argument to the capture
- [Generics](https://tour.gleam.run/functions/generic-functions/) is supported by using a lowercase name for a type annotation, e.g. `fn spam(x: type_, y: type_) -> type_ { ... }`
- [Pipelining](https://tour.gleam.run/functions/pipelines/) is done with `<subject> |> <target>`
- If the subject can be used as the first argument to the target then it will be used that way, e.g. the `a |> b()` becomes `b(a)`
- Otherwise it translates to an argument to whatever the target returns, e.g. `a |> b()` becomes `b()(a)`
- Use function captures if the subject needs to be passed to a parameter other than the first one
- To make it easier to pipeline with a function, the "subject" of a function call is specified first
- [Labelled arguments](https://tour.gleam.run/functions/labelled-arguments/) allows passing a parameter by name w/ the syntax `<name>: <param>`
- Using the names is optional
- You can use the same name for both the outer and inner name
- Unnamed parameters must come first
- There is no performance impact
- Shorthand -- as of 1.4 -- is `<var>:` to use the variable of the same name as the label
## `@deprecated`
https://tour.gleam.run/functions/deprecations
```gleam
@deprecated(<reason>)
fn ...
```
## `case`
https://tour.gleam.run/flow-control/case-expressions/
```gleam
case <expression> {
<pattern> -> <expression>
_ -> <expression>
}
```
- Can use [variable patterns](https://tour.gleam.run/flow-control/variable-patterns/) to assign in the pattern itself; `<variable> -> <expression>`
- `<pattern> as <variable>` specifies a [pattern alias](https://tour.gleam.run/flow-control/pattern-aliases/)
- [String patterns](https://tour.gleam.run/flow-control/string-patterns/) allow for matching by prefix; `<prefix> <> <variable>`
- [List patterns](https://tour.gleam.run/flow-control/list-patterns/)
- `[]` is empty
- Use `_` to represent any item, e.g. `[_, _]` is a list of two items
- You can use literals in any position
- The spread pattern `..` matches the rest of a list
- You can have [multiple subjects](https://tour.gleam.run/flow-control/multiple-subjects/), separated by commas: `case <subject 1>, <subject 2 { <match subject 1>, <match subject 2> -> <expression> }`
- `|` for [alternative patterns](https://tour.gleam.run/flow-control/alternative-patterns/)
- If variable names are used then they must be the same name in all alternatives
- You can't nest an alternative pattern
- `<pattern> if <clause>` for a [guard](https://tour.gleam.run/flow-control/guards/)
## Tuples
https://tour.gleam.run/data-types/tuples/
- `#(<items>)` for creating
- `<variable>.<index>` to access elements
## `type`
### Type Aliases
https://tour.gleam.run/basics/type-aliases/
- `type <CapWords>`
- `pub type <CapWords>` for a public name
- To [[#`import` |import]] a type unqualified, the name needs to be prefixed with `type`, e.g. `import gleam/option.{type Option}`
- Variants of types must be imported as normal, e.g., `gleam/option.{Some}`
### Custom types
https://tour.gleam.run/data-types/custom-types/
- `type <Name> { <Variants> }`
- Enum-like, i.e. defining constructor for a variant
- Name and variants are CapWords
- Variant names are **not** scoped, and so are exposed as a top-level name
- The type name is just that: a name of the type
- While the variants are like defining unique names that happen to a type in common
- If there's only a single variant then you can reuse the type name for the variant
#### Records
- Define a [record](https://tour.gleam.run/data-types/records/) variant by listing the fields, e.g. `<Name>(<fields>)`
- If you specify a field name then it acts as an argument label
- Label shorthand works
- Otherwise just specify the type
- If you define the same argument label on all variants with the same type, then you can use a [record accessor](https://tour.gleam.run/data-types/record-accessors/) via `<var>.<name>`
- [Record updates](https://tour.gleam.run/data-types/record-updates/) create a copy of a record with different values via `..<var>` as the first argument to the constructor, i.e. `<Name>(..<record>, <items>)`
- Must come **first** in the list of arguments to the constructor
- Custom types can be [generic](https://tour.gleam.run/data-types/generic-custom-types/) by specifying the type variable by the name, i.e. `<Name>(<TypeVars>) { <variants> }`
- An [external type](https://tour.gleam.run/advanced-features/externals/) has no constructor (i.e. body), making the shape private/hidden/unknown for use with [[#`@external`]]
## `Nil`
https://tour.gleam.run/data-types/nil/
- Both a type and value
- Returned by functions that return nothing
- Because it is a type it cannot be used as a value with any other type
## `Result`
https://tour.gleam.run/data-types/results/
```gleam
pub type Result(ok, error) {
Ok(ok)
Error(error)
}
```
- Due to the lack of inheritance or interfaces, the error type is completely generic
- It is universally used as a function return type even when [`gleam/option.{type Option}`](https://hexdocs.pm/gleam_stdlib/gleam/option.html#Option) makes sense
- "[The Option type should only be used for taking optional values as function arguments, or for storing them in other data structures.](https://hexdocs.pm/gleam_stdlib/gleam/option.html)"
- Use `Nil` as the error condition (thanks to to the error type being generic)
## `BitArray`
https://tour.gleam.run/data-types/bit-arrays/
- `<<>>` surrounds the segments (there can be 0 or more)
- Each segment can have options
- Specified via `:<option>` after the value
- Possible options are:
- `size`
- `unit`
- `bits`
- `bytes`
- `float`
- `int`
- `big`
- `little`
- `native`
- `signed`
- `unsigned`
- `utf8`
- `utf16`
- `utf32`
- `utf8_codepoint`
- `utf16_codepoint`
- `utf32_codepoint`
## `use`
https://tour.gleam.run/advanced-features/use/
```gleam
use <argument names> = <function>(<args>)
<callback>
```
[translates to](https://tour.gleam.run/advanced-features/use-sugar/) `<function>(<args>, fn(<argument names>) {<callback})`
- Can chain them when you are nesting calls with callbacks
- Somewhat like pipelining but for callbacks as the last argument to the function call and outside-in instead of inside-out
## `todo`
https://tour.gleam.run/advanced-features/todo/
- `todo` has the compiler warn and the runtime raise an error
- `todo as "<message>"` includes the message in the warning/error
## `panic`
https://tour.gleam.run/advanced-features/panic/
- `panic` to error out the program
- `panic as "<message>"`
## `@external`
https://tour.gleam.run/advanced-features/externals/
```gleam
@external(<language>, <file path>, <function name>)
fn <function name>(<args>) -> <return type>
```
- The return type needs to be an external [[#`type` |type]]
- You can specify [multiple targets](https://tour.gleam.run/advanced-features/multi-target-externals/) to implement the function
- A [fallback](https://tour.gleam.run/advanced-features/external-gleam-fallbacks/) written in Gleam can be provided by implementing a function body
# JavaScript
There's support for [JS as an FFI](https://gleam.run/book/tour/external-functions.html) along with a [prelude](https://github.com/gleam-lang/gleam/blob/main/compiler-core/templates/prelude.mjs) (available as `gleam.mjs` in your project; might need to [export it](https://gleam.run/writing-gleam/command-line-reference/)). [gleam_javascript](https://hexdocs.pm/gleam_javascript/) can be used to "work with JavaScript types and values in Gleam" and as example code for how to wrap things.
# Appendix
## Tokens
[Parser](https://github.com/gleam-lang/gleam/blob/7eaad191566107784495ba41a4550f1bdf618311/compiler-core/src/parse/token.rs) after the [1.0 announcement](https://gleam.run/news/gleam-version-1/).
```Rust
use std::fmt;
use ecow::EcoString;
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Token {
Name { name: EcoString },
UpName { name: EcoString },
DiscardName { name: EcoString },
Int { value: EcoString },
Float { value: EcoString },
String { value: EcoString },
CommentDoc { content: String },
// Groupings
LeftParen, // (
RightParen, // )
LeftSquare, // [
RightSquare, // }
LeftBrace, // {
RightBrace, // }
// Int Operators
Plus,
Minus,
Star,
Slash,
Less,
Greater,
LessEqual,
GreaterEqual,
Percent,
// Float Operators
PlusDot, // '+.'
MinusDot, // '-.'
StarDot, // '*.'
SlashDot, // '/.'
LessDot, // '<.'
GreaterDot, // '>.'
LessEqualDot, // '<=.'
GreaterEqualDot, // '>=.'
// String Operators
LtGt, // '<>'
// Other Punctuation
Colon,
Comma,
Hash, // '#'
Bang, // '!'
Equal,
EqualEqual, // '=='
NotEqual, // '!='
Vbar, // '|'
VbarVbar, // '||'
AmperAmper, // '&&'
LtLt, // '<<'
GtGt, // '>>'
Pipe, // '|>'
Dot, // '.'
RArrow, // '->'
LArrow, // '<-'
DotDot, // '..'
At, // '@'
EndOfFile,
// Extra
CommentNormal,
CommentModule,
EmptyLine,
// Keywords (alphabetically):
As,
Assert,
Auto,
Case,
Const,
Delegate,
Derive,
Echo,
Else,
Fn,
If,
Implement,
Import,
Let,
Macro,
Opaque,
Panic,
Pub,
Test,
Todo,
Type,
Use,
}
impl Token {
pub fn guard_precedence(&self) -> Option<u8> {
match self {
Self::VbarVbar => Some(1),
Self::AmperAmper => Some(2),
Self::EqualEqual | Self::NotEqual => Some(3),
Self::Less
| Self::LessEqual
| Self::LessDot
| Self::LessEqualDot
| Self::GreaterEqual
| Self::Greater
| Self::GreaterEqualDot
| Self::GreaterDot => Some(4),
_ => None,
}
}
}
impl fmt::Display for Token {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let s = match self {
Token::Name { name } | Token::UpName { name } | Token::DiscardName { name } => {
name.as_str()
}
Token::Int { value } | Token::Float { value } | Token::String { value } => {
value.as_str()
}
Token::AmperAmper => "&&",
Token::As => "as",
Token::Assert => "assert",
Token::At => "@",
Token::Auto => "auto",
Token::Bang => "!",
Token::Case => "case",
Token::Colon => ":",
Token::Comma => ",",
Token::CommentDoc { .. } => "///",
Token::CommentModule => "////",
Token::CommentNormal => "//",
Token::Const => "const",
Token::Delegate => "delegate",
Token::Derive => "derive",
Token::Dot => ".",
Token::DotDot => "..",
Token::Echo => "echo",
Token::Else => "else",
Token::EmptyLine => "EMPTYLINE",
Token::EndOfFile => "EOF",
Token::Equal => "=",
Token::EqualEqual => "==",
Token::Fn => "fn",
Token::Greater => ">",
Token::GreaterDot => ">.",
Token::GreaterEqual => ">=",
Token::GreaterEqualDot => ">=.",
Token::GtGt => ">>",
Token::Hash => "#",
Token::If => "if",
Token::Implement => "implement",
Token::Import => "import",
Token::LArrow => "<-",
Token::LeftBrace => "{",
Token::LeftParen => "(",
Token::LeftSquare => "[",
Token::Less => "<",
Token::LessDot => "<.",
Token::LessEqual => "<=",
Token::LessEqualDot => "<=.",
Token::Let => "let",
Token::LtGt => "<>",
Token::LtLt => "<<",
Token::Macro => "macro",
Token::Minus => "-",
Token::MinusDot => "-.",
Token::NotEqual => "!=",
Token::Opaque => "opaque",
Token::Panic => "panic",
Token::Percent => "%",
Token::Pipe => "|>",
Token::Plus => "+",
Token::PlusDot => "+.",
Token::Pub => "pub",
Token::RArrow => "->",
Token::RightBrace => "}",
Token::RightParen => ")",
Token::RightSquare => "]",
Token::Slash => "/",
Token::SlashDot => "/.",
Token::Star => "*",
Token::StarDot => "*.",
Token::Test => "test",
Token::Todo => "todo",
Token::Type => "type",
Token::Use => "use",
Token::Vbar => "|",
Token::VbarVbar => "||",
};
write!(f, "\"{s}\"")
}
}
```