位元詩人 以 OCaml 資料型態建模

Facebook Twitter LinkedIn LINE Skype EverNote GMail Yahoo Email

說明

本文介紹 OCaml 的資料型態,並探討如何利用這些型態進行建模。

需要強調的是,使用 OCaml 來建模並不是因為它提供了特殊的資料型態,而是因為 編譯器會嚴格檢查,確保模型的結構與行為符合預期。這種嚴謹的型態系統,使得建模過程更可靠、更具表達力。

基本型態

OCaml 提供一組核心的基本型態,作為建模的基礎:

  • 布林bool
    用來表示邏輯值,只有 truefalse

  • 整數int
    依系統不同,可能是 32 位元或 64 位元。

  • 浮點數float
    以 IEEE 754 格式表示的浮點數。

  • 字元char
    單一字元,使用 Latin-1 編碼。

  • 字串string
    可變長度的字元序列。

  • 位元組序列bytes
    適合處理原始資料或需要修改的字串內容。

容器型態

除了基本型態之外,OCaml 也提供多種容器型態,用來表達更複雜的資料結構:

  • 陣列array
    線性容器,元素在記憶體中是連續配置,適合需要快速隨機存取的情境。

  • 串列list
    線性容器,由節點組成,元素在記憶體中不連續。適合遞迴處理與模式匹配。

  • 選項option
    二元容器,用 Some 包裹有效值,用 None 表示空值。常用於避免空指標問題。

  • 結果result
    二元容器,用 Ok 包裹成功結果,用 Error 包裹錯誤資訊(通常是字串)。常用於錯誤處理。

  • 元組tuple
    離散值容器,以位置儲存多個值。通常包含兩到三個元素,且型態可以不同。

函式型態

在 OCaml 中,函式本身就是值,因此可以像其他型態一樣被傳遞或儲存。

  • 空值()
    表示沒有參數或沒有回傳值,常用於函式界面中。

  • 泛型'a, 'b
    ' 前綴表示任意型態,並且在同一函式中必須保持一致。這讓函式能夠具備抽象性與重用性。

範例

以下是一個簡單的平方函式:

let square x = x * x

它的型態為:

int -> int

代表此函式接受一個整數並回傳一個整數。

使用者自訂型態

除了基本型態與容器,OCaml 也允許我們定義 使用者自訂型態,用來表達更複雜或語意化的結構:

  • Variant
    以有限離散值的集合為值,常用於表示狀態或分類。類似主流語言中的 Enum

    type color = Red | Green | Blue
  • Record
    離散值容器,以欄位名稱而非位置來儲存值,適合描述結構化資料。

    type student = {
    id : int;
    name : string;
    grade : float;
    }
  • Aliases
    為既有型態加上識別字,讓程式更具可讀性。

    type user_id = int

以 OCaml 建模

OCaml 是一個非常適合建模的語言。這裡的「建模」指的是將 問題空間 (problem space) 映射到相對應的資料型態,並透過編譯器檢查模型是否合理。

在建模過程中,不需要撰寫完整的應用程式,只要能夠清楚表達概念即可。

建模的核心工具

  • Variant + Pattern Matching
    用來宣告型態的階層,並透過編譯器檢查抽象是否合乎預期。這是 OCaml 建模最核心的功能。

  • Record
    用來表達複合資料型態,類似主流語言的結構或類別。與 Variant 搭配時,可以形成多型。
    雖然 OCaml 支援 class,但在實務上幾乎不使用。

  • Option 與 Result
    用來表達可能出現錯誤或空值的情境,比傳統語言的 exception 更優雅。
    因為模型使用者可以自行決定如何處理錯誤,而不是被迫依賴例外機制。

建模哲學

OCaml 的型態系統提供嚴格的檢查機制,讓建模不只是程式設計的一部分,而是一種 抽象驗證
這種方式能夠確保模型的正確性與一致性,並且讓程式更具表達力。

OCaml 建模實例

這裡用 OCaml 來建立一個 markup language 的模型。這是站長自己設計的領域專用語言:

type meta_token =
  | CategoryForm of string * string
  | Category of string

