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

Types

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

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

Indicates that an expression is constant and can be assigned to a const.

pub type Constant

Information about a custom type.

pub opaque type CustomType(a)

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)
}

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

  • NoCaptureHole

    No capture hole is provided to a function_capture_alt call

  • DuplicateCaptureHole

    More than one capture hole is provided to a function_capture_alt call

  • InvalidName(name: String, expected: NameCase)

    The name of a value does not match what is expected.

A single expression, either marked as Constant or Variable.

pub opaque type Expression(a)

The field of a custom type variant.

pub type Field {
  Field(label: option.Option(String), type_: Type)
}

Constructors

Information about the labels and arity of a function or constructor.

pub type FieldMap {
  FieldMap(arity: Int, fields: dict.Dict(String, Int))
}

Constructors

  • FieldMap(arity: Int, fields: dict.Dict(String, Int))

Information 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

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

opaque

A module containing one or more definitions.

pub opaque type Module
pub type NameCase {
  SnakeCase
  PascalCase
}

Constructors

  • SnakeCase
  • PascalCase

Indicates that a custom type has no type parameters.

pub type NoParameters

The publicity of a top-level definition.

pub type Publicity {
  Public
  Internal
  Private
}

Constructors

  • Public
  • Internal
  • Private

One or more statements that can be used in a block or function body.

pub opaque type Statement

Type

opaque

The type of a value. This is different to ConcreteType in that it exists before type-checking and does not contain complete information yet.

pub opaque type Type

Indicates that a function does not have labelled arguments and can be turned into an anonymous function.

pub type Unlabelled

Indicates that an expression includes a runtime computation can cannot be assigned to a const.

pub type Variable

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 bit_array_type() -> Type

Returns the BitArray type.

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_type() -> Type

Returns the Bool type.

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 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 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 constructor(
  name: String,
  fields: List(Field),
  continue: fn(Expression(Constant)) -> 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 custom_type(
  name: String,
  publicity: Publicity,
  continue: fn(Type) -> 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 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 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.

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() }

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 float(value: Float) -> Expression(a)

Generates a Float.

Examples

trick.float(3.14) |> trick.expression_to_string
// -> Ok("3.14")
pub fn float_type() -> Type

Returns the Float type.

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),
  return: Type,
) -> Type

Returns a function type with the specified parameters and return type.

pub fn generic(name: String) -> Type

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 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_type() -> Type

Returns the Int type.

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,
  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 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 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_type(of element_type: Type) -> Type

Returns a List type with the specified element type.

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 nil_type() -> Type

Returns the Nil type.

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,
  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 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 string(value: String) -> Expression(a)

Generates a String.

Examples

trick.string("Hello, world!") |> trick.expression_to_string
// -> Ok("\"Hello, world!\"")
pub fn string_type() -> Type

Returns the String type.

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 to_string(module: Module) -> Result(String, Error)

Turns a Module into a string of Gleam code.

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_type(containing elements: List(Type)) -> Type

Returns a tuple type containing the specified elements.

pub fn type_parameter(
  name: String,
  continue: fn(Type) -> 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 utf_codepoint_type() -> Type

Returns the UtfCodepoint type.

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.

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
}
Search Document