ExamplesBy LevelBy TopicLearning Paths
941 Expert

941 Identity Monad

Functional Programming

Tutorial

The Problem

Implement the identity monad — the simplest possible monad — as a Rust struct. It wraps a value with no additional effects, serving as the base case in monad transformer stacks and as a teaching tool for monad laws. Implement of (pure/return), bind (>>=), and map (fmap), then verify the three monad laws: left identity, right identity, and associativity.

🎯 Learning Outcomes

  • • Understand the identity monad as the "no-op" wrapper that satisfies monad laws without adding effects
  • • Implement of, bind, and map for a concrete monadic type in Rust
  • • Verify the three monad laws: left identity (return a >>= f = f a), right identity (m >>= return = m), and associativity ((m >>= f) >>= g = m >>= (|x| f x >>= g))
  • • Recognize how bind encodes sequential composition of computations
  • • Understand why the identity monad is the base case for monad transformers (e.g., StateT Identity = State)
  • Code Example

    #![allow(clippy::all)]
    // Identity monad — the simplest possible monad.
    // Wraps a value with zero extra effects.
    // Useful as a base case in monad transformers.
    
    #[derive(Debug, Clone, PartialEq)]
    struct Identity<A>(A);
    
    impl<A> Identity<A> {
        /// monadic `return` / `pure` — lift a value into Identity
        fn of(x: A) -> Self {
            Identity(x)
        }
    
        /// `bind` (>>=) — sequence computations
        fn bind<B, F: FnOnce(A) -> Identity<B>>(self, f: F) -> Identity<B> {
            f(self.0)
        }
    
        /// Functor `map`
        fn map<B, F: FnOnce(A) -> B>(self, f: F) -> Identity<B> {
            Identity(f(self.0))
        }
    
        /// Extract the wrapped value
        fn run(self) -> A {
            self.0
        }
    }
    
    #[cfg(test)]
    mod tests {
        use super::*;
    
        #[test]
        fn test_functor_identity_law() {
            // map id = id
            let v = Identity(42);
            assert_eq!(v.clone().map(|x| x), v);
        }
    
        #[test]
        fn test_bind_chain() {
            let result = Identity::of(10)
                .bind(|x| Identity::of(x * 2))
                .bind(|x| Identity::of(x + 1));
            assert_eq!(result.run(), 21);
        }
    
        #[test]
        fn test_monad_left_identity() {
            // left identity: return a >>= f = f a
            let f = |x: i32| Identity::of(x * 3);
            let lhs = Identity::of(5).bind(f);
            let rhs = f(5);
            assert_eq!(lhs, rhs);
        }
    
        #[test]
        fn test_monad_right_identity() {
            // right identity: m >>= return = m
            let m = Identity(42);
            let result = m.clone().bind(Identity::of);
            assert_eq!(result, m);
        }
    
        #[test]
        fn test_map_composition_law() {
            // map (f . g) = map f . map g
            let v = Identity(5);
            let f = |x: i32| x + 1;
            let g = |x: i32| x * 2;
            let lhs = v.clone().map(|x| f(g(x)));
            let rhs = v.map(g).map(f);
            assert_eq!(lhs, rhs);
        }
    }

    Key Differences

    AspectRustOCaml
    HKT supportNone — each monad is a standalone structModule functors enable generic monad abstractions
    SyntaxMethod chaining: .bind(...).bind(...)let* / >>= operator
    Law verificationTests with assert_eq!Property tests or equational reasoning
    Monad transformersNo generic transformer stack possibleStateT, ReaderT, etc. via functors

    The identity monad is a pedagogical foundation. Understanding it makes other monads — Option (fail-fast), Result (error propagation), Vec (non-determinism) — easier to see as specializations of the same bind/return pattern.

    OCaml Approach

    (* OCaml with ppx_let for monadic syntax *)
    module Identity = struct
      type 'a t = Id of 'a
    
      let return x = Id x
      let bind (Id x) f = f x
      let map f (Id x) = Id (f x)
      let run (Id x) = x
    end
    
    (* Monad laws as expressions *)
    let left_identity a f =
      (* return a >>= f = f a *)
      Identity.(bind (return a) f = f a)
    
    let right_identity m =
      (* m >>= return = m *)
      let open Identity in
      bind m return = m
    
    (* With let* syntax (OCaml 4.08+) *)
    let pipeline =
      let open Identity in
      let* x = return 10 in
      let* y = return (x * 2) in
      return (y + 1)
    (* = Id 21 *)
    

    OCaml's module system makes it natural to define a MONAD signature and prove that Identity satisfies it. The let* syntax (monadic bind) makes pipelines readable without requiring do-notation.

    Full Source

    #![allow(clippy::all)]
    // Identity monad — the simplest possible monad.
    // Wraps a value with zero extra effects.
    // Useful as a base case in monad transformers.
    
    #[derive(Debug, Clone, PartialEq)]
    struct Identity<A>(A);
    
    impl<A> Identity<A> {
        /// monadic `return` / `pure` — lift a value into Identity
        fn of(x: A) -> Self {
            Identity(x)
        }
    
        /// `bind` (>>=) — sequence computations
        fn bind<B, F: FnOnce(A) -> Identity<B>>(self, f: F) -> Identity<B> {
            f(self.0)
        }
    
        /// Functor `map`
        fn map<B, F: FnOnce(A) -> B>(self, f: F) -> Identity<B> {
            Identity(f(self.0))
        }
    
        /// Extract the wrapped value
        fn run(self) -> A {
            self.0
        }
    }
    
    #[cfg(test)]
    mod tests {
        use super::*;
    
        #[test]
        fn test_functor_identity_law() {
            // map id = id
            let v = Identity(42);
            assert_eq!(v.clone().map(|x| x), v);
        }
    
        #[test]
        fn test_bind_chain() {
            let result = Identity::of(10)
                .bind(|x| Identity::of(x * 2))
                .bind(|x| Identity::of(x + 1));
            assert_eq!(result.run(), 21);
        }
    
        #[test]
        fn test_monad_left_identity() {
            // left identity: return a >>= f = f a
            let f = |x: i32| Identity::of(x * 3);
            let lhs = Identity::of(5).bind(f);
            let rhs = f(5);
            assert_eq!(lhs, rhs);
        }
    
        #[test]
        fn test_monad_right_identity() {
            // right identity: m >>= return = m
            let m = Identity(42);
            let result = m.clone().bind(Identity::of);
            assert_eq!(result, m);
        }
    
        #[test]
        fn test_map_composition_law() {
            // map (f . g) = map f . map g
            let v = Identity(5);
            let f = |x: i32| x + 1;
            let g = |x: i32| x * 2;
            let lhs = v.clone().map(|x| f(g(x)));
            let rhs = v.map(g).map(f);
            assert_eq!(lhs, rhs);
        }
    }
    ✓ Tests Rust test suite
    #[cfg(test)]
    mod tests {
        use super::*;
    
        #[test]
        fn test_functor_identity_law() {
            // map id = id
            let v = Identity(42);
            assert_eq!(v.clone().map(|x| x), v);
        }
    
        #[test]
        fn test_bind_chain() {
            let result = Identity::of(10)
                .bind(|x| Identity::of(x * 2))
                .bind(|x| Identity::of(x + 1));
            assert_eq!(result.run(), 21);
        }
    
        #[test]
        fn test_monad_left_identity() {
            // left identity: return a >>= f = f a
            let f = |x: i32| Identity::of(x * 3);
            let lhs = Identity::of(5).bind(f);
            let rhs = f(5);
            assert_eq!(lhs, rhs);
        }
    
        #[test]
        fn test_monad_right_identity() {
            // right identity: m >>= return = m
            let m = Identity(42);
            let result = m.clone().bind(Identity::of);
            assert_eq!(result, m);
        }
    
        #[test]
        fn test_map_composition_law() {
            // map (f . g) = map f . map g
            let v = Identity(5);
            let f = |x: i32| x + 1;
            let g = |x: i32| x * 2;
            let lhs = v.clone().map(|x| f(g(x)));
            let rhs = v.map(g).map(f);
            assert_eq!(lhs, rhs);
        }
    }

    Exercises

  • Verify all three monad laws with assert_eq! tests using concrete values.
  • Implement Applicative (ap) for Identity: ap(Identity(f), Identity(x)) = Identity(f(x)).
  • Define join: Identity<Identity<A>> -> Identity<A> and show it equals |m| m.bind(|x| x).
  • Implement a State monad and confirm that StateT<Identity> reduces to plain State.
  • Write a pipeline that uses bind to sequence five transformations and compare to a direct function composition using |> or method chaining.
  • Open Source Repos