🦀 Functional Rust
🎬 Traits & Generics Shared behaviour, static vs dynamic dispatch, zero-cost polymorphism.
📝 Text version (for readers / accessibility)

• Traits define shared behaviour — like interfaces but with default implementations

• Generics with trait bounds: fn process(item: T) — monomorphized at compile time

• Static dispatch (impl Trait) = zero cost; dynamic dispatch (dyn Trait) = runtime flexibility via vtable

• Blanket implementations apply traits to all types matching a bound

• Associated types and supertraits enable complex type relationships

207: Prism Laws — What Makes a Prism Well-Behaved

Difficulty: ⭐⭐⭐ Level: Intermediate Two round-trip laws guarantee that a Prism's `preview` and `review` are consistent with each other.

The Problem This Solves

A Prism is just two functions. Nothing stops you from writing a `preview` that transforms the value it returns — say, uppercasing a string before returning it — while `review` doesn't apply the same transformation. The code compiles. Basic tests might pass. But when you use this Prism in composition, the round-trip breaks: you put in `"hello"`, preview gives you `"HELLO"`, review puts back `"HELLO"` — and now your data has silently changed. Unlike Lens laws (which verify that get and set are inverses of each other), Prism laws verify that construction and deconstruction are consistent. `review` builds a value; `preview` should be able to read that same value back out unchanged. If the Prism's two functions aren't compatible, it's not a Prism in any meaningful sense — it's just two unrelated functions wrapped in the same struct. Laws make Prisms composable and trustworthy. When every Prism satisfies both laws, you can compose them confidently. This example exists to solve exactly that pain.

The Intuition

