A type class and dependent type based generic programming library for Scala
npx @tessl/cli install tessl/maven-com-chuusai--shapeless_2-12@2.3.0Shapeless is a comprehensive generic programming library for Scala that enables type-safe, compile-time generic programming through type classes and dependent types. It provides powerful abstractions for working with heterogeneous lists, coproducts, generic representations, and automatic derivation of type class instances, allowing developers to eliminate boilerplate code while maintaining full type safety.
libraryDependencies += "com.chuusai" %% "shapeless" % "2.3.13"import shapeless._For specific functionality:
import shapeless.{HList, ::, HNil, Generic, Coproduct, :+:, CNil}
import shapeless.ops.hlist._
import shapeless.ops.coproduct._
import shapeless.syntax.hlist._
import shapeless.syntax.coproduct._
import shapeless.labelled.FieldType
import shapeless.tag.@@Common syntax extensions:
import shapeless.syntax.singleton._ // Narrow type literals
import shapeless.syntax.std.tuple._ // Tuple conversions
import shapeless.syntax.std.function._ // Function conversionsimport shapeless._
// Define a case class
case class Person(name: String, age: Int, active: Boolean)
// Get generic representation
val gen = Generic[Person]
val person = Person("Alice", 30, true)
// Convert to HList
val hlist = gen.to(person) // String :: Int :: Boolean :: HNil
// Access elements by type
val name: String = hlist.select[String]
val age: Int = hlist.select[Int]
// Convert back to case class
val reconstructed = gen.from(hlist)
// Work with heterogeneous lists directly
val mixed: String :: Int :: Boolean :: HNil = "test" :: 42 :: true :: HNil
val length = mixed.length // Nat._3 (compile-time known)
val head = mixed.head // "test"
val tail = mixed.tail // Int :: Boolean :: HNilShapeless is built around several key architectural concepts:
This design enables zero-runtime-cost abstractions and ensures that all type relationships are verified at compile time, making it impossible to access non-existent fields or perform invalid operations.
Essential type operators, constraints, and dependent types that form the foundation of Shapeless. Includes identity types, logical operators, type inequalities, and basic utilities that underpin all other functionality.
type Id[+T] = T
type Const[C] = { type λ[T] = C }
// Type inequalities
trait =:!=[A, B] extends Serializable
trait <:!<[A, B] extends Serializable
// Logical type operators
type ¬[T] = T => Nothing
type ¬¬[T] = ¬[¬[T]]
type ∧[T, U] = T with U
type ∨[T, U] = ¬[¬[T] ∧ ¬[U]]
// Type-lambda helpers for context bounds
type |∨|[T, U] = { type λ[X] = ¬¬[X] <:< (T ∨ U) }
type |¬|[T] = { type λ[U] = U <:!< T }
// Quantifiers
type ∃[P[_]] = P[T] forSome { type T }
type ∀[P[_]] = ¬[∃[({ type λ[X] = ¬[P[X]]})#λ]]
// Dependent function types
trait DepFn0 { type Out; def apply(): Out }
trait DepFn1[T] { type Out; def apply(t: T): Out }
trait DepFn2[T, U] { type Out; def apply(t: T, u: U): Out }
// Macro-based cached implicit resolution
def cachedImplicit[T]: T = macro CachedImplicitMacros.cachedImplicitImpl[T]Core heterogeneous data structures that can contain elements of different types while preserving complete type information at compile time. Provides extensive operations for construction, access, and transformation.
sealed trait HList
final case class ::[+H, +T <: HList](head: H, tail: T) extends HList
sealed trait HNil extends HList
// Construction and access
def apply[T](t: T): T :: HNil
def select[U]: U // Select element by type
def at[N <: Nat]: Out // Access by positionHLists and Heterogeneous Collections
Type-safe sum types representing "one of" relationships, enabling exhaustive pattern matching and safe union operations. The dual concept to HLists for modeling exclusive alternatives.
sealed trait Coproduct
sealed trait :+:[+H, +T <: Coproduct] extends Coproduct
final case class Inl[+H, +T <: Coproduct](head: H) extends (H :+: T)
final case class Inr[+H, +T <: Coproduct](tail: T) extends (H :+: T)
// Injection and selection
def inject[I]: I => Coproduct
def select[T]: Option[T]The core value proposition of Shapeless - automatic derivation of type class instances by converting between user-defined types and generic representations. Eliminates boilerplate code while maintaining type safety.
trait Generic[A] {
type Repr
def to(a: A): Repr
def from(repr: Repr): A
}
trait LabelledGeneric[A] {
type Repr
def to(a: A): Repr // Preserves field names as types
def from(repr: Repr): A
}Generic Programming and Automatic Derivation
Structured data access using field names rather than positions, providing a more user-friendly interface for working with case classes and other product types through symbolic field access.
type FieldType[K, +V] = V @@ KeyTag[K, V]
object field[K] extends FieldOf[K]
def selectDynamic(field: String): FieldType[K, V]
def updatedDynamic[V](field: String, value: V): RecordRecords and Named Field Access
Functional programming patterns for composable data access and transformation. Provides type-safe navigation and modification of nested data structures with automatic derivation.
case class Lens[S, A](get: S => A, set: S => A => S) {
def modify(s: S)(f: A => A): S
}
case class Prism[S, A](get: S => Option[A], set: S => A => S) {
def modifyOption(s: S)(f: A => A): Option[S]
}Advanced type-level computations including polymorphic functions that work across different types, natural transformations, type-level arithmetic with natural numbers, and sophisticated type-level logic.
trait Poly {
def apply[A](a: A)(implicit cse: Case.Aux[this.type, A :: HNil, Out]): Out
}
trait ~>[F[_], G[_]] { // Natural transformation
def apply[A](fa: F[A]): G[A]
}
sealed trait Nat { type N <: Nat }
trait Succ[P <: Nat] extends NatPolymorphic Functions and Type-Level Programming
Specialized features including functional cursors (zippers), tuple operations, compile-time testing utilities, annotation processing, runtime type information, and various conversion utilities for integration with Scala's standard library.
case class Zipper[C, L <: HList](left: L, focus: C, right: L)
def typed[T](t: => T): Unit // Assert expression has type T
def typeError(t: String): Unit // Assert code fails to type check
trait Typeable[T] {
def cast(any: Any): Option[T]
}