# How to Automatically Implement Functions for the Reader Monad Using CurryHoward

> Automatically implement Reader monad functions like point map and flatMap in Scala using CurryHoward's implement macro Save time and effort by generating code from type signatures alone

- Repository: [Chymyst/curryhoward](https://github.com/chymyst/curryhoward)
- Tags: how-to-guide
- Published: 2026-02-27

---

**CurryHoward’s `implement` macro synthesizes fully working Scala functions from type signatures alone, allowing you to obtain Reader monad operations like `point`, `map`, and `flatMap` without writing any implementation code.**

To automatically implement functions for the Reader monad using CurryHoward, you define the Reader type as a simple function `E => A` and use the `implement` macro in place of method bodies. The macro, located in [`src/main/scala/io/chymyst/ch/package.scala`](https://github.com/chymyst/curryhoward/blob/main/src/main/scala/io/chymyst/ch/package.scala), inspects the left-hand side of your definition, constructs a type expression, and invokes an automated theorem prover to generate the corresponding lambda term.

## Understanding the Reader Monad Structure

The Reader monad represents computations that depend on a shared environment. In Scala, it is naturally expressed as a function type from some environment `E` to a result `A`.

In the CurryHoward test suite, the Reader is defined as `type Reader[A] = Int ⇒ A` in [`src/test/scala/io/chymyst/ch/unit/LawsSpec.scala`](https://github.com/chymyst/curryhoward/blob/main/src/test/scala/io/chymyst/ch/unit/LawsSpec.scala) at line 26. This type alias serves as the foundation for generating the three core monadic operations: `point` (also called `pure` or `return`), `map` (functor), and `flatMap` (monad bind).

## How the `implement` Macro Synthesizes Code

The automatic implementation process follows a pipeline from type signature to executable Scala AST. Understanding these internals helps debug compilation errors and verify that generated code satisfies the expected laws.

### Macro Entry Point and Type Inspection

The user-facing API is the `implement` macro, defined at lines 27-29 of [`src/main/scala/io/chymyst/ch/package.scala`](https://github.com/chymyst/curryhoward/blob/main/src/main/scala/io/chymyst/ch/package.scala). This zero-argument macro immediately forwards to `Macros.inhabitImpl[U]`, where `U` represents the return type inferred from the left-hand side of the definition.

The macro captures the lexical scope, including local `val`s and method parameters, making them available as premises to the theorem prover.

### Building Type Expressions from Scala Types

Before proving, the macro must translate Scala's `c.Type` into CurryHoward's internal `TypeExpr` representation. This occurs in `Macros.buildTypeExpr` at lines 85-90 of [`src/main/scala/io/chymyst/ch/Macros.scala`](https://github.com/chymyst/curryhoward/blob/main/src/main/scala/io/chymyst/ch/Macros.scala).

For the Reader monad, the function arrow `=>` becomes a `ConjunctT … #-> …` node, representing implication in the logic. This transformation allows the prover to treat function arguments as hypotheses and the return type as the goal.

### Theorem Proving and Term Generation

The search for an implementation happens in `Macros.inhabitImpl` (lines 57-74 of [`src/main/scala/io/chymyst/ch/Macros.scala`](https://github.com/chymyst/curryhoward/blob/main/src/main/scala/io/chymyst/ch/Macros.scala)). This method:

1. Collects all symbols in scope (including class members and local definitions).
2. Constructs a "type structure" representing the entire function signature.
3. Invokes `inhabitOneInternal`, which delegates to `TheoremProver.inhabitInternal` (lines 35-44) to search for a proof term with minimal information loss.

The theorem prover performs a constructive proof search, ensuring that the generated term is the most direct implementation possible given the available premises.

### Emitting Scala ASTs

Once a proof term (`TermExpr`) is found, `Macros.returnTerm` converts it back into a Scala AST (`c.Tree`) using `emitTermCode`. For ordinary functions, this produces a lambda expression; for higher-arity functions, it may wrap the result in a `FunctionNLambda` to preserve the original lambda structure (lines 58-70 of [`src/main/scala/io/chymyst/ch/Macros.scala`](https://github.com/chymyst/curryhoward/blob/main/src/main/scala/io/chymyst/ch/Macros.scala)).

The resulting code is then inlined at the call site, giving you a zero-overhead abstraction with no runtime reflection.

## Automatically Implementing Reader Monad Functions

With the macro machinery understood, you can define the complete Reader monad instance using only type signatures. The following example mirrors the implementation verified in [`src/test/scala/io/chymyst/ch/unit/LawsSpec.scala`](https://github.com/chymyst/curryhoward/blob/main/src/test/scala/io/chymyst/ch/unit/LawsSpec.scala) at lines 14-33.

```scala
import io.chymyst.ch._

// Define the Reader type as a function from environment E to value A
type Reader[E, A] = E => A

// 1. Point (pure) - lifts a value into the Reader context
def pointReader[E, A]: A => Reader[E, A] = implement

// 2. Map (functor) - transforms the result value while keeping the environment
def mapReader[E, A, B]: Reader[E, A] => (A => B) => Reader[E, B] = implement

// 3. FlatMap (monad) - sequences readers, passing the environment through both
def flatMapReader[E, A, B]: Reader[E, A] => (A => Reader[E, B]) => Reader[E, B] = implement

```

When compiled, the macro expands these definitions into the standard Reader monad implementations:

- `pointReader` returns a function that ignores the environment and returns the original value.
- `mapReader` composes the reader with a transformation function.
- `flatMapReader` passes the environment to the first reader, uses its result to determine the second reader, and applies the environment to that second reader.

## Verifying Monad Laws with Generated Code

The CurryHoward test suite confirms that these macro-generated functions satisfy the monad laws. In [`src/test/scala/io/chymyst/ch/unit/LawsSpec.scala`](https://github.com/chymyst/curryhoward/blob/main/src/test/scala/io/chymyst/ch/unit/LawsSpec.scala), the generated `pointReader`, `mapReader`, and `flatMapReader` are tested against the functor and monad laws using ScalaCheck-style property tests.

Because the theorem prover constructs terms with minimal information loss, the generated implementations are guaranteed to be the canonical ones that satisfy the type signatures. For the Reader monad, this means the macro produces exactly the lawful implementations you would write by hand, ensuring associativity, left identity, and right identity hold for `flatMapReader` with `pointReader`.

## Summary

- **CurryHoward’s `implement` macro** synthesizes Scala code from types alone by treating function signatures as logical propositions and constructing proof terms via `TheoremProver.inhabitInternal`.
- **Reader monad functions**—`point`, `map`, and `flatMap`—can be fully implemented using only type signatures and the `implement` macro, as demonstrated in [`src/test/scala/io/chymyst/ch/unit/LawsSpec.scala`](https://github.com/chymyst/curryhoward/blob/main/src/test/scala/io/chymyst/ch/unit/LawsSpec.scala).
- **The implementation pipeline** involves type expression building in `Macros.buildTypeExpr`, proof search in `Macros.inhabitImpl`, and code emission via `emitTermCode` in `Macros.returnTerm`.
- **Generated code is lawful**: The theorem prover’s minimization strategy ensures the resulting Reader monad instances satisfy functor and monad laws without manual verification.

## Frequently Asked Questions

### Can CurryHoward generate Reader monad instances for any environment type?

Yes, the macro is generic over the environment type `E`. In [`src/test/scala/io/chymyst/ch/unit/LawsSpec.scala`](https://github.com/chymyst/curryhoward/blob/main/src/test/scala/io/chymyst/ch/unit/LawsSpec.scala), the tests use `Int` as the environment, but you can define `type Reader[E, A] = E => A` for any `E`. The theorem prover treats the environment as an implicit hypothesis available to the proof term, regardless of its specific type.

### How does the macro handle higher-kinded types like Reader?

CurryHoward operates on the fully resolved type representation after Scala’s type checker has applied all higher-kinded type constructors. When you write `Reader[E, A] => (A => B) => Reader[E, B]`, the macro sees the underlying function type `(E => A) => (A => B) => (E => B)`. It then builds the corresponding `TypeExpr` with implication nodes (`#->`) and searches for a proof, effectively handling the higher-kinded structure by working with its concrete representation.

### Is the generated Reader monad code efficient?

Yes, the generated code is a zero-overhead abstraction. The macro expands into standard Scala lambda expressions at compile time, as seen in `Macros.returnTerm` and `emitTermCode`. There is no runtime reflection or intermediate data structure overhead. The resulting bytecode is identical to what you would write manually: simple function composition for `map` and environment threading for `flatMap`.

### What happens if the type signature is ambiguous or uninhabited?

If the theorem prover cannot construct a proof term for the given type signature, compilation fails with an error indicating that no implementation could be found. This occurs in `TheoremProver.inhabitInternal` when the search space is exhausted without finding a valid term. For the Reader monad, this protects you from defining nonsensical operations like `Reader[E, A] => (B => A) => Reader[E, B]` where the types don't align for a lawful transformation.