A Prism is a relationship between a "big" type `S` (the enum) and a "small" type `A` (the variant's payload). The two laws express that this relationship is consistent: Law 1 — ReviewPreview: "If I build an `S` using `review`, I can always get back my `A` using `preview`."
preview(review(a)) == Some(a)
You put `"hello"` into a `JString` via `review`. `preview` on that `JString` must give back `Some("hello")` — exactly what you put in. Not `Some("HELLO")`. Not `Some("hello ")`. Exactly `"hello"`. Law 2 — PreviewReview: "If `preview` succeeds and gives me `a`, then `review(a)` reconstructs the original `s`."
if preview(s) == Some(a)  then  review(a) == s
If you look at a `JString("hello")` and preview gives `Some("hello")`, then building from `"hello"` with `review` must give back `JString("hello")` — the exact original. An unlawful Prism in this file `preview`s with `.to_uppercase()` — it transforms the value during extraction. `review` doesn't uppercase. So `preview(review("hello"))` gives `Some("HELLO")` ≠ `Some("hello")`. Law 1 broken.

How It Works in Rust

Lawful Prisms for a `Json` type:
fn jstring_prism() -> Prism<Json, String> {
 Prism::new(
     |j| match j { Json::JString(s) => Some(s.clone()), _ => None },
     |s| Json::JString(s),
 )
}
`preview` extracts the string as-is. `review` wraps it. No transformation — perfectly consistent. The unlawful Prism:
fn bad_prism() -> Prism<Json, String> {
 Prism::new(
     |j| match j { Json::JString(s) => Some(s.to_uppercase()), _ => None },
     |s| Json::JString(s),  // review doesn't uppercase!
 )
}
Law verification functions:
// Law 1: preview(review(a)) == Some(a)
fn check_review_preview<S: PartialEq, A: Clone + PartialEq>(
 prism: &Prism<S, A>, a: &A,
) -> bool {
 let s = (prism.review)(a.clone());
 (prism.preview)(&s) == Some(a.clone())
}

// Law 2: if preview(s) == Some(a) then review(a) == s
fn check_preview_review<S: PartialEq + Clone, A: Clone>(
 prism: &Prism<S, A>, s: &S,
) -> bool {
 match (prism.preview)(s) {
     None    => true,                      // preview didn't match — vacuously true
     Some(a) => (prism.review)(a) == *s,  // reconstruct and compare
 }
}
Running the checks:
// jstring_prism is lawful
let p = jstring_prism();
assert!(check_review_preview(&p, &"hello".to_string()));
assert!(check_preview_review(&p, &Json::JString("hello".into())));
assert!(check_preview_review(&p, &Json::JNull));  // None case — trivially true

// bad_prism violates both laws
let bp = bad_prism();
assert!(!check_review_preview(&bp, &"hello".to_string()));
// preview(review("hello")) = preview(JString("hello")) = Some("HELLO") ≠ Some("hello")
assert!(!check_preview_review(&bp, &Json::JString("hello".into())));
// preview gives "HELLO", review("HELLO") = JString("HELLO") ≠ JString("hello")

What This Unlocks

Key Differences

ConceptOCamlRust
Law 1 nameReviewPreviewReviewPreview
Law 2 namePreviewReviewPreviewReview
Equality checkStructural `=` on variants`PartialEq` required on both `S` and `A`
Vacuous case (Law 2)`None -> true` in match`None => true` — same pattern
Unlawful example`String.uppercase_ascii` in preview`.to_uppercase()` in preview closure
Batch testing`List.for_all` over test values`slice.iter().all(…)` or loop
// Example 207: Prism Laws — ReviewPreview and PreviewReview

struct Prism<S, A> {
    preview: Box<dyn Fn(&S) -> Option<A>>,
    review: Box<dyn Fn(A) -> S>,
}

impl<S: 'static, A: 'static> Prism<S, A> {
    fn new(
        preview: impl Fn(&S) -> Option<A> + 'static,
        review: impl Fn(A) -> S + 'static,
    ) -> Self {
        Prism { preview: Box::new(preview), review: Box::new(review) }
    }
}

// Approach 1: Lawful prisms for a JSON type
#[derive(Debug, Clone, PartialEq)]
enum Json {
    JString(String),
    JInt(i64),
    JBool(bool),
    JNull,
    JArray(Vec<Json>),
}

fn jstring_prism() -> Prism<Json, String> {
    Prism::new(
        |j| match j { Json::JString(s) => Some(s.clone()), _ => None },
        |s| Json::JString(s),
    )
}

fn jint_prism() -> Prism<Json, i64> {
    Prism::new(
        |j| match j { Json::JInt(n) => Some(*n), _ => None },
        |n| Json::JInt(n),
    )
}

fn jbool_prism() -> Prism<Json, bool> {
    Prism::new(
        |j| match j { Json::JBool(b) => Some(*b), _ => None },
        |b| Json::JBool(b),
    )
}

// Approach 2: An UNLAWFUL prism
fn bad_prism() -> Prism<Json, String> {
    Prism::new(
        |j| match j { Json::JString(s) => Some(s.to_uppercase()), _ => None },
        |s| Json::JString(s), // review doesn't uppercase!
    )
}

// Approach 3: Law verification
fn check_review_preview<S: PartialEq, A: Clone + PartialEq>(
    prism: &Prism<S, A>, a: &A,
) -> bool {
    let s = (prism.review)(a.clone());
    (prism.preview)(&s) == Some(a.clone())
}

fn check_preview_review<S: PartialEq + Clone, A: Clone>(
    prism: &Prism<S, A>, s: &S,
) -> bool {
    match (prism.preview)(s) {
        None => true,
        Some(a) => (prism.review)(a) == *s,
    }
}

fn main() {
    // jstring_prism is lawful
    let p = jstring_prism();
    for val in &["hello".to_string(), "world".into(), "".into()] {
        assert!(check_review_preview(&p, val));
    }
    for src in &[Json::JString("hello".into()), Json::JInt(42), Json::JNull] {
        assert!(check_preview_review(&p, src));
    }

    // jint_prism is lawful
    let p = jint_prism();
    for val in &[1i64, 0, -99] {
        assert!(check_review_preview(&p, val));
    }

    // bad_prism violates ReviewPreview
    let bp = bad_prism();
    assert!(!check_review_preview(&bp, &"hello".to_string()));
    // preview(review("hello")) = Some("HELLO") ≠ Some("hello")

    // Also violates PreviewReview
    let s = Json::JString("hello".into());
    assert!(!check_preview_review(&bp, &s));
    // preview gives "HELLO", review("HELLO") = JString("HELLO") ≠ JString("hello")

    println!("✓ All tests passed");
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_review_preview_law() {
        let p = jbool_prism();
        assert!(check_review_preview(&p, &true));
        assert!(check_review_preview(&p, &false));
    }

    #[test]
    fn test_preview_review_law() {
        let p = jint_prism();
        assert!(check_preview_review(&p, &Json::JInt(42)));
        assert!(check_preview_review(&p, &Json::JString("x".into())));
    }

    #[test]
    fn test_bad_prism_violates() {
        let bp = bad_prism();
        assert!(!check_review_preview(&bp, &"test".to_string()));
    }
}
(* Example 207: Prism Laws — ReviewPreview and PreviewReview *)

type ('s, 'a) prism = {
  preview : 's -> 'a option;
  review  : 'a -> 's;
}

(* Prism Laws:
   1. ReviewPreview: preview (review a) = Some a
      (round-trip: inject then extract always succeeds)
   2. PreviewReview: if preview s = Some a then review a = s
      (round-trip: if extraction succeeds, re-injection gives back original)
*)

(* Approach 1: Lawful prisms *)
type json =
  | JString of string
  | JInt of int
  | JBool of bool
  | JNull
  | JArray of json list

let jstring_prism : (json, string) prism = {
  preview = (function JString s -> Some s | _ -> None);
  review = (fun s -> JString s);
}

let jint_prism : (json, int) prism = {
  preview = (function JInt n -> Some n | _ -> None);
  review = (fun n -> JInt n);
}

let jbool_prism : (json, bool) prism = {
  preview = (function JBool b -> Some b | _ -> None);
  review = (fun b -> JBool b);
}

(* Approach 2: An UNLAWFUL prism *)
let bad_prism : (json, string) prism = {
  preview = (function JString s -> Some (String.uppercase_ascii s) | _ -> None);
  (* violates PreviewReview: preview gives uppercase, review uses original *)
  review = (fun s -> JString s);
}

(* Approach 3: Law verification *)
let check_review_preview prism a =
  prism.preview (prism.review a) = Some a

let check_preview_review prism s =
  match prism.preview s with
  | None -> true  (* law only applies when preview succeeds *)
  | Some a -> prism.review a = s

let verify_prism_laws name prism values sources =
  let rp = List.for_all (check_review_preview prism) values in
  let pr = List.for_all (check_preview_review prism) sources in
  Printf.printf "%s: ReviewPreview=%b PreviewReview=%b\n" name rp pr;
  (rp, pr)

(* === Tests === *)
let () =
  (* jstring_prism is lawful *)
  let (rp, pr) = verify_prism_laws "jstring"
    jstring_prism
    ["hello"; "world"; ""]
    [JString "hello"; JInt 42; JNull] in
  assert rp; assert pr;

  (* jint_prism is lawful *)
  let (rp, pr) = verify_prism_laws "jint"
    jint_prism
    [1; 0; -99]
    [JInt 1; JString "x"; JBool true] in
  assert rp; assert pr;

  (* bad_prism violates PreviewReview *)
  let rp = check_review_preview bad_prism "hello" in
  assert (not rp); (* preview(review "hello") = Some "HELLO" ≠ Some "hello" *)

  (* Verify specific violation *)
  let s = JString "hello" in
  (match bad_prism.preview s with
   | Some a -> assert (bad_prism.review a <> s) (* "HELLO" ≠ "hello" *)
   | None -> assert false);

  print_endline "✓ All tests passed"

📊 Detailed Comparison

Comparison: Example 207 — Prism Laws

ReviewPreview Law

OCaml

🐪 Show OCaml equivalent
let check_review_preview prism a =
prism.preview (prism.review a) = Some a

Rust

fn check_review_preview<S: PartialEq, A: Clone + PartialEq>(
 prism: &Prism<S, A>, a: &A,
) -> bool {
 (prism.preview)(&(prism.review)(a.clone())) == Some(a.clone())
}

PreviewReview Law

OCaml

🐪 Show OCaml equivalent
let check_preview_review prism s =
match prism.preview s with
| None -> true
| Some a -> prism.review a = s

Rust

fn check_preview_review<S: PartialEq + Clone, A: Clone>(
 prism: &Prism<S, A>, s: &S,
) -> bool {
 match (prism.preview)(s) {
     None => true,
     Some(a) => (prism.review)(a) == *s,
 }
}

Unlawful Prism

OCaml

🐪 Show OCaml equivalent
let bad_prism = {
preview = (function JString s -> Some (String.uppercase_ascii s) | _ -> None);
review = (fun s -> JString s);
}
(* preview (review "hello") = Some "HELLO" ≠ Some "hello" *)

Rust

fn bad_prism() -> Prism<Json, String> {
 Prism::new(
     |j| match j { Json::JString(s) => Some(s.to_uppercase()), _ => None },
     |s| Json::JString(s),
 )
}
// preview(review("hello")) = Some("HELLO") ≠ Some("hello")