package ppx_camlrack

  1. Overview
  2. Docs
PPX for matching S-Expressions


Dune Dependency





Camlrack: S-Expression Matching in OCaml

Camlrack brings S-Expressions and easy pattern matching for S-Expressions to OCaml like never before!

Full Manual

There is a full manual for Camlrack at docs/

Quick Overview

S-Expressions can be instantiated directly:

open Camlrack

(* Represent '(+ 1 2) *)
let se1 = SExp [ Symbol "+"; Integer 1; Integer 2 ]

(* Represent '(add1 x) *)
let se2 = SExp [ Symbol "add1"; Symbol "x" ]

They can also be parsed from strings:

open Camlrack

let se3 = sexp_of_string_exn "(let ([x 2] [y 3]) (+ x y))"
let se4 = SExp [ Symbol "let"
               ; SExp [ SExp [ Symbol "x"; Integer 2 ]
                      ; SExp [ Symbol "y"; Integer 3 ] ]
               ; SExp [ Symbol "+"; Symbol "x"; Symbol "y" ] ]
assert (s3 = se4)

S-Expressions can also be compared against S-Expression patterns. S-Expression pattern matching is based entirely on the PLAIT language implemented by Matthew Flatt.

open Camlrack

let spat1 = SPat [ SYMBOL    ; INTEGER   ; PSymbol "literal" ]
let sexp1 = SExp [ Symbol "x"; Integer 42; Symbol  "literal" ]
assert (sexp_match spat1 sexp1)

let spat2 = sexp_pattern_of_string_exn "{lambda {SYMBOL ...} ANY ...}"
let sexp2 = sexp_of_string_exn "(lambda (x y) (+ x y))"
assert (sexp_match spat2 sexp2)

PPX Extensions

Camlrack also provides two PPX extensions: %sexp and %spat.


The first can be used to either rewrite strings as S-Expressions (sometimes at compile-time), or else to provide a more fully featured S-Expression matching system.

let sexp1 = [%sexp "(foo bar)"]
let sexp2 = SExp [ Symbol "foo"; Symbol "bar" ]
assert (sexp1 = sexp2)

let do_a_match = function%sexp
  | (foo, bar) -> ...
  | (lambda, (x, y)) -> ...
  | "{lambda {x y}}" -> ... (* redundant; identical to previous case *)

Note that the non-string forms are somewhat limited. PPX extensions are restricted to only supporting syntactically valid OCaml, so the tuple-like form must be built of real tuples (meaning commas are required). Additionally, symbols containing special characters such as those used by operators cannot be handled in the tuple-like form.

For most cases, it is probably advisable to use the string form.


The second extension allows for easy pattern-matching against S-Expressions.

let matching_function sexp = match%spat sexp with
  | "INTEGER" -> "it's an integer"
  | "(lhs rhs)" -> "found two symbols: lhs and rhs"
  | "(let ([SYMBOL ANY] ...) ANY ...)" -> "whoa, pretty fancy!"

This extension only works on match expressions, and the cases must be written as string literals.