Domain values
UserId / PersonName / Age / User
|
| smart constructors / validation
v
Data / ADT layer
Option / Either / Validated / NonEmptyList
|
| described by external instances
v
Typeclasses
Show / Eq / Ord / Semigroup / Monoid
|
v
Instances + syntax helpers
|
v
Laws and property tests (test-only)
corecontains basic typeclass contracts.algebracontains algebraic contracts.datacontains immutable ADTs.domaindemonstrates invariant-safe domain modeling.instancesderives behavior externally from data types.syntaxcontains generic helper functions.- test-only
lawscontains reusable executable laws.
List<E> + runtime non-empty check (0.4.0)
|
v
NonEmptyList<E> encoded invariant (0.4.1)
This removes one invalid representable state from Invalid<E,A>.
raw fields
|
+--> UserId.from ------> Either<ValidationError,UserId>
+--> PersonName.from --> Either<ValidationError,PersonName>
`--> Age.from ---------> Either<ValidationError,Age>
|
v
UserValidator
|
v
Validated<ValidationError,User>
The accumulation in UserValidator is intentionally concrete. A generic solution will be introduced with Applicative.
Domain examples depend on ADTs. ADTs do not depend on domain classes. Typeclasses do not depend on either domain examples or specific instances.
This preserves DIP and keeps the educational abstractions reusable.
Milestone 0.5 adds a small type-level layer without changing the runtime representation of the ADTs.
Kind<F,A>
▲
┌────────────────┼─────────────────┐
│ │ │
│ │ │
Option<A> Either<L,A> Validated<E,A>
│ │ │
│ │ │
OptionK EitherK<L> ValidatedK<E>
Conceptually:
Option<A> ≈ Kind<OptionK, A>
Either<L,A> ≈ Kind<EitherK<L>, A>
Validated<E,A> ≈ Kind<ValidatedK<E>, A>
Java erasure means the compiler cannot reconstruct a concrete ADT from Kind<F,A> purely from the witness parameter. The unavoidable casts are therefore centralized in:
OptionKinds.narrow
EitherKinds.narrow
ValidatedKinds.narrow
This is an explicit architectural boundary: future higher-order typeclass implementations may call those helpers, but should not introduce additional HKT casts.
higher-order typeclasses (0.6+)
│
▼
Kind<F,A>
▲
│
concrete ADTs + witnesses
Kind depends on no ADT. Concrete ADTs opt into the encoding. Future generic abstractions can therefore depend on Kind rather than concrete data types.