Gleam类型系统Skill GleamTypeSystem

这个技能涵盖Gleam语言的类型系统,用于构建类型安全的Erlang VM应用程序。它包括代数数据类型、自定义类型、模式匹配、泛型类型、类型推断、不透明类型、穷举检查和函数式错误处理。关键词:Gleam, 类型系统, 代数数据类型, 模式匹配, 泛型, Erlang VM, 类型安全, 函数式编程。

后端开发 0 次安装 0 次浏览 更新于 3/25/2026

名称: Gleam 类型系统 用户可调用: false 描述: 当需要Gleam的类型系统,包括代数数据类型、自定义类型、模式匹配、泛型类型、类型推断、不透明类型、穷举检查和函数式错误处理,用于构建类型安全的Erlang VM应用程序时使用。 允许工具: []

Gleam 类型系统

介绍

Gleam 是一种静态类型的函数式语言,可编译到 Erlang 和 JavaScript,为 BEAM 生态系统带来现代类型安全。其类型系统在保持 Erlang VM 的并发性和容错性优势的同时,防止了整类运行时错误。

类型系统特点包括代数数据类型、参数多态、类型推断、穷举模式匹配和无空值。每个值都有类型,编译器在编译时强制执行类型安全,在代码运行前消除常见错误。

本技能涵盖自定义类型和ADTs、模式匹配、泛型类型、Result 和 Option 类型、类型别名、不透明类型、类型推断以及BEAM上类型安全错误处理的模式。

自定义类型和记录

自定义类型定义了具有命名字段的结构化数据,提供类型安全访问和模式匹配。

// 简单自定义类型(记录)
pub type User {
  User(name: String, age: Int, email: String)
}

// 创建实例
pub fn create_user() -> User {
  User(name: "Alice", age: 30, email: "alice@example.com")
}

// 访问字段
pub fn get_user_name(user: User) -> String {
  user.name
}

pub fn get_user_age(user: User) -> Int {
  user.age
}

// 更新记录(不可变)
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)
}

// 多个构造函数
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
  }
}

// 元组结构(未标记字段)
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)
}

// 嵌套自定义类型
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
}

// 泛型自定义类型
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
}

// 递归类型
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))
  }
}

// 幻影类型用于类型安全API
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("无效邮箱格式")
  }
}

pub fn send_email(email: Email(Validated)) -> Nil {
  // 只有验证过的邮箱可以发送
  io.println("发送邮件到: " <> email.value)
}

自定义类型提供具有穷举模式匹配保证的命名、类型安全数据结构。

代数数据类型

ADTs 用多个变体建模数据,支持穷举模式匹配并使无效状态无法表示。

// 和类型(枚举)
pub type Status {
  Pending
  Approved
  Rejected
}

pub fn status_to_string(status: Status) -> String {
  case status {
    Pending -> "Pending"
    Approved -> "Approved"
    Rejected -> "Rejected"
  }
}

// Result 类型(内置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("非有效整数")
  }
}

pub fn handle_result(result: Result(Int, String)) -> String {
  case result {
    Ok(n) -> "得到数字: " <> int.to_string(n)
    Error(msg) -> "错误: " <> msg
  }
}

// Option 类型模式
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
  }
}

// 复杂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) -> "成功: " <> body
    Created201(body, location) -> "创建于 " <> location <> ": " <> body
    BadRequest400(message) -> "错误请求: " <> message
    NotFound404 -> "资源未找到"
    ServerError500(message) -> "服务器错误: " <> message
  }
}

// 链表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 类型
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))
    }
  }
}

// 带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
  }
}

// 表达式树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("除以零")
        _ -> Ok(l /. r)
      }
    }
  }
}

ADTs 允许用编译器验证穷举性,类型安全地建模复杂领域逻辑。

模式匹配

模式匹配提供穷举、类型安全的条件逻辑,具有解构能力。

// 基本模式匹配
pub fn describe_number(n: Int) -> String {
  case n {
    0 -> "零"
    1 -> "一"
    2 -> "二"
    _ -> "多"
  }
}

// 带守卫的模式匹配
pub fn classify_age(age: Int) -> String {
  case age {
    n if n < 0 -> "无效"
    n if n < 13 -> "儿童"
    n if n < 20 -> "青少年"
    n if n < 65 -> "成人"
    _ -> "老年人"
  }
}

// 解构元组
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, _, _) -> "第一个是零"
    #(_, "hello", _) -> "第二个是hello"
    #(_, _, True) -> "第三个是真"
    _ -> "其他"
  }
}

// 解构自定义类型
pub fn greet_user(user: User) -> String {
  let User(name: name, age: age, email: _) = user
  "你好 " <> name <> ", 你 " <> int.to_string(age) <> " 岁"
}

pub fn is_circle(shape: Shape) -> Bool {
  case shape {
    Circle(_) -> True
    _ -> False
  }
}

// 嵌套模式匹配
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
  }
}