let string_of_meta_token m =
  match m with
  | CategoryForm (k, v) -> k ^ ":" ^ v
  | Category x -> x

type token_syntax =
  | MetaToken of meta_token
  | Literal of string

let string_of_token t =
  match t with
  | MetaToken m -> "<" ^ (string_of_meta_token m) ^ ">"
  | Literal x -> x

type chunk_syntax =
  | Comment of string
  | TokenSequence of token_syntax list
  | Metadata of string * string
  | Newline
  | End

let string_of_chunk s =
  match s with
  | Comment x -> "#" ^ x
  | TokenSequence seq ->
    seq
    |> List.map string_of_token
    |> String.concat ","
  | Metadata (k, v) -> "&" ^ k ^ "=" ^ v
  | Newline -> "\n"
  | End -> ";"

type rule = chunk_syntax list

let string_of_rule r =
  r
  |> List.map string_of_chunk
  |> String.concat ""

type document = rule list

let string_of_document doc =
  doc
  |> List.map string_of_rule
  |> String.concat "\n\n"

(* main *)
let r = [
    Comment " Adverbial indicating the desire to perform an action."; Newline;
    TokenSequence [Literal"想要"; Literal "去"; MetaToken (Category "Verb")];
    Metadata ("meaning", "want to act");
    Metadata ("chunkType", "chunkType");
    End;
  ]

let _ =
  Printf.printf "%s\n" (string_of_rule r)

設計哲學

注意:這裡的程式碼並沒有包含完整的 parser 實作。它的目的不是要建立一個可解析的語言工具,而是將 DSL 的語法結構 映射到 OCaml 的資料型態,並透過編譯器檢查抽象是否合理。

在這個模型中,型態同時承載了 語法 (syntax)語意 (semantics)

  • Syntax 元素CommentNewlineEnd
    這些型態純粹描述結構或格式,用來控制語法的外觀與邊界。

  • Semantics 元素TokenSequenceMetadata
    這些型態則表達語意層次,像是語言片段的組合 (TokenSequence),或附加的語意標註 (Metadata)。

這種混合設計讓 DSL 不只是形式上的語法描述,而是同時能捕捉結構與意義。
換句話說,建模不是「能不能 parse」,而是「能不能把問題空間的語法與語意都映射到型態裡」。

結語

OCaml 的型態系統不僅是一種程式語言特性,更是一種 建模工具
透過 Variant、Record、Option、Result 等型態,我們能夠將問題空間精確映射到程式結構,並藉由編譯器的嚴格檢查,確保模型的正確性。

這樣的建模方式讓程式不只是執行邏輯,更是 抽象的驗證
在設計系統時,OCaml 提供了清晰、可靠且具表達力的途徑,讓開發者能專注於概念本身,而不是陷入語言細節或錯誤處理的混亂。

總結來說,OCaml 的強大之處在於:
它讓我們能以型態為核心,建立穩健的模型,並以簡潔的程式碼表達複雜的抽象。

建模比較:OCaml vs Rust

雖然 OCaml 與 Rust 都屬於 ML 系語言,並且擁有強大的型態系統,但它們在建模上的取向有所不同:

  • OCaml
    專注於抽象建模。Variant、Record、Option、Result 等型態讓開發者能直接映射問題空間,並透過編譯器驗證抽象。建模過程流暢,重心在「如何表達概念」。

  • Rust
    除了型態建模,還必須同時考慮 所有權 (ownership)生命週期 (lifetimes)。這對系統程式設計是優勢,能避免記憶體錯誤。但在建模時會帶來摩擦,因為抽象必須和資源管理綁定。

附註

  • F# 與 OCaml 的建模能力幾乎等效,兩者都能以型態為核心,建立穩健且具表達力的模型。
關於作者

位元詩人 (ByteBard) 是資訊領域碩士,專注於從原型到產品的開發過程,並以工具驅動的方式持續探索技術。喜歡以開源專案作為成果,回饋社群。

主要方向包括:自用工具的打磨 (dogfooding)、編譯器前端在工具開發中的應用,以及將研究與實驗轉化為可維護的開源成果。

除了技術之外,也喜歡日本料理和黑咖啡,偶爾自助旅行,將生活中的靈感融入技術隨筆。