thebushidocollective/han/gleam-type-system

Claude Code and agent skill by thebushidocollective/han

Trust tier 2
  • community
Source check pending

Checking that the SKILL.md file is still in the repository.

Use when gleam's type system including algebraic data types, custom types, pattern matching, generic types, type inference, opaque types, exhaustive checking, and functional error handling for building type-safe Erlang VM applications.

Install

npx vskill@latest install thebushidocollective/han/gleam-type-system

SKILL.md

Gleam Type System

Introduction

Gleam is a statically-typed functional language that compiles to Erlang and JavaScript, bringing modern type safety to the BEAM ecosystem. Its type system prevents entire categories of runtime errors while maintaining the concurrency and fault-tolerance benefits of the Erlang VM.

The type system features algebraic data types, parametric polymorphism, type inference, exhaustive pattern matching, and no null values. Every value is typed, and the compiler enforces type safety at compile time, eliminating common bugs before code runs.

This skill covers custom types and ADTs, pattern matching, generic types, Result and Option types, type aliases, opaque types, type inference, and patterns for type-safe error handling on the BEAM.

Custom Types and Records

Custom types define structured data with named fields, providing type-safe access and pattern matching.

gleam
// Simple custom type (record)
pub type User {
User(name: String, age: Int, email: String)
}
// Creating instances
pub fn create_user() -> User {
User(name: "Alice", age: 30, email: "alice@example.com")
}
// Accessing fields
pub fn get_user_name(user: User) -> String {
user.name
}
pub fn get_user_age(user: User) -> Int {
user.age
}
// Updating records (immutable)
pub fn birthday(user: User) -> User {
User(..user, age: user.age + 1)
}
pub fn change_email(user: User, new_email: String) -> User {
User(..user, email: new_email)
}
// Multiple constructors
pub type Shape {
Circle(radius: Float)
Rectangle(width: Float, height: Float)
Triangle(base: Float, height: Float)
}
pub fn area(shape: Shape) -> Float {
case shape {
Circle(radius) -> 3.14159 *. radius *. radius
Rectangle(width, height) -> width *. height
Triangle(base, height) -> base *. height /. 2.0
}
}
// Tuple structs (unlabeled fields)
pub type Point {
Point(Float, Float)
}
pub fn distance(p1: Point, p2: Point) -> Float {
let Point(x1, y1) = p1
let Point(x2, y2) = p2
let dx = x2 -. x1
let dy = y2 -. y1
float.square_root(dx *. dx +. dy *. dy)
}
// Nested custom types
pub type Address {
Address(street: String, city: String, zip: String)
}
pub type Person {
Person(name: String, age: Int, address: Address)
}
pub fn get_city(person: Person) -> String {
person.address.city
}
// Generic custom types
pub type Box(a) {
Box(value: a)
}
pub fn box_map(box: Box(a), f: fn(a) -> b) -> Box(b) {
Box(value: f(box.value))
}
pub fn unbox(box: Box(a)) -> a {
box.value
}
// Recursive types
pub type Tree(a) {
Leaf(value: a)
Branch(left: Tree(a), right: Tree(a))
}
pub fn tree_depth(tree: Tree(a)) -> Int {
case tree {
Leaf(_) -> 1
Branch(left, right) -> 1 + int.max(tree_depth(left), tree_depth(right))
}
}
// Phantom types for type-safe APIs
pub type Validated
pub type Unvalidated
pub type Email(state) {
Email(value: String)
}
pub fn create_email(value: String) -> Email(Unvalidated) {
Email(value: value)
}
pub fn validate_email(email: Email(Unvalidated)) ->
Result(Email(Validated), String) {
case string.contains(email.value, "@") {
True -> Ok(Email(value: email.value))
False -> Error("Invalid email format")
}
}
pub fn send_email(email: Email(Validated)) -> Nil {
// Only validated emails can be sent
io.println("Sending email to: " <> email.value)
}

Custom types provide named, type-safe data structures with exhaustive pattern matching guarantees.

Algebraic Data Types

ADTs model data with multiple variants, enabling exhaustive pattern matching and making invalid states unrepresentable.

