# Does CurryHoward Support Type Aliases and Parametric Polymorphism?

> Discover if CurryHoward supports type aliases and parametric polymorphism. Learn how its Scala macro system handles type aliasing and type parameters for robust code.

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

---

**Yes, CurryHoward fully supports both type aliases and parametric polymorphism through its Scala macro system, which automatically dealsias types and represents type parameters as `TP` nodes in its internal `TypeExpr` AST.**

The CurryHoward library for Scala enables automatic implementation of types via the Curry-Howard correspondence. A common question among developers working with generic code is whether the library handles **type aliases** and **parametric polymorphism**. According to the source code in `chymyst/curryhoward`, the macro expansion system explicitly dealsias types and constructs a parametric AST using the `TP` case class, enabling seamless support for both features.

## How CurryHoward Handles Type Aliases

The macro responsible for converting Scala types into the library's internal representation explicitly resolves type aliases before processing. In [`src/main/scala/io/chymyst/ch/Macros.scala`](https://github.com/chymyst/curryhoward/blob/main/src/main/scala/io/chymyst/ch/Macros.scala), the implementation calls `dealias` on the given type:

```scala
// Lines 65-67 in Macros.scala
val finalType = givenType.dealias

```

This ensures that any type alias—whether simple or parameterized—is expanded to its underlying concrete type before the library constructs the `TypeExpr` AST. Consequently, using `typeExpr[MyAlias]` produces the same internal representation as using the aliased type directly.

### Practical Example with Type Aliases

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

type MyEither[A, B] = Either[A, B]

// The macro automatically expands MyEither to Either
val ty = typeExpr[MyEither[Int, String]]
println(ty.prettyPrint)  // Output: <tc>Either[Int,String]

```

The `dealias` operation ensures that the theorem prover works with the canonical type representation, eliminating any distinction between aliases and their targets.

## Parametric Polymorphism and the `TP` AST Node

CurryHoward represents type parameters using the `TP` case class defined in [`src/main/scala/io/chymyst/ch/TypeExpr.scala`](https://github.com/chymyst/curryhoward/blob/main/src/main/scala/io/chymyst/ch/TypeExpr.scala):

```scala
// Lines 89-91 in TypeExpr.scala
final case class TP(name: String) extends TypeExpr with AtomicTypeExpr

```

When the macro encounters a generic type, it creates `TP` nodes for each type parameter. These nodes participate in the full unification and substitution pipeline, enabling the library to reason about polymorphic types.

### Unification and Substitution Logic

The library implements unification for parametric types through methods like `leftUnifyRec` (lines 332-356 in [`TypeExpr.scala`](https://github.com/chymyst/curryhoward/blob/main/TypeExpr.scala)). These methods handle `TP` nodes during type inference, allowing the theorem prover to:

- Substitute concrete types for type variables via `substTypeVar`
- Match generic constructors against concrete instances
- Generate implementations for polymorphic signatures like `def foo[F[_], A]: F[A]`

### Working with Generic Case Classes

```scala
case class Box[T](value: T)

// Generate an implementation for Box[Int] => Int
val impl = ofType[Box[Int] => Int]
println(impl)  
// Result: (b: Box[Int]) => b.value

```

Here, the macro identifies `Box[Int]` as a `NamedConjunctT` with type parameter `TP("T")` substituted by `BasicT("Int")`. The theorem prover solves the implication and emits the accessor code.

## Higher-Kinded Types and Type Constructors

CurryHoward extends its polymorphic support to higher-kinded types (type constructors). When encountering a type like `F[_]`, the macro treats the unknown constructor as atomic but preserves the `TP` structure for the type argument, enabling limited but effective reasoning about generic contexts.

```scala
def lift[F[_], A](fa: F[A]): F[Option[A]] = 
  implement[fa.type => F[Option[A]]]

```

While the library treats `F` as a `ConstructorT` without knowledge of its specific structure, the `TP` placeholder allows the unifier to treat the type parametrically, often synthesizing identity-like implementations that pass the generic structure through unchanged.

## Summary

CurryHoward provides comprehensive support for both type aliases and parametric polymorphism through its macro-based architecture:

- **Type aliases** are automatically resolved via `dealias` in [`Macros.scala`](https://github.com/chymyst/curryhoward/blob/main/Macros.scala) before AST construction, ensuring seamless use of aliased types.
- **Parametric polymorphism** is implemented through the `TP` case class in [`TypeExpr.scala`](https://github.com/chymyst/curryhoward/blob/main/TypeExpr.scala), which integrates with unification and substitution algorithms to handle generic types.
- **Higher-kinded types** receive partial support through parametric placeholders, enabling generic programming patterns with type constructors.

## Frequently Asked Questions

### Does CurryHoward expand recursive type aliases?

Yes. Because the macro calls `dealias` on the input type, recursive aliases are expanded to their underlying recursive structure. The library then processes the resulting type according to its standard rules for recursive types and case classes.

### Can CurryHoward generate implementations for methods with multiple type parameters?

Yes. The `TP` representation handles each type parameter independently. When using `implement` or `ofType` with signatures like `def process[A, B, C]: (A, B) => C`, the macro creates separate `TP` nodes for `A`, `B`, and `C`, allowing the theorem prover to find valid implementations across multiple generic parameters.

### How does CurryHoward handle variance annotations on type parameters?

The library reflects on the erased type structure after `dealias`, which preserves variance information in the type signature. However, the internal `TypeExpr` AST (including `TP` nodes) focuses on structural typing for theorem proving rather than variance-specific subtyping. The generated code respects Scala's variance rules because it emits standard Scala syntax that the compiler then checks for variance correctness.

### Is there a performance penalty for using type aliases with CurryHoward?

No. The `dealias` operation occurs at compile time during macro expansion in [`Macros.scala`](https://github.com/chymyst/curryhoward/blob/main/Macros.scala). By the time the code is generated, all aliases have been replaced with their underlying types, resulting in zero runtime overhead compared to using the original types directly.