// 列表模式匹配
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)
  }
}

// 多case表达式
pub fn compare_results(r1: Result(Int, String),
                       r2: Result(Int, String)) -> String {
  case r1, r2 {
    Ok(n1), Ok(n2) -> "都成功: " <> int.to_string(n1 + n2)
    Ok(n), Error(_) -> "第一个成功: " <> int.to_string(n)
    Error(_), Ok(n) -> "第二个成功: " <> int.to_string(n)
    Error(e1), Error(e2) -> "都失败: " <> e1 <> ", " <> e2
  }
}

// 带替代模式的模式匹配
pub fn is_weekend(day: String) -> Bool {
  case day {
    "Saturday" | "Sunday" -> True
    _ -> False
  }
}

// 字符串模式匹配
pub fn parse_command(input: String) -> String {
  case string.lowercase(input) {
    "quit" | "exit" | "q" -> "退出中..."
    "help" | "h" | "?" -> "帮助消息"
    _ -> "未知命令"
  }
}

// 使用表达式处理结果
pub fn divide_and_double(a: Int, b: Int) -> Result(Int, String) {
  use quotient <- result.try(case b {
    0 -> Error("除以零")
    _ -> Ok(a / b)
  })
  Ok(quotient * 2)
}

// 枚举的穷举匹配
pub fn status_code(status: Status) -> Int {
  case status {
    Pending -> 0
    Approved -> 1
    Rejected -> 2
  }
}

模式匹配支持简洁、穷举的条件逻辑,具有编译时验证。

泛型类型和多态

泛型类型允许编写可重用代码,适用于多种类型,同时保持类型安全。

// 泛型函数
pub fn identity(value: a) -> a {
  value
}

pub fn const(a: a, b: b) -> a {
  a
}

// 泛型数据结构
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)
}

// 泛型容器
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
  }
}

// 高阶函数
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)
    }
  }
}

pub fn fold(list: List(a), initial: b, f: fn(b, a) -> b) -> b {
  case list {
    [] -> initial
    [head, ..tail] -> fold(tail, f(initial, head), f)
  }
}

// 泛型Result操作
pub fn result_map(result: Result(a, e), f: fn(a) -> b) -> Result(b, e) {
  case result {
    Ok(value) -> Ok(f(value))
    Error(err) -> Error(err)
  }
}

pub fn result_map_error(result: Result(a, e), f: fn(e) -> f) -> Result(a, f) {
  case result {
    Ok(value) -> Ok(value)
    Error(err) -> Error(f(err))
  }
}

pub fn result_and_then(
  result: Result(a, e),
  f: fn(a) -> Result(b, e),
) -> Result(b, e) {
  case result {
    Ok(value) -> f(value)
    Error(err) -> Error(err)
  }
}

pub fn result_unwrap_or(result: Result(a, e), default: a) -> a {
  case result {
    Ok(value) -> value
    Error(_) -> default
  }
}

// 组合Results
pub fn result_all(results: List(Result(a, e))) -> Result(List(a), e) {
  case results {
    [] -> Ok([])
    [Ok(value), ..rest] -> {
      use tail <- result_and_then(result_all(rest))
      Ok([value, ..tail])
    }
    [Error(err), ..] -> Error(err)
  }
}

// 泛型树操作
pub fn tree_map(tree: Tree(a), f: fn(a) -> b) -> Tree(b) {
  case tree {
    Leaf(value) -> Leaf(f(value))
    Branch(left, right) -> Branch(tree_map(left, f), tree_map(right, f))
  }
}

pub fn tree_fold(tree: Tree(a), initial: b, f: fn(b, a) -> b) -> b {
  case tree {
    Leaf(value) -> f(initial, value)
    Branch(left, right) -> {
      let left_result = tree_fold(left, initial, f)
      tree_fold(right, left_result, f)
    }
  }
}

// 函子模式
pub fn functor_compose(
  fa: Container(a),
  f: fn(a) -> b,
  g: fn(b) -> c,
) -> Container(c) {
  container_map(container_map(fa, f), g)
}

泛型类型支持跨不同具体类型的可重用、类型安全抽象。

类型别名和不透明类型

类型别名创建可读名称给复杂类型,而不透明类型隐藏实现细节。

// 类型别名
pub type UserId = Int
pub type Email = String
pub type Age = Int

pub type UserData = #(UserId, String, Email, Age)

pub fn create_user_data(id: UserId, name: String, email: Email, age: Age) ->
  UserData {
  #(id, name, email, age)
}

// 函数类型别名
pub type Validator(a) = fn(a) -> Result(a, String)
pub type Transformer(a, b) = fn(a) -> b

pub fn validate_age(age: Age) -> Result(Age, String) {
  case age >= 0 && age <= 150 {
    True -> Ok(age)
    False -> Error("无效年龄")
  }
}

// 集合类型别名
pub type StringList = List(String)
pub type IntResult = Result(Int, String)
pub type UserMap = Dict(UserId, User)