gleam
// Sum type (enum)
pub type Status {
Pending
Approved
Rejected
}
pub fn status_to_string(status: Status) -> String {
case status {
Pending -> "Pending"
Approved -> "Approved"
Rejected -> "Rejected"
}
}
// Result type (built-in ADT)
pub type Result(ok, error) {
Ok(ok)
Error(error)
}
pub fn parse_int(str: String) -> Result(Int, String) {
case int.parse(str) {
Ok(n) -> Ok(n)
Error(_) -> Error("Not a valid integer")
}
}
pub fn handle_result(result: Result(Int, String)) -> String {
case result {
Ok(n) -> "Got number: " <> int.to_string(n)
Error(msg) -> "Error: " <> msg
}
}
// Option type pattern
pub type Option(a) {
Some(a)
None
}
pub fn find_user(id: Int) -> Option(User) {
case id {
1 -> Some(User(name: "Alice", age: 30, email: "alice@example.com"))
_ -> None
}
}
pub fn option_map(opt: Option(a), f: fn(a) -> b) -> Option(b) {
case opt {
Some(value) -> Some(f(value))
None -> None
}
}
pub fn option_unwrap_or(opt: Option(a), default: a) -> a {
case opt {
Some(value) -> value
None -> default
}
}
// Complex ADTs
pub type HttpResponse {
Ok200(body: String)
Created201(body: String, location: String)
BadRequest400(message: String)
NotFound404
ServerError500(message: String)
}
pub fn handle_response(response: HttpResponse) -> String {
case response {
Ok200(body) -> "Success: " <> body
Created201(body, location) -> "Created at " <> location <> ": " <> body
BadRequest400(message) -> "Bad request: " <> message
NotFound404 -> "Resource not found"
ServerError500(message) -> "Server error: " <> message
}
}
// Linked list ADT
pub type List(a) {
Nil
Cons(head: a, tail: List(a))
}
pub fn list_length(list: List(a)) -> Int {
case list {
Nil -> 0
Cons(_, tail) -> 1 + list_length(tail)
}
}
pub fn list_map(list: List(a), f: fn(a) -> b) -> List(b) {
case list {
Nil -> Nil
Cons(head, tail) -> Cons(f(head), list_map(tail, f))
}
}
// Either type
pub type Either(left, right) {
Left(left)
Right(right)
}
pub fn partition_either(list: List(Either(a, b))) -> #(List(a), List(b)) {
case list {
Nil -> #(Nil, Nil)
Cons(Left(a), tail) -> {
let #(lefts, rights) = partition_either(tail)
#(Cons(a, lefts), rights)
}
Cons(Right(b), tail) -> {
let #(lefts, rights) = partition_either(tail)
#(lefts, Cons(b, rights))
}
}
}
// State machine with ADTs
pub type ConnectionState {
Disconnected
Connecting(attempt: Int)
Connected(session_id: String)
Disconnecting
}
pub fn handle_connect_event(state: ConnectionState) -> ConnectionState {
case state {
Disconnected -> Connecting(attempt: 1)
Connecting(attempt) if attempt < 3 -> Connecting(attempt: attempt + 1)
Connecting(_) -> Disconnected
Connected(_) -> state
Disconnecting -> state
}
}
// Expression tree ADT
pub type Expr {
Number(Float)
Add(left: Expr, right: Expr)
Subtract(left: Expr, right: Expr)
Multiply(left: Expr, right: Expr)
Divide(left: Expr, right: Expr)
}
pub fn evaluate(expr: Expr) -> Result(Float, String) {
case expr {
Number(n) -> Ok(n)
Add(left, right) -> {
use l <- result.try(evaluate(left))
use r <- result.try(evaluate(right))
Ok(l +. r)
}
Subtract(left, right) -> {
use l <- result.try(evaluate(left))
use r <- result.try(evaluate(right))
Ok(l -. r)
}
Multiply(left, right) -> {
use l <- result.try(evaluate(left))
use r <- result.try(evaluate(right))
Ok(l *. r)
}
Divide(left, right) -> {
use l <- result.try(evaluate(left))
use r <- result.try(evaluate(right))
case r {
0.0 -> Error("Division by zero")
_ -> Ok(l /. r)
}
}
}
}

ADTs enable type-safe modeling of complex domain logic with compiler-verified exhaustiveness.

Pattern Matching

Pattern matching provides exhaustive, type-safe conditional logic with destructuring capabilities.

