trick
Code generated using trick is built up by combining expressions and
statements into a module.
The trick API is designed to make it as hard as possible to make mistakes
in your generation.
A trick code generator will look something like this:
use pi <- trick.constant("pi", trick.Private, trick.float(3.14))
use circle_area <- trick.function("circle_area", trick.Public, {
use radius <- trick.parameter("radius", trick.float_type())
trick.function_body({
use radius_squared <- trick.variable(
"radius_squared",
trick.multiply_float(radius, radius),
)
trick.expression(trick.multiply_float(radius_squared, pi))
})
})
trick.end_module()
The above code, when passed to to_string, will produce the
following code:
const pi = 3.14
pub fn circle_area(radius: Float) -> Float {
let radius_squared = radius *. radius
radius_squared *. pi
}
The called functions more or less mimic the structure of the resulting code, with the exception for a few boilerplate functions needed to convert between types to appease the Gleam type system.
Expression generation is pretty intuitive and straightforward, but some of the functions for creating custom types and top-level functions can get a bit complicated due to type system limitations. See the documentation of individual functions for full explanations of how they are used.
Table of contents
Definitions
Statements
Expressions
Expressionintfloatstringboolniladdadd_floatsubtractsubtract_floatmultiplymultiply_floatdividedivide_floatremainderconcatenateandorequalnot_equalless_thanless_than_floatless_than_or_equalless_than_or_equal_floatgreater_thangreater_than_floatgreater_than_or_equalgreater_than_or_equal_floatnegate_intnegate_boollistprependtupletuple_indexpanic_todo_echo_anonymouscall
Types
TypeConcreteTypeFieldMapErrorint_typefloat_typestring_typebool_typenil_typebit_array_typeutf_codepoint_typelist_typetuple_typefunction_typegeneric
Best practises
To avoid confusion, it’s usually best if you name any variables after their names in the generated code. For example, if you’re defining a variable, assign it to a variable of the same name in your generator code:
// DO:
use my_variable <- trick.variable("my_variable", trick.int(1))
// DON'T:
use number_one <- trick.variable("my_variable", trick.int(1))
The same applies to functions, constants, and types (although you may need to change these a little as your variable will be in the same scope as values). This helps to avoid cases where you (accidentally or intentionally) shadow a variable in the generated code, but don’t shadow it in your generator code, allowing out-of-scope values to be referenced.
Break up your code generators into multiple functions. While the API is designed to be as ergonomic as possible, due to limitations of the Gleam type system, generators can get quite verbose. Splitting separate parts of the code into different functions can make it easier to read and modify. After all, that’s the benefit of having code generators just be plain old Gleam code.
}
Types
A function argument with an optional label.
pub type Argument {
Argument(
label: option.Option(String),
value: Expression(Variable),
)
}
Constructors
-
Argument( label: option.Option(String), value: Expression(Variable), )
Clause
opaqueA clause of a case expression.
pub opaque type Clause
A known type for an expression. Unlike Type, this exists after
type-checking and contains the full information about each type.
pub type ConcreteType {
Custom(
module: String,
name: String,
generics: List(ConcreteType),
)
Generic(id: Int)
Unbound(id: Int)
Tuple(elements: List(ConcreteType))
Function(
parameters: List(ConcreteType),
return: ConcreteType,
field_map: option.Option(FieldMap),
)
}
Constructors
-
Custom( module: String, name: String, generics: List(ConcreteType), ) -
Generic(id: Int) -
Unbound(id: Int) -
Tuple(elements: List(ConcreteType)) -
Function( parameters: List(ConcreteType), return: ConcreteType, field_map: option.Option(FieldMap), )
Indicates that an expression is constant and can be assigned to a const.
pub type Constant
Constructor
opaqueInformation about a particular constructor. It can be turned into an expression
using construct, or a pattern using
constructor_pattern.
pub opaque type Constructor
CustomType
opaqueInformation about a custom type.
pub opaque type CustomType(a)
CustomTypeInterface
opaqueThe public interface of a custom type, containing only type information.
pub opaque type CustomTypeInterface(has_parameter)
DefinedModule
opaqueThe bare-bones interface of a module, containing only the type information
for public definitions, allowing it to be imported from other modules without
being able to generate any code. This is useful for creating typed interfaces
for existing modules that need to be imported from generated ones. See
define_module for examples.
pub opaque type DefinedModule
A type error.
pub type Error {
TypeMismatch(expected: ConcreteType, got: ConcreteType)
TupleIndexOutOfBounds(length: Int, index: Int)
InvalidTupleAccess(type_: ConcreteType)
InvalidCall(type_: ConcreteType)
InvalidListPrepend(type_: ConcreteType)
IncorrectNumberOfArguments(expected: Int, got: Int)
UnlabelledParameterAfterLabelledParameter(name: String)
UnexpectedLabelledArgument(label: String)
UnknownLabel(label: String, available_labels: List(String))
DuplicateLabel(label: String)
NoCaptureHole
DuplicateCaptureHole
InvalidName(name: String, expected: NameCase)
InvalidFieldAccess(type_: ConcreteType)
TypeDoesNotHaveField(type_: ConcreteType, field: String)
ModuleDoesNotHaveType(module: String, type_: String)
ModuleDoesNotHaveValue(module: String, value: String)
IncorrectNumberOfTypeArguments(expected: Int, got: Int)
UnexpectedGenericType(module: String, name: String)
ExpectedGenericType(module: String, name: String)
PatternDoesNotAlwaysMatch
DuplicateDefinition(name: String)
DuplicateImport(local_name: String)
ModuleDoesNotHaveConstructor(module: String, name: String)
}
Constructors
-
TypeMismatch(expected: ConcreteType, got: ConcreteType) -
TupleIndexOutOfBounds(length: Int, index: Int)Attempting to access a non-existent tuple field
-
InvalidTupleAccess(type_: ConcreteType)Attempting to perform tuple access on a value which is not a tuple
-
InvalidCall(type_: ConcreteType)Attempting to call a value which is not a function
-
InvalidListPrepend(type_: ConcreteType)Attempting to prepend to a value which is not a list
-
IncorrectNumberOfArguments(expected: Int, got: Int)Calling a function with the incorrect number of arguments
-
UnlabelledParameterAfterLabelledParameter(name: String)Attempting to define an unlabelled function parameter after a labelled parameter
-
UnexpectedLabelledArgument(label: String)Using a label in a call to a function with no labels
-
UnknownLabel(label: String, available_labels: List(String))Using a label which is not defined in the called function
-
DuplicateLabel(label: String)Attempting to define parameters with duplicate labels
-
NoCaptureHoleNo capture hole is provided to a
function_capture_altcall -
DuplicateCaptureHoleMore than one capture hole is provided to a
function_capture_altcall -
InvalidName(name: String, expected: NameCase)The name of a value does not match what is expected.
-
InvalidFieldAccess(type_: ConcreteType)Attempting field access on a value which is not a custom type.
-
TypeDoesNotHaveField(type_: ConcreteType, field: String)Attempting to access a field on a custom type which does not have said field.
-
ModuleDoesNotHaveType(module: String, type_: String) -
ModuleDoesNotHaveValue(module: String, value: String) -
IncorrectNumberOfTypeArguments(expected: Int, got: Int) -
UnexpectedGenericType(module: String, name: String) -
ExpectedGenericType(module: String, name: String) -
PatternDoesNotAlwaysMatch -
DuplicateDefinition(name: String) -
DuplicateImport(local_name: String) -
ModuleDoesNotHaveConstructor(module: String, name: String)
Expression
opaqueThe field of a custom type variant.
pub type Field {
Field(label: option.Option(String), type_: Type(NoParameters))
}
Constructors
-
Field(label: option.Option(String), type_: Type(NoParameters))
FunctionBuilder
opaqueInformation about a function which can either be turned into a function definition or an anonymous function.
Marked as either Labelled or Unlabelled.
pub opaque type FunctionBuilder(labelling)
An argument to a function capture.
pub type FunctionCaptureArgument {
CaptureArgument(value: Expression(Variable))
CaptureHole
}
Constructors
-
CaptureArgument(value: Expression(Variable)) -
CaptureHole
Indicates that a custom type has one or more type parameters.
pub type HasParameters
Indicates that a function has one or more labelled arguments can cannot be turned into an anonymous function as anonymous functions do not support labels.
pub type Labelled
Module
opaqueA module containing one or more definitions.
pub opaque type Module
ModuleInterface
opaqueThe public interface of a module. Holds the type information about a particular
module, but in order to be used in generated code, you must first import it
using import_.
pub opaque type ModuleInterface
ModuleName
opaqueAn imported module which can be used to access values.
pub opaque type ModuleName
The expected case of the name for a definition.
pub type NameCase {
SnakeCase
PascalCase
}
Constructors
-
SnakeCase -
PascalCase
Indicates that a custom type has no type parameters.
pub type NoParameters
Pattern
opaqueA typed pattern.
The type parameter indicates what kind of data the pattern holds – that is,
which variables can be referenced as a result of matching the pattern. This
is usually either Nil for patterns which do not bind variables (int patterns,
float patterns, etc.), Expression for patterns which bind a single variable
(variable patterns), or a tuple of multiple expressions for patterns which
return more than one (constructors, lists, etc.).
pub opaque type Pattern(a)
PatternList
opaqueA list of patterns which can be used to construct a tuple_pattern,
a list_pattern, or a constructor_pattern.
The first type parameter indicates which syntactic features this list contains
– it is one of Unlabelled, Labelled, or
WithTail. For example, list tail patterns cannot be used in
tuple patterns, and labels cannot be used in list patterns.
pub opaque type PatternList(features, value)
The publicity of a top-level definition.
pub type Publicity {
Public
Internal
Private
}
Constructors
-
Public -
Internal -
Private
Statement
opaqueOne or more statements that can be used in a block or function body.
pub opaque type Statement
Type
opaqueThe type of a value. This is different to ConcreteType
in that it exists before type-checking and does not contain complete
information yet.
The type parameter represents whether the type is a “type constructor”, and has generics which must be supplied before it can be used.
pub opaque type Type(parameters)
Indicates that a function does not have labelled arguments and can be turned into an anonymous function.
pub type Unlabelled
The public type interface of a value in a module.
pub type ValueInterface {
ConstantInterface(name: String, type_: Type(NoParameters))
FunctionInterface(
name: String,
parameters: List(Field),
return_type: Type(NoParameters),
)
}
Constructors
-
ConstantInterface(name: String, type_: Type(NoParameters)) -
FunctionInterface( name: String, parameters: List(Field), return_type: Type(NoParameters), )
Indicates that an expression includes a runtime computation can cannot be
assigned to a const.
pub type Variable
Indicates that a PatternList contains a list tail pattern,
meaning it can only be used for list patterns, and not tuple or constructor
patterns.
pub type WithTail
Values
pub fn add(
left: Expression(a),
right: Expression(a),
) -> Expression(Variable)
Generates a + operation.
Examples
trick.add(trick.int(1), trick.int(2)) |> trick.expression_to_string
// -> Ok("1 + 2")
pub fn add_float(
left: Expression(a),
right: Expression(a),
) -> Expression(Variable)
Generates a +. operation.
Examples
trick.add_float(trick.float(1.0), trick.float(2.0))
|> trick.expression_to_string
// -> Ok("1.0 +. 2.0")
pub fn and(
left: Expression(a),
right: Expression(a),
) -> Expression(Variable)
Generates a && operation.
Examples
trick.and(trick.bool(True), trick.bool(False))
|> trick.expression_to_string
// -> Ok("True && False")
pub fn anonymous(
function: FunctionBuilder(Unlabelled),
) -> Expression(Variable)
Generates an anonymous function.
Examples
trick.anonymous({
use a <- trick.parameter("a", trick.int_type())
use b <- trick.parameter("b", trick.int_type())
trick.add(a, b) |> trick.expression |> trick.function_body
})
|> trick.expression_to_string
// -> Ok("fn(a: Int, b: Int) { a + b }")
pub fn assert_(
condition: Expression(a),
message: option.Option(Expression(a)),
) -> Statement
Generates an assert statement with an optional message. The condition must
be of type Bool, and the message, if present, must be of type String.
Like expression, assert by default terminates the block
and doesn’t expect a continuation. To place statements after an assert,
use discard.
Examples
trick.assert_(trick.bool(True), None)
|> trick.block
|> trick.expression_to_string
Will generate:
{
assert True
}
trick.assert_(trick.bool(False), Some(trick.string("This will panic")))
|> trick.block
|> trick.expression_to_string
Will generate:
{
assert False as \"This will panic\"
}
trick.assert_(trick.int(1), None)
|> trick.block
|> trick.expression_to_string
// -> Error(TypeMismatch(expected: Bool, got: Int))
trick.assert_(trick.bool(True), Some(trick.bool(True)))
|> trick.block
|> trick.expression_to_string
// -> Error(TypeMismatch(expected: String, got: Bool))
pub fn assignment_pattern(
pattern: Pattern(a),
name: String,
) -> Pattern(#(a, Expression(Variable)))
Generates a pattern which matches a specific value and binds it to a variable.
To match any value and bind it to a variable, see
variable_pattern.
Examples
trick.case_(trick.int(1), [
{
use x <- trick.clause(
trick.assignment_pattern(trick.int_pattern(1), "x"),
)
trick.add(x, 1)
},
{
use x <- trick.clause(trick.variable_pattern("x"))
x
},
])
|> trick.expression_to_string
Will generate:
case 1 {
1 as x -> x + 1
x -> x
}
pub fn block(inner: Statement) -> Expression(Variable)
Generates a block wrapping one or more statements.
Examples
trick.int(1)
|> trick.add(trick.int(2))
|> trick.expression
|> trick.block
|> trick.expression_to_string
// -> Ok("{ 1 + 2 }")
trick.block({
use x <- trick.variable("x", trick.int(1))
use y <- trick.variable("y", trick.int(2))
trick.expression(trick.add(x, y))
})
|> trick.expression_to_string
Will generate:
{
let x = 1
let y = 2
x + y
}
pub fn bool(value: Bool) -> Expression(a)
Generates a Bool.
Examples
trick.bool(True) |> trick.expression_to_string
// -> Ok("True")
pub fn bool_pattern(bool: Bool) -> Pattern(Nil)
Generates a pattern that matches a specific bool value.
Examples
{
use bool_to_string <- trick.function("bool_to_string", trick.Public, {
use value <- trick.parameter("value", trick.bool_type())
trick.function_body(trick.expression(trick.case_(value, [
{
use _ <- trick.clause(trick.bool_pattern(True))
trick.string("True")
},
{
use _ <- trick.clause(trick.bool_pattern(False))
trick.string("False")
},
])))
})
trick.end_module()
}
|> trick.to_string
Will generate:
pub fn bool_to_string(value: Bool) -> String {
case value {
True -> "True"
False -> "False"
}
}
pub fn call(
function: Expression(a),
arguments: List(Expression(a)),
) -> Expression(Variable)
Generates a function call with unlabelled arguments. To use labels in the
call, see labelled_call.
Example
The following examples assume a function called add defined as the following:
pub fn add(a: Int, b: Int) -> Int {
a + b
}
The definition has been omitted for brevity. See function for
examples of how to create functions.
trick.call(add, [trick.int(1), trick.int(2)]) |> trick.expression_to_string
// -> Ok("add(1, 2)")
trick.call(add, [trick.float(1.0), trick.float(2.0)])
|> trick.expression_to_string
// -> Error(TypeMismatch(expected: Int, got: Float))
trick.call(add, [trick.int(1), trick.int(2), trick.int(3)])
|> trick.expression_to_string
// -> Error(IncorrectNumberOfArguments(expected: 2, got: 3))
trick.call(trick.int(1), [trick.int(2), trick.int(3)])
|> trick.expression_to_string
// -> Error(InvalidCall(type_: int))
pub fn case_(
subject: Expression(a),
clauses: List(Clause),
) -> Expression(Variable)
Generates a case expression that matches one or more patterns against a
value. NOTE: Currently this does not perform any form of exhaustiveness
checking so you need to ensure that patterns are exhaustive yourself.
Examples
{
use operation_type <- trick.custom_type("Operation", trick.Public)
use operation_constructor <- trick.constructor("Operation", [
trick.Field(Some("operator"), trick.string_type()),
trick.Field(Some("a"), trick.int_type()),
trick.Field(Some("b"), trick.int_type()),
])
use <- trick.end_custom_type
use evaluate <- trick.funtion("evaluate", trick.Public, {
use operation <- trick.parameter("operation", operation_type)
trick.function_body(trick.expression(trick.case_(operation, [
{
use #(a, b) <- trick.clause(trick.constructor_pattern(
operation_constructor,
{
use _ <- trick.pattern(trick.string_pattern("+"))
use a <- trick.pattern(trick.variable_pattern("a"))
use b <- trick.pattern(trick.variable_pattern("b"))
#(a, b)
},
))
ttrick.return_from_pattern(rick.add(a, b))
},
{
use #(left, right) <- trick.clause(trick.constructor_pattern(
operation_constructor,
{
use _ <- trick.pattern(trick.string_pattern("-"))
use left <- trick.labelled_pattern(
"a",
trick.variable_pattern("left"),
)
use right <- trick.labelled_pattern(
"b",
trick.variable_pattern("right"),
)
trick.return_from_pattern(#(left, right))
},
))
trick.subtract(left, right)
},
{
use #(one, other) <- trick.clause(trick.constructor_pattern(
operation_constructor,
{
use one <- trick.labelled_pattern(
"b",
trick.variable_pattern("one"),
)
use other <- trick.labelled_pattern(
"a",
trick.variable_pattern("other"),
)
use _ <- trick.labelled_pattern(
"operator",
trick.string_pattern("*"),
)
trick.return_from_pattern(#(one, other))
},
))
trick.multiply(one, other)
},
{
use _ <- trick.clause(trick.constructor_pattern(
operation_constructor,
{
use _ <- trick.pattern(trick.string_pattern("/"))
use _ <- trick.labelled_pattern(
"b",
trick.int_pattern(0),
)
use <- trick.ignore_fields
Nil
},
))
trick.int(0)
},
{
use #(a, b) <- trick.clause(trick.constructor_pattern(
operation_constructor,
{
use _ <- trick.pattern(trick.string_pattern("/"))
use a <- trick.pattern(trick.variable_pattern("a"))
use b <- trick.pattern(trick.variable_pattern("b"))
trick.return_from_pattern(#(a, b))
},
))
trick.divide(a, b)
},
{
use _ <- trick.clause(trick.discard_pattern())
trick.int(0)
}
])))
})
trick.end_module()
}
|> trick.to_string
Will generate:
pub type Operation {
Operation(operator: String, a: Int, b: Int)
}
pub fn evaluate(operation: Operation) -> Int {
case operation {
Operation("+", a, b) -> a + b
Operation("-", a: left, b: right) -> left - right
Operation(b: one, a: other, operator: "*") -> one * other
Operation("/", b: 0, ..) -> 0
Operation("/", a, b) -> a / b
_ -> 0
}
}
pub fn clause(
pattern: Pattern(a),
body: fn(a) -> Expression(Variable),
) -> Clause
Generates a single branch or “clause” of a case expression.
See the documentation for case_ for usae examples.
pub fn comment(
comment: String,
continue: fn() -> Statement,
) -> Statement
Generates a comment.
Examples
trick.block({
use <- trick.comment("Pi to 2 decimal places")
trick.expression(trick.float(3.14))
})
|> trick.expression_to_string
Will generate:
{
// Pi to 2 decimal places
3.14
}
pub fn compile(
module: Module,
module_name: String,
) -> Result(#(String, ModuleInterface), Error)
Compiles a generated module, returning the string of generated code as well as the module interface, so it can be imported by other generated code.
If you don’t need to import it, use to_string instead.
Example
let assert Ok(#(maths_code, maths_module)) = {
use _pi <- trick.constant("pi", trick.Public, trick.float(3.14))
trick.end_module()
}
|> trick.compile("maths")
let assert Ok(main_module) = {
use maths <- trick.import_(maths_module)
use circle_area <- trick.function("circe_area", trick.Public, {
use radius <- trick.parameter("radius", trick.float_type())
radius
|> trick.multiply_float(radius)
|> trick.multiply_float(trick.imported_value(maths, "pi"))
|> trick.expression
|> trick.function_body
})
trick.end_module()
}
file.write("maths.gleam", maths_code)
file.write("main.gleam", main_module)
Produces:
// maths.gleam
pub const pi = 3.14
// main.gleam
import maths
pub fn circle_area(radius: Float) -> Float {
radius *. radius *. maths.pi
}
pub fn concatenate(
left: Expression(a),
right: Expression(a),
) -> Expression(a)
Generates a <> operation.
Examples
trick.concatenate(trick.string("Hello"), trick.string("world"))
|> trick.expression_to_string
// -> Ok("\"Hello\" <> \"world\"")
pub fn constant(
name: String,
publicity: Publicity,
value: Expression(Constant),
continue: fn(Expression(Constant)) -> Module,
) -> Module
Generates a top-level constant from a constant expression, passing the name of the constant to the continuing function allowing it to be used.
Examples
{
use hello <- trick.constant("hello", trick.Private, trick.string("Hello,"))
use world <- trick.constant("world", trick.Private, trick.string(" world!"))
use hello_world <- trick.constant(
"hello_world",
trick.Public,
trick.concatenate(hello, world),
)
trick.end_module()
}
|> trick.to_string
Will generate:
const hello = "Hello,"
const world = " world!"
pub const hello_world = hello <> world
pub fn construct(constructor: Constructor) -> Expression(a)
Turns a constructor into an expression which references it.
Examples
{
use wibble_type <- trick.custom_type("Wibble", trick.Public)
use wibble <- trick.constructor("Wibble", [])
use <- trick.end_custom_type
use main <- trick.function(
"main",
trick.Public,
wibble
|> trick.construct
|> trick.expression
|> trick.function_body,
)
trick.end_module()
}
|> trick.to_string
Will generate:
pub type Wibble {
Wibble
}
pub fn main() -> Wibble {
Wibble
}
pub fn constructor(
name: String,
fields: List(Field),
continue: fn(Constructor) -> CustomType(NoParameters),
) -> CustomType(NoParameters)
Generates a constructor for a custom types.
Examples
{
use wibble_type <- trick.custom_type("Wibble", trick.Public)
use wibble <- trick.constructor("Wibble", [
trick.Field(None, trick.int_type()),
trick.Field(None, trick.float_type()),
trick.Field(Some("a_label"), trick.string_type()),
trick.Field(Some("another_label"), trick.bool_type()),
])
use <- trick.end_custom_type
trick.end_module()
}
|> trick.to_string
Will generate:
pub type Wibble {
Wibble(Int, Float, a_label: String, another_label: Bool)
}
pub fn constructor_pattern(
constructor: Constructor,
arguments: PatternList(Labelled, a),
) -> Pattern(a)
Generates a pattern that matches on a specific constructor a custom type,
along with the specified arguments. If you want to match a variant without
any fields, use variant_pattern instead.
Examples
{
use person_type <- trick.custom_type("Person", trick.Public)
use person_constructor <- trick.constructor("Person", [
trick.Field(Some("name"), trick.string_type()),
trick.Field(Some("job"), trick.string_type()),
trick.Field(Some("age"), trick.int_type()),
])
use <- trick.end_custom_type
use is_gleam_creator <- trick.function("is_gleam_creator", trick.Public, {
use person <- trick.parameter("person", person_type)
trick.function_body(trick.expression(trick.case_(person, [
{
use _ <- trick.clause(trick.constructor_pattern(person_constructor, {
use _ <- trick.labelled_pattern(
"name",
trick.string_pattern("Louis"),
)
use _ <- trick.labelled_pattern(
"job",
trick.string_pattern("Programmer"),
)
use <- trick.ignore_fields
Nil
}))
trick.bool(True)
},
{
use _ <- trick.clause(trick.discard_pattern())
trick.bool(False)
},
])))
})
trick.end_module()
}
|> trick.to_string
Will generate:
pub type Person {
Person(name: String, job: String, age: Int)
}
pub fn is_gleam_creator(person: Person) -> Bool {
case person {
Person(name: "Louis", job: "Programmer", ..) -> True
_ -> False
}
}
pub fn custom_type(
name: String,
publicity: Publicity,
continue: fn(Type(a)) -> CustomType(a),
) -> Module
Begins a custom type declaration, passing the type to the continuing function so it can be used in constructors as a recursive definition, or in later functions and types.
Examples
{
use list <- trick.custom_type("List", trick.Public)
use a <- trick.type_parameter("a")
use empty <- trick.constructor("Empty", [])
use non_empty <- trick.constructor("NonEmpty", [
trick.Field(Some("head"), a),
trick.Field(Some("tail"), list),
])
use <- trick.end_custom_type
trick.end_module()
}
|> trick.to_string
Will generate:
pub type List(a) {
Empty
NonEmpty(head: a, tail: List(a))
}
pub fn define_constructors(
constructors: List(ConstructorInterface),
continue: fn() -> DefinedModule,
) -> CustomTypeInterface(NoParameters)
Defines public interface for the constructors of a custom type.
Examples
let assert Ok(option_module) = trick.define_module("gleam/option", {
use option <- trick.define_custom_type("Option")
use a <- trick.define_type_parameter("a")
use <- trick.define_constructors([
trick.DefinedConstructor("Some", [trick.Field(None, a)]),
trick.DefinedConstructor("None", []),
])
trick.define_values([])
})
pub fn define_custom_type(
name: String,
continue: fn(Type(a)) -> CustomTypeInterface(a),
) -> DefinedModule
Defines the public interface of a custom type, so that it can be imported from another module.
Examples
let assert Ok(option_module) = trick.define_module("gleam/option", {
use option <- trick.define_custom_type("Option")
use a <- trick.define_type_parameter("a")
use <- trick.define_constructors([
trick.DefinedConstructor("Some", [trick.Field(None, a)]),
trick.DefinedConstructor("None", []),
])
trick.define_values([])
})
pub fn define_module(
name: String,
definitions: DefinedModule,
) -> Result(ModuleInterface, Error)
Defines the minimum public interface of a module so it can be imported and
used in generated code. If you need to generate code for this module, see
compile.
Examples
let assert Ok(interface) = trick.define_module("wibble/wobble", {
use wibble <- trick.define_custom_type("Wibble")
use <- trick.define_constructors([trick.DefinedConstructor("Wibble", [
trick.Field(Some("self"), wibble)
])])
trick.define_values([trick.FunctionInterface("wobble", [wibble], wibble)])
})
pub fn define_type_parameter(
name: String,
continue: fn(Type(NoParameters)) -> CustomTypeInterface(
has_parameter,
),
) -> CustomTypeInterface(HasParameters)
Defines a type parameter for a custom type interface generated using
define_custom_type. If you want a type parameter
for a custom type being generated as code, see type_parameter.
Examples
let assert Ok(module) = trick.define_module("pair", {
use pair <- trick.define_custom_type("pair")
use left <- trick.define_type_parameter("left")
use right <- trick.define_type_parameter("right")
use <- trick.define_constructors([trick.DefinedConstructor("Pair", [
trick.Field(None, left), trick.Field(None, right)
])])
trick.define_values([trick.FunctionInterface("new", [left, right], pair)])
})
pub fn define_values(
values: List(ValueInterface),
) -> DefinedModule
Defines the types of public values in a module so they can be imported and used in other modules. Only contains type information, not enough information to generate code.
Examples
let assert Ok(int_module) = trick.define_module(
"gleam/int",
trick.define_values([
trick.ConstantInterface("zero", trick.int_type()),
trick.FunctionInterface("add", trick.function_type([
trick.int_type(), trick.int_type()
], trick.int_type())),
])),
pub fn discard(
discarded: Statement,
continue: fn() -> Statement,
) -> Statement
Discards a terminating statement and allows continuation.
trick.block({
use <- trick.discard(trick.expression(trick.int(1)))
trick.expression(trick.int(2))
})
|> trick.expression_to_string
Will generate:
{
1
2
}
trick.block({
use <- trick.discard(trick.assert(trick.bool(True), None))
trick.assert(trick.bool(False), None)
})
|> trick.expression_to_string
Will generate:
{
assert True
assert False
}
pub fn discard_pattern() -> Pattern(Nil)
Generates a pattern that matches anything and ignores its contents.
Examples
trick.case_(trick.int(1), [
{
use _ <- trick.clause(trick.discard_pattern())
trick.nil()
}
])
|> trick.expression_to_string
Will generate:
case 1 {
_ -> Nil
}
pub fn divide(
divide left: Expression(a),
by right: Expression(a),
) -> Expression(Variable)
Generates a / operation.
Examples
trick.divide(trick.int(1), trick.int(2)) |> trick.expression_to_string
// -> Ok("1 / 2")
pub fn divide_float(
divide left: Expression(a),
by right: Expression(a),
) -> Expression(Variable)
Generates a /. operation.
Examples
trick.divide_float(trick.float(1.0), trick.float(2.0))
|> trick.expression_to_string
// -> Ok("1.0 /. 2.0")
pub fn doc_comment(
comment: String,
continue: fn() -> Module,
) -> Module
Generates a doc comment in a module, which provides documentation for a particular type or value..
Examples
{
use <- trick.doc_comment(
"The ultimate answer to life, the universe, and everything."
)
use _ <- trick.constant("the_answer", trick.Public, trick.int(42))
trick.end_module()
}
Will generate:
/// The ultimate answer to life, the universe, and everything.
pub const the_answer = 42
pub fn echo_(
value: Expression(a),
message: option.Option(Expression(a)),
) -> Expression(Variable)
Generates an echo expression, with an optional message. If present, the
message must be of type String.
Examples
trick.echo_(trick.int(42), None) |> trick.expression_to_string
// -> Ok("echo 42")
trick.echo_(trick.int(42), Some(trick.string("the answer")))
|> trick.expression_to_string
// -> Ok("echo 42 as \"the answer\"")
trick.echo_(trick.int(42), Some(trick.int(42)))
|> trick.expression_to_string
// -> Error(TypeMismatch(expected: String, got: Int))
pub fn end_custom_type(continue: fn() -> Module) -> CustomType(a)
Marks the end of a custom type definition.
Examples
{
use box_type <- trick.custom_type("Box", trick.Public)
use value <- trick.type_parameter("value")
use box <- trick.constructor("Box", [trick.Field(None, value)])
use <- trick.end_custom_type
trick.end_module()
}
|> trick.to_string
Will generate:
pub type Box(value) {
Box(value)
}
pub fn end_module() -> Module
Marks the end of a module.
Examples
{
use _ <- trick.constant("pi", trick.Public, trick.float(3.14))
trick.end_module()
}
|> trick.to_string
// -> Ok("pub const pi = 3.14")
pub fn equal(
left: Expression(a),
right: Expression(a),
) -> Expression(Variable)
Generates a == operation. The two values must be of the same type.
Examples
trick.equal(trick.int(1), trick.int(1)) |> trick.expression_to_string
// -> Ok("1 == 1")
trick.equal(trick.float(1.0), trick.float(2.0))
|> trick.expression_to_string
// -> Ok("1.0 == 2.0")
trick.equal(trick.int(1), trick.float(2.0))
|> trick.expression_to_string
// -> Error(TypeMismatch(expected: Int, got: Float))
pub fn expression(expression: Expression(a)) -> Statement
Turns an Expression into a Statement so it can be used in statement
position.
By default, an expression statement ends the block and doesn’t allow being
followed by another statement. Use discard to include a
continuation.
pub fn expression_to_string(
expression: Expression(a),
) -> Result(String, Error)
Turns an Expression into a string of Gleam code.
Examples
trick.int(1) |> trick.add(trick.int(2)) |> trick.expression_to_string
// -> Ok("1 + 2")
trick.int(1) |> trick.add(trick.float(2.0)) |> trick.expression_to_string
// -> Error(TypeMismatch(expected: Int, got: Float))
pub fn field_access(
value: Expression(a),
field: String,
) -> Expression(Variable)
Generates a field access expression.
Examples
{
use person <- trick.custom_type("Person", trick.public)
use child <- trick.constructor("Child", [
trick.Field(Some("age"), trick.int_type()),
])
use adult <- trick.constructor("Adult", [
trick.Field(Some("age"), trick.int_type()),
trick.Field(Some("job"), trick.string_type()),
])
use <- trick.end_custom_type
use age_after_birthday <- trick.function("age_after_birthday", trick.Public, {
use person <- trick.parameter("person", person)
person
|> trick.field_access("age")
|> trick.add(trick.int(1))
|> trick.expression
|> trick.function_body
})
trick.end_module()
}
|> trick.to_string
Will generate:
pub type Person {
Child(age: Int)
Adult(age: Int, job: String)
}
pub fn age_after_birthday(person: Person) -> Int {
person.age + 1
}
pub fn float(value: Float) -> Expression(a)
Generates a Float.
Examples
trick.float(3.14) |> trick.expression_to_string
// -> Ok("3.14")
pub fn float_pattern(value: Float) -> Pattern(Nil)
Generates a pattern which matches a specific float value.
Examples
trick.case_(trick.float(1.0), [
{
use _ <- trick.clause(trick.float_pattern(3.14))
trick.float(3.14159265)
},
{
use x <- trick.clause(trick.variable_pattern("x"))
x
},
])
|> trick.expression_to_string
Will generate:
case 1.0 {
3.14 -> 3.14159265
x -> x
}
pub fn function(
name: String,
publicity: Publicity,
function: FunctionBuilder(a),
continue: fn(Expression(Constant)) -> Module,
) -> Module
Generates a top-level function definition, passing the function name to the continuing function so it can be called later.
Examples
{
use square <- trick.function("square", trick.Private, {
use value <- trick.parameter("value", trick.float_type())
trick.multiply_float(value, value)
|> trick.expression
|> trick.function_body
})
use circle_area <- trick.function("circle_area", trick.Public, {
use radius <- trick.parameter("radius", trick.float_type())
trick.call(square, [radius])
|> trick.multiple_float(trick.float(3.14))
|> trick.expression
|> trick.function_body
})
use main <- trick.function("main", trick.Public, trick.function_body(
trick.expression(
trick.echo_(trick.call(circle_area, [trick.float(5.0)]), None)
)
))
}
|> trick.to_string
Will generate:
fn square(value: Float) -> Float {
value *. value
}
pub fn circle_area(radius: Float) -> Float {
square(radius) *. 3.14
}
pub fn main() -> Float {
echo circle_area(5.0)
}
pub fn function_body(
body: Statement,
) -> FunctionBuilder(Unlabelled)
Marks a statement as the body of a function, concluding the definition.
Examples
trick.nil()
|> trick.expression
|> trick.function_body
|> trick.anonymous
|> trick.expression_to_string
// -> Ok("fn() { Nil }")
pub fn function_capture(
function: Expression(a),
before_hole: List(Expression(a)),
after_hole: List(Expression(a)),
) -> Expression(Variable)
Generates a function capture expression, receiving two lists of arguments. The function hole goes between the two lists.
See also: function_capture_alt for an alternative API.
Examples
{
use add_5_numbers <- trick.function("add_5_numbers", trick.Private, {
use a <- trick.parameter("a", int_type())
use b <- trick.parameter("b", int_type())
use c <- trick.parameter("c", int_type())
use d <- trick.parameter("d", int_type())
use e <- trick.parameter("e", int_type())
a
|> trick.add(b)
|> trick.add(c)
|> trick.add(d)
|> trick.add(e)
|> trick.expression
|> trick.function_body
})
use main <- trick.function("main", trick.Public, trick.function_body(
trick.expression(trick.function_capture(
add_5_numbers,
[trick.int(1), trick.int(2)],
[trick.int(4), trick.int(5)],
))
))
trick.end_module()
}
Will generate:
fn add_5_numbers(a: Int, b: Int, c: Int, d: Int, e: Int) -> Int {
a + b + c + d + e
}
pub fn main() -> fn(Int) -> Int {
add_5_numbers(1, 2, _, 4, 5)
}
pub fn function_capture_alt(
function: Expression(a),
arguments: List(FunctionCaptureArgument),
) -> Expression(Variable)
An alternative experimental API to function_capture,
structured more like a regular call.
The downside to this approach is that the type system doesn’t guarantee that there’s exactly one type hole, so we need to report errors for that too.
Examples
{
use add_5_numbers <- trick.function("add_5_numbers", trick.Private, {
use a <- trick.parameter("a", int_type())
use b <- trick.parameter("b", int_type())
use c <- trick.parameter("c", int_type())
use d <- trick.parameter("d", int_type())
use e <- trick.parameter("e", int_type())
a
|> trick.add(b)
|> trick.add(c)
|> trick.add(d)
|> trick.add(e)
|> trick.expression
|> trick.function_body
})
use main <- trick.function("main", trick.Public, trick.function_body(
trick.expression(trick.function_capture_alt(add_5_numbers, [
CaptureArgument(trick.int(1)),
CaptureArgument(trick.int(2)),
CaptureHole,
CaptureArgument(trick.int(4)),
CaptureArgument(trick.int(5)),
]))
))
trick.end_module()
}
Will generate:
fn add_5_numbers(a: Int, b: Int, c: Int, d: Int, e: Int) -> Int {
a + b + c + d + e
}
pub fn main() -> fn(Int) -> Int {
add_5_numbers(1, 2, _, 4, 5)
}
pub fn function_type(
parameters: List(Type(NoParameters)),
return: Type(NoParameters),
) -> Type(NoParameters)
Returns a function type with the specified parameters and return type.
pub fn generic(name: String) -> Type(NoParameters)
Returns a generic type with the given name.
pub fn greater_than(
left: Expression(a),
right: Expression(a),
) -> Expression(Variable)
Generates a > operation.
Examples
trick.greater_than(trick.int(1), trick.int(2))
|> trick.expression_to_string
// -> Ok("1 > 2")
pub fn greater_than_float(
left: Expression(a),
right: Expression(a),
) -> Expression(Variable)
Generates a >. operation.
Examples
trick.greater_than_float(trick.float(1.0), trick.float(2.0))
|> trick.expression_to_string
// -> Ok("1.0 >. 2.0")
pub fn greater_than_or_equal(
left: Expression(a),
right: Expression(a),
) -> Expression(Variable)
Generates a >= operation.
Examples
trick.greater_than_or_equal(trick.int(1), trick.int(2))
|> trick.expression_to_string
// -> Ok("1 >= 2")
pub fn greater_than_or_equal_float(
left: Expression(a),
right: Expression(a),
) -> Expression(Variable)
Generates a >=. operation.
Examples
trick.greater_than_or_equal_float(trick.float(1.0), trick.float(2.0))
|> trick.expression_to_string
// -> Ok("1.0 >=. 2.0")
pub fn ignore_fields(
variables: fn() -> a,
) -> PatternList(Labelled, a)
Generates a pattern which ignores the remaining fields of a record. Since this pattern cannot bind any variables and must not be followed by other patterns, this function doesn’t acceptanother pattern from the callback, just the value to return from the entire pattern.
See the documentation for constructor_pattern for
usage examples.
pub fn import_(
module: ModuleInterface,
continue: fn(ModuleName) -> Module,
) -> Module
Import a particular module so it can be used.
Examples
let assert Ok(option_module) = trick.define_module("gleam/option", ...)
{
use imported_option <- trick.import_(option_module)
use _ <- trick.function(
"main",
trick.Public,
trick.function_body({
use option <- trick.variable(
"option",
trick.call(trick.imported_value(imported_option, "Some"), [
trick.int(1),
]),
)
trick.expression(
trick.call(trick.imported_value(imported_option, "unwrap"), [
option,
trick.int(1),
]),
)
}),
)
trick.end_module()
}
|> trick.to_string
Will produce:
import gleam/option
pub fn main() -> Int {
let option = option.Some(1)
option.unwrap(option, 1)
}
pub fn imported_constuctor(
module: ModuleName,
name: String,
) -> Constructor
Imports a constructor from another module, for use in either an expression,
or a pattern. For expressions, imported_value can be
used also.
Examples
{
use option <- trick.import_(option_module)
let option_type = trick.imported_generic_type(option, "Option")
let some = trick.imported_constructor(option, "Some")
let none = trick.imported_constructor(option, "None")
use unwrap <- trick.function("unwrap", trick.Public, {
let a = trick.generic("a")
use option <- trick.parameter(
"option",
trick.with_generics(option_type, [a]),
)
use fallback <- trick.parameter("fallback", a)
trick.function_body(trick.expression(trick.case_(option, [
{
use value <- trick.clause(trick.constructor_pattern(some, {
use value <- trick.pattern(trick.variable_pattern("value"))
trick.return_from_pattern(value)
})))
value
},
{
use _ <- trick.clause(trick.variant_pattern(none)
fallback
},
])))
})
trick.end_module()
}
|> trick.to_string
Will generate:
import gleam/option
pub fn unwrap(option: option.Option(a), fallback: a) -> a {
case option {
Some(value) -> value
None -> fallback
}
}
pub fn imported_generic_type(
module: ModuleName,
name: String,
) -> Type(HasParameters)
Retrieves a generic type from an imported module. For importing non-generic
types, use imported_type.
Examples
{
use option <- trick.import_(option_module)
let option_type = trick.imported_generic_type(option, "Option")
use _process_option <- trick.function("process_option", trick.Public, {
use option <- trick.parameter(
"option",
trick.with_generics(option_type, trick.generic("a")),
)
trick.function_body(trick.expression(option))
})
trick.end_module()
}
|> trick.to_string
Will generate:
import gleam/option
pub fn process_option(option: option.Option(a)) -> option.Option(a) {
option
}
pub fn imported_type(
module: ModuleName,
name: String,
) -> Type(NoParameters)
Retrieves a type from an imported module.
If a generic type is imported using this function, an error will be returned.
For generic types, use imported_generic_type.
Examples
{
use person <- trick.import_(person_module)
let person_type = trick.imported_type(person, "Person")
use _process_person <- trick.function("process_person", trick.Public, {
use person <- trick.parameter("person", person_type)
trick.function_body(trick.expression(person))
})
trick.end_module()
}
|> trick.to_string
Will generate:
import person
pub fn process_person(person: person.Person) -> person.Person {
person
}
pub fn imported_value(
module: ModuleName,
name: String,
) -> Expression(a)
Generates an expression representing a value which is imported from another module.
Examples
{
use option <- trick.import_(option_module)
let none = trick.imported_value(option, "None")
use _none <- trick.constant("none", trick.Public, none)
trick.end_module()
}
|> trick.to_string
Will generate:
import gleam/option
pub const none: option.Option(a) = option.None
pub fn int(value: Int) -> Expression(a)
Generates an Int.
Examples
trick.int(42) |> trick.expression_to_string
// -> Ok("42")
pub fn int_base16(value: Int) -> Expression(a)
Generates an Int using hexadecimal syntax.
Examples
trick.int_base16(42) |> trick.expression_to_string
// -> Ok("0x2a")
pub fn int_base2(value: Int) -> Expression(a)
Generates an Int using binary syntax.
Examples
trick.int_base2(42) |> trick.expression_to_string
// -> Ok("0b101010")
pub fn int_base8(value: Int) -> Expression(a)
Generates an Int using octal syntax.
Examples
trick.int_base8(42) |> trick.expression_to_string
// -> Ok("0o52")
pub fn int_pattern(value: Int) -> Pattern(Nil)
Generates a pattern which matches a specific integer value.
Examples
trick.case_(trick.int(1), [
{
use _ <- trick.clause(trick.int_pattern(1))
trick.int(-1)
},
{
use x <- trick.clause(trick.variable_pattern("x"))
x
},
])
|> trick.expression_to_string
Will generate:
case 1 {
1 -> -1
x -> x
}
pub fn labelled_call(
function: Expression(a),
arguments: List(Argument),
) -> Expression(Variable)
Generates a function call, allowing you to specify labelled arguments. For
a call with no labelled arguments, it’s more convenient to simply use
call.
Examples
{
use function_with_labels <- trick.function(
"function_with_labels",
trick.Private,
{
use _ <- trick.parameter("unlabelled", trick.int_type())
use _ <- trick.labelled_parameter("label", "name", trick.float_type())
use _ <- trick.labelled_parameter(
"other_label",
"different_name",
trick.bool_type(),
)
trick.todo_(None) |> trick.expression |> trick.function_body
},
)
use main <- trick.function("main", trick.Public, trick.function_body(
trick.expression(trick.labelled_call(function_with_labels, [
trick.Argument(None, trick.int(42)),
trick.Argument(Some("other_label"), trick.bool(False)),
trick.Argument(Some("label"), trick.float(3.14)),
]))
))
trick.end_module()
}
|> trick.to_string
Will generate:
fn function_with_labels(
unlabelled: Int,
label name: Float,
other_label different_name: Bool,
) -> a {
todo
}
pub fn main() -> a {
function_with_labels(42, other_label: False, label: 3.14)
}
pub fn labelled_parameter(
label: String,
name: String,
type_: Type(NoParameters),
continue: fn(Expression(a)) -> FunctionBuilder(a),
) -> FunctionBuilder(Labelled)
Adds a labelled parameter to a function definition.
Examples
trick.function("subtract", trick.Public, {
use left <- trick.labelled_parameter("from", "left", trick.type_int())
use right <- trick.labelled_parameter("subtract", "right", trick.type_int())
trick.subtract(left, right) |> trick.expression |> trick.function_body
}, fn(_) { trick.end_module() })
|> trick.to_string
Will generate:
pub fn subtract(from left: Int, subtract right: Int) -> Int {
left - right
}
pub fn labelled_pattern(
label: String,
pattern: Pattern(a),
continue: fn(a) -> PatternList(Labelled, b),
) -> PatternList(Labelled, b)
Generates an argument of a constructor pattern which matches a specific pattern for a labelled parameter of the record.
See the documentation for constructor_pattern for
usage examples.
pub fn less_than(
left: Expression(a),
right: Expression(a),
) -> Expression(Variable)
Generates a < operation.
Examples
trick.less_than(trick.int(1), trick.int(2)) |> trick.expression_to_string
// -> Ok("1 < 2")
pub fn less_than_float(
left: Expression(a),
right: Expression(a),
) -> Expression(Variable)
Generates a <. operation.
Examples
trick.less_than_float(trick.float(1.0), trick.float(2.0))
|> trick.expression_to_string
// -> Ok("1.0 <. 2.0")
pub fn less_than_or_equal(
left: Expression(a),
right: Expression(a),
) -> Expression(Variable)
Generates a <= operation.
Examples
trick.less_than_or_equal(trick.int(1), trick.int(2))
|> trick.expression_to_string
// -> Ok("1 <= 2")
pub fn less_than_or_equal_float(
left: Expression(a),
right: Expression(a),
) -> Expression(Variable)
Generates a <=. operation.
Examples
trick.less_than_or_equal_float(trick.float(1.0), trick.float(2.0))
|> trick.expression_to_string
// -> Ok("1.0 <=. 2.0")
pub fn let_(
pattern: Pattern(a),
value: Expression(a),
continue: fn(a) -> Statement,
) -> Statement
Generates a let statement which matches the provided expression to the
specified pattern. Returns an error if the pattern does not always match.
For binding a simple variable pattern, it’s easier to use
variable.
Examples
trick.block({
use #(a, b) <- trick.let_(
trick.tuple_pattern({
use a <- trick.pattern(trick.variable_pattern("a"))
use b <- trick.pattern(trick.variable_pattern("b"))
trick.return_from_pattern(#(a, b))
}),
trick.tuple([trick.int(1), trick.int(2)])
)
trick.expression(trick.add(a, b))
})
|> trick.expression_to_string
Will generate:
{
let #(a, b) = #(1, 2)
a + b
}
pub fn let_assert(
pattern: Pattern(a),
value: Expression(a),
continue: fn(a) -> Statement,
) -> Statement
Generates a let assert statement which matches the provided expression to
the specified pattern.
Examples
trick.block({
use #(a, b) <- trick.let_assert(
trick.list_pattern({
use _ <- trick.pattern(trick.int_pattern(1))
use a <- trick.pattern(trick.variable_pattern("a"))
use _ <- trick.pattern(trick.int_pattern(3))
use b <- trick.pattern(trick.variable_pattern("b"))
trick.return_from_pattern(#(a, b))
}),
trick.list([trick.int(1), trick.int(2), trick.int(3), trick.int(4)]),
)
trick.expression(trick.add(a, b))
})
|> trick.expression_to_string
Will generate:
{
let assert [1, a, 3, b] = [1, 2, 3, 4]
a + b
}
pub fn list(values: List(Expression(a))) -> Expression(a)
Generates a list of values. The values must all be of the same type.
Examples
trick.list([trick.int(1), trick.int(2), trick.int(3)])
|> trick.expression_to_string
// -> Ok("[1, 2, 3]")
trick.list([trick.float(1.0), trick.float(2.0), trick.float(3.0)])
|> trick.expression_to_string
// -> Ok("[1.0, 2.0, 3.0]")
trick.list([trick.int(1), trick.float(2.0), trick.float(3.0)])
|> trick.expression_to_string
// -> Error(TypeMismatch(expected: Int, got: Float))
pub fn list_pattern(
elements: PatternList(WithTail, a),
) -> Pattern(a)
Generates a pattern that matches a list using the specified elements.
Since list patterns can potentially bind more than one variable, the API is
different to that of most other patterns. Here, each element of the pattern
is used, so that each variable can be obtained. At the end of the pattern,
the relevant variables are returned so that they can be referenced in the
clause body.
Examples
trick.case_(trick.list([trick.int(1), trick.int(2), trick.int(3)]), [
{
use #(x, rest) <- trick.clause(trick.in({
use _ <- trick.pattern(trick.int_pattern(1))
use x <- trick.pattern(trick.variable_pattern("x"))
use rest <- trick.tail(trick.variable_pattern("rest"))
#(x, rest)
}))
trick.tuple([x, rest])
},
{
use _ <- trick.clause(trick.discard_pattern())
trick.tuple([trick.int(0), trick.list([])])
},
])
|> trick.expression_to_string
Will generate:
case [1, 2, 3] {
[1, x, ..rest] -> #(x, rest)
_ -> #(0, [])
}
pub fn list_type(
of element_type: Type(NoParameters),
) -> Type(NoParameters)
Returns a List type with the specified element type.
pub fn module_comment(
comment: String,
continue: fn() -> Module,
) -> Module
Generates a top-level module comment to provide documentation for the entire module.
Examples
{
use <- trick.module_comment(
"This module contains constants relating to\n"
<> "the Hitchhiker's Guide to the Galaxy.",
)
use _ <- trick.constant("the_answer", trick.Public, trick.int(42))
trick.end_module()
}
Will generate:
//// This module contains constants relating to
//// the Hitchhiker's Guide to the Galaxy.
pub const the_answer = 42
pub fn multiply(
left: Expression(a),
right: Expression(a),
) -> Expression(Variable)
Generates a * operation.
Examples
trick.multiply(trick.int(1), trick.int(2)) |> trick.expression_to_string
// -> Ok("1 * 2")
pub fn multiply_float(
left: Expression(a),
right: Expression(a),
) -> Expression(Variable)
Generates a *. operation.
Examples
trick.multiply_float(trick.float(1.0), trick.float(2.0))
|> trick.expression_to_string
// -> Ok("1.0 *. 2.0")
pub fn negate_bool(value: Expression(a)) -> Expression(Variable)
Generates a unary ! operation.
Examples
trick.negate_bool(trick.bool(True))
|> trick.expression_to_string
// -> Ok("!True")
pub fn negate_int(value: Expression(a)) -> Expression(Variable)
Generates a unary - operation.
Examples
trick.negate_int(trick.int(1))
|> trick.expression_to_string
// -> Ok("-1")
trick.negate_int(trick.float(1.0))
|> trick.expression_to_string
// -> Error(TypeMismatch(expected: Int, got: Float))
pub fn nil() -> Expression(a)
Generates Nil.
Examples
trick.nil() |> trick.expression_to_string
// -> Ok("Nil")
pub fn not_equal(
left: Expression(a),
right: Expression(a),
) -> Expression(Variable)
Generates a != operation. The two values must be of the same type.
Examples
trick.not_equal(trick.int(1), trick.int(1)) |> trick.expression_to_string
// -> Ok("1 != 1")
trick.not_equal(trick.float(1.0), trick.float(2.0))
|> trick.expression_to_string
// -> Ok("1.0 != 2.0")
trick.not_equal(trick.int(1), trick.float(2.0))
|> trick.expression_to_string
// -> Error(TypeMismatch(expected: Int, got: Float))
pub fn or(
left: Expression(a),
right: Expression(a),
) -> Expression(Variable)
Generates a || operation.
Examples
trick.or(trick.bool(False), trick.bool(False))
|> trick.expression_to_string
// -> Ok("False || False")
pub fn panic_(
message: option.Option(Expression(a)),
) -> Expression(Variable)
Generates a panic expression, with an optional message. If present, the
message must be of type String.
Examples
trick.panic_(None) |> trick.expression_to_string
// -> Ok("panic")
trick.panic_(Some(trick.string("uh oh"))) |> trick.expression_to_string
// -> Ok("panic as \"uh oh\"")
trick.panic_(Some(trick.int(42))) |> trick.expression_to_string
// -> Error(TypeMismatch(expected: String, got: Int))
pub fn parameter(
name: String,
type_: Type(NoParameters),
continue: fn(Expression(a)) -> FunctionBuilder(a),
) -> FunctionBuilder(a)
Adds an unlabelled parameter to a function definition.
Examples
trick.anonymous({
use parameter <- trick.parameter("parameter", trick.type_int())
trick.todo_(None) |> trick.expression |> trick.function_body
})
|> trick.expression_to_string
// -> Ok("fn(parameter: Int) { todo }")
pub fn pattern(
pattern: Pattern(a),
callback: fn(a) -> PatternList(features, b),
) -> PatternList(features, b)
Generates a pattern as an element of a composite pattern.
Examples
trick.case_(trick.tuple([trick.int(1), trick.int(2), trick.int(3)]), [
{
use #(a, b) <- trick.clause(trick.tuple_pattern({
use a <- trick.pattern(trick.variable_pattern("a"))
use b <- trick.pattern(trick.variable_pattern("b"))
use _ <- trick.pattern(trick.int(3))
trick.return_from_pattern(#(a, b))
}))
trick.add(a, b)
},
{
use _ <- trick.clause(trick.discard_pattern())
trick.int(0)
},
])
Will generate:
case #(1, 2, 3) {
#(a, b, 3) -> a + b
_ -> 0
}
pub fn prepend(
to list: Expression(a),
prepend elements: List(Expression(a)),
) -> Expression(a)
Generates a list prepend expression, prepending one or more items.
Examples
trick.list([trick.int(2), trick.int(3)])
|> trick.prepend([trick.int(0), trick.int(1)])
|> trick.expression_to_string
// -> Ok("[0, 1, ..[2, 3]]")
trick.list([trick.int(2), trick.int(3)])
|> trick.prepend([trick.float(0.0), trick.float(1.0)])
|> trick.expression_to_string
// -> Error(TypeMismatch(expected: Int, got: Float))
trick.int(2)
|> trick.prepend([trick.int(0), trick.int(1)])
|> trick.expression_to_string
// -> InvalidListPrepend(type_: Int)
pub fn recursive(
continue: fn(Expression(Constant)) -> Statement,
) -> FunctionBuilder(Labelled)
Creates a recursive function by passing in the function name to the body.
Once a function is declared as recursive, no more parameters can be added.
Examples
trick.function("infinity", trick.Private, {
use parameter <- trick.parameter("parameter", trick.generic("a"))
use infinity <- trick.recursive
trick.call(infinity, parameter)
}, fn(_) { trick.end_module() })
|> trick.to_string
Will generate:
fn infinity(parameter: a) -> b {
infinity(parameter)
}
pub fn remainder(
left: Expression(a),
right: Expression(a),
) -> Expression(Variable)
Generates a % operation.
Examples
trick.remainder(trick.int(1), trick.int(2)) |> trick.expression_to_string
// -> Ok("1 % 2")
pub fn return_from_pattern(value: a) -> PatternList(features, a)
Returns a value from a pattern, usually containing a tuple of the variables which are bound by the pattern.
Examples
trick.case_(trick.tuple([trick.int(1), trick.int(2), trick.int(3)]), [
{
use #(a, b, c) <- trick.clause(trick.tuple_pattern({
use a <- trick.variable_pattern("a")
use b <- trick.variable_pattern("b")
use c <- trick.variable_pattern("c")
trick.return_from_pattern(#(a, b, c))
}))
a |> trick.add(b) |> trick.add(c)
},
])
pub fn string(value: String) -> Expression(a)
Generates a String.
Examples
trick.string("Hello, world!") |> trick.expression_to_string
// -> Ok("\"Hello, world!\"")
pub fn string_pattern(value: String) -> Pattern(Nil)
Generates a pattern that matches a specific string value. For extracting a
prefix from a string, see string_prefix_pattern.
Examples
trick.case_(trick.string("Hello, world!"), [
{
use _ <- trick.clause(trick.string_pattern("Hello, world!"))
trick.string("greeting")
},
{
use _ <- trick.clause(trick.discard_pattern())
trick.string("other")
},
])
|> trick.expression_to_string
Will generate:
case "Hello, world!" {
"Hello, world!" -> "greeting"
_ -> "other"
}
pub fn string_prefix_pattern(
prefix: String,
variable_name: String,
) -> Pattern(Expression(Variable))
Generates a pattern that matches a specific string prefix, and binds the remainder of the string to a variable.
Examples
trick.case_(trick.string("Hello Joe"), [
{
use name <- trick.clause(trick.string_prefix_pattern("Hello", "name"))
name
},
{
use _ <- trick.clause(trick.discard_variable())
trick.string("unknown")
},
])
|> trick.expression_to_string
Will generate:
case "Hello Joe" {
"Hello" <> name -> name
_ -> "unknown"
}
pub fn subtract(
from left: Expression(a),
subtract right: Expression(a),
) -> Expression(Variable)
Generates a - operation.
Examples
trick.subtract(trick.int(1), trick.int(2)) |> trick.expression_to_string
// -> Ok("1 - 2")
pub fn subtract_float(
from left: Expression(a),
subtract right: Expression(a),
) -> Expression(Variable)
Generates a -. operation.
Examples
trick.subtract_float(trick.float(1.0), trick.float(2.0))
|> trick.expression_to_string
// -> Ok("1.0 -. 2.0")
pub fn tail(
pattern: Pattern(a),
callback: fn(a) -> b,
) -> PatternList(WithTail, b)
Generates a pattern which matches any remaining items in a list. Since list tails must come at the end of list patterns, this function doesn’t accept another pattern from the callback, just the value to return from the entire pattern.
Examples
trick.case_(trick.list([trick.int(1), trick.int(2)]), [
{
use tail <- trick.clause(trick.list_pattern({
use _ <- trick.pattern(trick.discard_pattern())
use tail <- trick.tail(trick.variable_pattern("tail"))
tail
}))
tail
},
{
use _ <- trick.clause(trick.discard_pattern())
trick.list([])
}
])
Will generate:
case [1, 2] {
[_, ..tail] -> tail
_ -> []
}
pub fn to_string(module: Module) -> Result(String, Error)
Turns a Module into a string of Gleam code. If you need to import the
module from other generated code, use compile instead.
Examples
{
use _pi <- trick.constant("pi", trick.Public, trick.float(3.14))
trick.end_module()
}
|> trick.to_string
// -> Ok("pub const pi = 3.14")
pub fn todo_(
message: option.Option(Expression(a)),
) -> Expression(Variable)
Generates a todo expression, with an optional message. If present, the
message must be of type String.
Examples
trick.todo_(None) |> trick.expression_to_string
// -> Ok("todo")
trick.todo_(Some(trick.string("uh oh"))) |> trick.expression_to_string
// -> Ok("todo as \"uh oh\"")
trick.todo_(Some(trick.int(42))) |> trick.expression_to_string
// -> Error(TypeMismatch(expected: String, got: Int))
pub fn tuple(values: List(Expression(a))) -> Expression(a)
Generates a tuple from the specified values. The values can be of different types.
Examples
trick.tuple([trick.int(1), trick.float(2.0), trick.string("three")])
|> trick.expression_to_string
// -> Ok("#(1, 2.0, \"three\")")
pub fn tuple_index(
tuple: Expression(a),
index: Int,
) -> Expression(Variable)
Generates a tuple access expression.
Examples
trick.tuple([trick.int(1), trick.float(2.0), trick.string("three")])
|> trick.tuple_index(2)
|> trick.expression_to_string
// -> Ok("#(1, 2.0, \"three\").2")
trick.tuple([trick.int(1), trick.float(2.0), trick.string("three")])
|> trick.tuple_index(4)
|> trick.expression_to_string
// -> Error(TupleIndexOutOfBounds(length: 3, index: 4))
trick.list([trick.int(1), trick.int(2)])
|> trick.tuple_index(0)
|> trick.expression_to_string
// -> Error(InvalidTupleAccess(type_: List(Int)))
pub fn tuple_pattern(
elements: PatternList(Unlabelled, a),
) -> Pattern(a)
Generates a pattern that matches a tuple using the specified elements.
Since tuple patterns can potentially bind more than one variable, the API is
different to that of most other patterns. Here, each element of the pattern
is used, so that each variable can be obtained. At the end of the pattern,
the relevant variables are returned so that they can be referenced in the
clause body.
Examples
trick.case_(trick.tuple([trick.int(1), trick.int(2)]), [
{
use x <- trick.clause(trick.tuple_pattern({
use _ <- trick.pattern(trick.int_pattern(0))
use x <- trick.pattern(trick.variable_pattern("x"))
trick.return_from_pattern(x)
}))
x
},
{
use #(a, b) <- trick.clause(trick.tuple_pattern({
use a <- trick.pattern(trick.variable_pattern("b"))
use b <- trick.pattern(trick.variable_pattern("b"))
trick.return_from_pattern(#(a, b))
}))
trick.add(a, b)
},
])
|> trick.expression_to_string
Will generate:
case #(1, 2) {
#(0, x) -> x
#(a, b) -> a + b
}
pub fn tuple_type(
containing elements: List(Type(NoParameters)),
) -> Type(NoParameters)
Returns a tuple type containing the specified elements.
pub fn type_parameter(
name: String,
continue: fn(Type(NoParameters)) -> CustomType(a),
) -> CustomType(HasParameters)
Adds a type parameter to a custom type.
Examples
{
use dict <- trick.custom_type("Dict", trick.Public)
use key <- trick.type_parameter("key")
use value <- trick.type_parameter("value")
use <- trick.end_custom_type
trick.end_module()
}
|> trick.to_string
// -> Ok("pub type Dict(key, value)")
{
use box_type <- trick.custom_type("Box", trick.Public)
use value <- trick.type_parameter("value")
use box <- trick.constructor("Box", [trick.Field(None, value)])
use <- trick.end_custom_type
trick.end_module()
}
|> trick.to_string
Will generate:
pub type Box(value) {
Box(value)
}
pub fn variable(
name: String,
value: Expression(a),
continue: fn(Expression(Variable)) -> Statement,
) -> Statement
Declares a variable in the current scope. Calls the continuing function with an expression representing the variable name.
For matching more complex patterns, use let_
Examples
trick.block({
use x <- trick.variable("x", trick.int(1))
trick.expression(trick.add(x, trick.int(1)))
})
|> trick.expression_to_string
Will generate:
{
let x = 1
x + 1
}
pub fn variable_pattern(
name: String,
) -> Pattern(Expression(Variable))
Generates a pattern which matches any value and binds it to a variable.
If you want to match a specific value and bind it, see
assignment_pattern.
Examples
trick.case_(trick.int(1), [
{
use a <- trick.clause(trick.variable_pattern("a"))
trick.add(a, trick.int(1))
}
])
|> trick.expression_to_string
Will generate:
case 1 {
a -> a + 1
}
pub fn variant_pattern(constructor: Constructor) -> Pattern(Nil)
Generates a pattern that matches a specific variant of a custom type, without
any parameters. For variants which have parameters, use
constructor_pattern.
Examples
{
use wibble_type <- trick.custom_type(trick.Public, "Wibble")
use wibble <- trick.constructor("Wibble", [])
use wobble <- trick.constructor("Wobble", [])
use <- trick.end_custom_type
use is_wibble <- trick.function(trick.Public, "is_wibble", {
use value <- trick.parameter("value", wibble_type)
trick.function_body(trick.expression(trick.case_(value, [
{
use _ <- trick.clause(trick.variant_pattern(wibble))
trick.bool(True)
},
{
use _ <- trick.clause(trick.variant_pattern(wobble))
trick.bool(False)
},
])))
})
trick.end_module()
}
|> trick.to_string
Will generate:
pub type Wibble {
Wibble
Wobble
}
pub fn is_wibble(value: Wibble) -> Bool {
case value {
Wibble -> True
Wobble -> False
}
}
pub fn with_generics(
type_: Type(HasParameters),
generics: List(Type(NoParameters)),
) -> Type(NoParameters)
Adds generics to a generic type constructor, turning it into a type which can be used in annotations.
Returns an error if the wrong number of parameters are supplied.
Examples
{
use option <- trick.import_(option_module)
let option_type = trick.imported_generic_type(option, "Option")
use wibble <- trick.function("wibble", trick.Public, {
use a <- trick.parameter(
"a",
trick.with_generics(option_type, [trick.int_type()]),
)
use b <- trick.parameter(
"b",
trick.with_generics(option_type, [trick.float_type()]),
)
trick.function_body(trick.expression(trick.tuple([a, b])))
})
}
|> trick.to_string
Will generate:
import gleam/option
pub fn wibble(
a: option.Option(Int),
b: option.Option(Float),
) -> #(option.Option(Int), option.Option(Float)) {
#(a, b)
}