// 不透明类型(隐藏内部表示)
pub opaque type Password {
  Password(hash: String)
}

pub fn create_password(plain: String) -> Password {
  // 哈希密码(简化)
  Password(hash: hash_string(plain))
}

pub fn verify_password(password: Password, plain: String) -> Bool {
  let Password(hash: stored_hash) = password
  stored_hash == hash_string(plain)
}

fn hash_string(s: String) -> String {
  // 实现隐藏
  s <> "_hashed"
}

// 不透明类型用于已验证数据
pub opaque type ValidatedEmail {
  ValidatedEmail(value: String)
}

pub fn validate_and_create_email(value: String) ->
  Result(ValidatedEmail, String) {
  case string.contains(value, "@") {
    True -> Ok(ValidatedEmail(value: value))
    False -> Error("无效邮箱格式")
  }
}

pub fn email_to_string(email: ValidatedEmail) -> String {
  let ValidatedEmail(value: value) = email
  value
}

// 不透明类型用于单位
pub opaque type Meters {
  Meters(Float)
}

pub opaque type Feet {
  Feet(Float)
}

pub fn meters(value: Float) -> Meters {
  Meters(value)
}

pub fn feet(value: Float) -> Feet {
  Feet(value)
}

pub fn meters_to_feet(m: Meters) -> Feet {
  let Meters(value) = m
  Feet(value *. 3.28084)
}

pub fn feet_to_meters(f: Feet) -> Meters {
  let Feet(value) = f
  Meters(value /. 3.28084)
}

// 不透明类型用于IDs
pub opaque type OrderId {
  OrderId(Int)
}

pub fn new_order_id(id: Int) -> OrderId {
  OrderId(id)
}

pub fn order_id_to_int(id: OrderId) -> Int {
  let OrderId(value) = id
  value
}

// 带不透明类型的构建器模式
pub opaque type Query {
  Query(table: String, conditions: List(String), limit: Option(Int))
}

pub fn new_query(table: String) -> Query {
  Query(table: table, conditions: [], limit: None)
}

pub fn where(query: Query, condition: String) -> Query {
  let Query(table: table, conditions: conditions, limit: limit) = query
  Query(table: table, conditions: [condition, ..conditions], limit: limit)
}

pub fn limit(query: Query, n: Int) -> Query {
  let Query(table: table, conditions: conditions, limit: _) = query
  Query(table: table, conditions: conditions, limit: Some(n))
}

pub fn to_sql(query: Query) -> String {
  let Query(table: table, conditions: conditions, limit: limit) = query
  let where_clause = case conditions {
    [] -> ""
    _ -> " WHERE " <> string.join(conditions, " AND ")
  }
  let limit_clause = case limit {
    None -> ""
    Some(n) -> " LIMIT " <> int.to_string(n)
  }
  "SELECT * FROM " <> table <> where_clause <> limit_clause
}

类型别名提高可读性,而不透明类型强制不变性并隐藏实现细节。

最佳实践

  1. 使用自定义类型进行领域建模 以在编译时使无效状态无法表示

  2. 利用模式匹配穷举性 确保处理所有情况,无需运行时检查

  3. 首选Result而非异常 用于预期错误,使错误处理显式化

  4. 使用不透明类型进行验证 防止在模块外创建无效值

  5. 应用泛型类型 当算法适用于多种类型时,最大化代码重用

  6. 使用类型别名 提高复杂类型的可读性和可维护性

  7. 模式匹配特定变体 而非使用通配符模式,提高安全性

  8. 使用幻影类型 用于状态机或工作流中的编译时状态跟踪

  9. 避免嵌套Results 通过使用 result.try 或 use 表达式,简化错误处理

  10. 文档化不透明类型不变量 澄清抽象强制约束

常见陷阱

  1. 过度使用泛型类型 当特定类型足够时,增加复杂性而无益处

  2. 不使用不透明类型 暴露内部表示并破坏封装

  3. 忽略编译器警告 关于非穷举模式,导致运行时崩溃

  4. 创建冗余类型别名 对于简单类型,降低清晰度

  5. 在边界处不验证 当使用不透明类型时,允许无效数据创建

  6. 在模式中过度使用下划线 错过有价值的解构机会

  7. 嵌套太多Results 创建回调式复杂性;使用use表达式

  8. 在模式中不使用守卫 当需要条件时,导致冗长case表达式

  9. 创建过于复杂的ADTs 变体太多,降低可维护性

  10. 忘记公共函数的类型注解 降低文档清晰度

何时使用此技能

应用自定义类型时建模具有特定字段和行为的领域实体。

使用ADTs当数据可以存在于多个状态或具有不同属性的变体中。

利用模式匹配用于所有需要解构或穷举性的条件逻辑。

应用泛型类型当实现可重用算法或数据结构时。

使用不透明类型当强制不变量或隐藏模块用户的实现细节时。

使用Result类型用于所有可能失败的操作,使错误处理显式化。

资源