gleam
// Basic pattern matching
pub fn describe_number(n: Int) -> String {
case n {
0 -> "zero"
1 -> "one"
2 -> "two"
_ -> "many"
}
}
// Pattern matching with guards
pub fn classify_age(age: Int) -> String {
case age {
n if n < 0 -> "Invalid"
n if n < 13 -> "Child"
n if n < 20 -> "Teen"
n if n < 65 -> "Adult"
_ -> "Senior"
}
}
// Destructuring tuples
pub fn swap(pair: #(a, b)) -> #(b, a) {
let #(first, second) = pair
#(second, first)
}
pub fn tuple_pattern(tuple: #(Int, String, Bool)) -> String {
case tuple {
#(0, _, _) -> "First is zero"
#(_, "hello", _) -> "Second is hello"
#(_, _, True) -> "Third is true"
_ -> "Something else"
}
}
// Destructuring custom types
pub fn greet_user(user: User) -> String {
let User(name: name, age: age, email: _) = user
"Hello " <> name <> ", you are " <> int.to_string(age)
}
pub fn is_circle(shape: Shape) -> Bool {
case shape {
Circle(_) -> True
_ -> False
}
}
// Nested pattern matching
pub type Nested {
Outer(inner: Inner)
}
pub type Inner {
Value(Int)
Empty
}
pub fn extract_value(nested: Nested) -> Option(Int) {
case nested {
Outer(Value(n)) -> Some(n)
Outer(Empty) -> None
}
}
// List pattern matching
pub fn list_sum(list: List(Int)) -> Int {
case list {
[] -> 0
[head] -> head
[first, second] -> first + second
[head, ..tail] -> head + list_sum(tail)
}
}
pub fn list_head(list: List(a)) -> Option(a) {
case list {
[] -> None
[head, ..] -> Some(head)
}
}
// Multiple case expressions
pub fn compare_results(r1: Result(Int, String),
r2: Result(Int, String)) -> String {
case r1, r2 {
Ok(n1), Ok(n2) -> "Both ok: " <> int.to_string(n1 + n2)
Ok(n), Error(_) -> "First ok: " <> int.to_string(n)
Error(_), Ok(n) -> "Second ok: " <> int.to_string(n)
Error(e1), Error(e2) -> "Both failed: " <> e1 <> ", " <> e2
}
}
// Pattern matching with alternative patterns
pub fn is_weekend(day: String) -> Bool {
case day {
"Saturday" | "Sunday" -> True
_ -> False
}
}
// Matching on string patterns
pub fn parse_command(input: String) -> String {
case string.lowercase(input) {
"quit" | "exit" | "q" -> "Exiting..."
"help" | "h" | "?" -> "Help message"
_ -> "Unknown command"
}
}
// Use expressions for result handling
pub fn divide_and_double(a: Int, b: Int) -> Result(Int, String) {
use quotient <- result.try(case b {
0 -> Error("Division by zero")
_ -> Ok(a / b)
})
Ok(quotient * 2)
}
// Exhaustive matching on enums
pub fn status_code(status: Status) -> Int {
case status {
Pending -> 0
Approved -> 1
Rejected -> 2
}
}

Pattern matching enables concise, exhaustive conditional logic with compile-time verification.

Generic Types and Polymorphism

Generic types enable writing reusable code that works with multiple types while maintaining type safety.

gleam
// Generic function
pub fn identity(value: a) -> a {
value
}
pub fn const(a: a, b: b) -> a {
a
}
// Generic data structure
pub type Pair(a, b) {
Pair(first: a, second: b)
}
pub fn pair_map_first(pair: Pair(a, b), f: fn(a) -> c) -> Pair(c, b) {
Pair(first: f(pair.first), second: pair.second)
}
pub fn pair_map_second(pair: Pair(a, b), f: fn(b) -> c) -> Pair(a, c) {
Pair(first: pair.first, second: f(pair.second))
}
pub fn pair_swap(pair: Pair(a, b)) -> Pair(b, a) {
Pair(first: pair.second, second: pair.first)
}
// Generic container
pub type Container(a) {
Empty
Full(value: a)
}
pub fn container_map(cont: Container(a), f: fn(a) -> b) -> Container(b) {
case cont {
Empty -> Empty
Full(value) -> Full(f(value))
}
}
pub fn container_unwrap_or(cont: Container(a), default: a) -> a {
case cont {
Empty -> default
Full(value) -> value
}
}
// Higher-order functions
pub fn map(list: List(a), f: fn(a) -> b) -> List(b) {
case list {
[] -> []
[head, ..tail] -> [f(head), ..map(tail, f)]
}
}
pub fn filter(list: List(a), predicate: fn(a) -> Bool) -> List(a) {
case list {
[] -> []
[head, ..tail] -> case predicate(head) {
True -> [head, ..filter(tail, predicate)]
False -> filter(tail, predicate)
}
}
}

This is the start of the file. Read the full SKILL.md on GitHub.

Security

  • Security scanPassed, 100 of 100Pattern checks on the skill's files.
  • Model reviewPassed

Quality evaluation

  • Task evaluationNot runNo evaluation yet. Run one in Skill Studio.

Source

Popularity

Repository stars
129
Repository forks
14
7-day trend score
24

Stars and forks are for the whole GitHub repository, not this skill alone. Refreshed 29 Mar 2026, 7 months ago.

Works with

Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.

  • Claude Code
  • Cursor
  • GitHub Copilot
  • Windsurf
  • Codex
  • Gemini CLI
  • Cline
  • Amp
  • Roo Code
  • Goose
  • Continue
  • Kilo Code
  • Junie
  • Trae
  • OpenHands
  • Qwen Code
  • AI Agent
  • Tabnine Chat
  • Sourcegraph Cody
  • Amazon Q
  • Firebase Genkit
  • Sweep
  • Devin
  • Phind
  • Mentat
  • Claude Desktop
  • Aider
  • GPT Pilot
  • Plandex
  • bolt.new
  • v0
  • Replit Agent
  • Anse
  • TypingMind
  • BetterChatGPT
  • LibreChat
  • Warp AI
  • Pieces
  • Fig AI
Embed badge
vskill VERIFIED badge
[![vskill VERIFIED](https://verified-skill.com/api/v1/skills/thebushidocollective/han/gleam-type-system/badge)](https://verified-skill.com/skills/thebushidocollective/han/gleam-type-system)

Something wrong with this skill or its page? Tell us.