by Oleg Nizhnikov
(1 + x) < 4 AND y == 6
AND(
LESS(
PLUS(
LITERAL(1),
VARIABLE(x)
)
),
EQUALS(
VARIABLE(Y),
LITERAL(6)
)
)
enum Lang:
case Universe(options: TypeOptions)
case Record(name: RecordKey, typ: Lang, options: TypeOptions)
case Extend(base: Lang, deps: Lang)
case Function(domain: Lang, effect: Lang, body: Lang)
case Builtin(bt: BuiltinType)
case GetKey(key: RecordKey, up: Int)
case Unit
case Id
case Set(key: RecordKey, term: Lang)
case Merge(base: Lang, deps: Lang)
case Narrow(term: Lang, typ: Lang)
case AndThen(left: Lang, right: Lang)
case Capture(domain: Lang, body: Lang)
case Apply
case External(ref: LibRef)
case Str(value: String)
case Float(value: Double)
case Integer(value: BigInt)
case Bool(value: Boolean)
Order
Database
Customer
Product
Cart
RPC Client
Message Broker
Network
Concurrent Framework
to
from
to(from(b)) = b
from(to(a)) = a
.toVector
.toList
v.toList.toVector == v
l.toVector.toList == l
fromTuple
toPair
def fromPair[A](p: (A, A)) = (b: Boolean) => if (b) p._1 else p._2
def toPair[A](f: Boolean => A) = (f(true), f(false))
capture
eval
def capture[A](a: A) = () => a
def eval[A](t: () => A) = t()
toLazy
fromLazy
def toLazy[A](a: A): Lazy[A] = new:
def use[B](f: A => B) = f(a)
def fromLazy[A](l: Lazy[A]): A = l.use(identity)
trait Lazy[A]:
def use[B](f: A => B): B
trait Representable[F[_]] extends Functor[F]:
type Representation
def index[A](f: F[A]): Representation => A
def tabulate[A](f: Representation => A): F[A]
end Representable
given [R]: Representable[[a] =>> R => a] with
type Representation = R
def index[A](fa: R => A): Representation => A = fa
def tabulate[A](f: R => A): R => A = f
given [R]: Representable[[a] =>> (a, a)] with
type Representation = Boolean
def index[A](fa: (A, A)): Boolean => A = if _ then fa._1 else fa._2
def tabulate[A](f: Boolean => A): (A, A) = (f(true), f(false))
enum User:
case Anonymous
case Authorized(name: String, email: String)
case Admin(key: Seq[Byte])
trait FromUser[R]:
def anonymous: R
def authorized(name: String, email: String): R
def admin(key: Seq[Byte]): R
enum User:
case Anonymous
case Authorized(name: String, email: String)
case Admin(key: Seq[Byte])
trait FromUser[R]:
def anonymous: R
def authorized(name: String, email: String): R
def admin(key: Seq[Byte]): R
type User = Rep[FromUser]
given Representable[FromUser] with
type Representation = User
def index[A](fa: FromUser[A]): User => A = _ match
case User.Anonymous => fa.anonymous
case User.Authorized(name, email) => fa.authorized(name, email)
case User.Admin(key) => fa.admin(key)
def tabulate[A](f: User => A): FromUser[A] = new:
def anonymous = f(User.Anonymous)
def authorized(name: String, email: String) = f(User.Authorized(name, email))
def admin(key: Seq[Byte]) = f(User.Admin(key))
trait Lazy[A]:
def use[B](f: A => B): B
trait Repr[F[_]]:
def apply[B](fb: F[B]): B
trait Representable[F[_]] extends Functor[F]:
def tabulate[A](f: Repr[F] => A): F[A]
def index[F[_], A](f: F[A]): Repr[F] => A = _(f)
enum User:
case Anonymous
case Authorized(name: String, email: String)
case Admin(key: Seq[Byte])
trait FromUser[R]:
def anonymous: R
def authorized(name: String, email: String): R
def admin(key: Seq[Byte]): R
Repr[FromUser] ~ User
trait FromUser[R]:
def anonymous: R
def authorized(name: String, email: String, friends: List[R]): R
def admin(key: Seq[Byte]): R
enum User:
case Anonymous
case Authorized(name: String, email: String, friends: List[User])
case Admin(key: Seq[Byte])
Repr[FromUser] ~ User
def toRepr(user: User): Repr[FromUser] = user match
case User.Anonymous =>
new { def apply[B](f: FromUser[B]) = f.anonymous }
case User.Admin(key) =>
new { def apply[B](f: FromUser[B]) = f.admin(key) }
case User.Authorized(name, email, friends) =>
new { def apply[B](f: FromUser[B]) = f.authorized(name, email, friends.map(toRepr(_)(f))) }
def fromRepr(repr: Repr[FromUser]): User = repr(new FromUser[User] {
def anonymous =
User.Anonymous
def admin(key: Seq[Byte]) =
User.Admin(key)
def authorized(name: String, email: String, friends: List[User]): User =
User.Authorized(name, email, friends)
})
enum Bool:
case False, True
trait FromBool[A]:
def False: A
def True: A
enum Nat:
case Zero
case Suc(prev: Nat)
trait FromNat[A]:
def Zero: A
def Suc(prev: A): A
enum List[A]:
case Nil
case Cons(head: A, tail: List[A])
trait FromList[A, B]:
def Nil: B
def Cons(head: A, tail: B): B
enum User:
case Anonymous
case Authorized(
name: String,
email: String,
friends: List[User]
)
case Admin(key: Seq[Byte])
trait FromUser[R]:
def anonymous: R
def authorized(
name: String,
email: String,
friends: List[R]
): R
def admin(key: Seq[Byte]): R
trait Repr[F[_]]:
def apply[B](fb: F[B]): B
trait Repr[-F[_]]:
def apply[B](fb: F[B]): B
trait OfNotFound[R]:
def notFound(id: String): R
case class NotFound(id: String)
trait OfAlreadyExists[R]:
def alreadyExists(id: String): R
case class AlreadyExists(id String)
trait `OfNotFound & OfAlreadyExits`[R]:
def notFound(id: String): R
def alreadyExists(id: String): R
enum `NotFound | AlreadyExists`:
case NotFound(id: String)
case AlreadyExists(id: String)
trait OfBools[A]:
def True: A
def False: A
def Not(x: A): A
def And(x: A, y: A): A
def Or(x: A, y: A): A
enum Bools:
case True
case False
case Not(x: Bools)
case And(x: Bools, y: Bools)
case Or(x: Bools, y: Bools)
trait OfNumbers[A]:
def fromInt(x: Int): A
def plus(x: A, y: A): A
def multiply(x: A, y: A): A
enum Numbers:
case FromInt(x: Int)
case Plus(x: Numbers, y: Numbers)
case Multiply(x: Numbers, y: Numbers)
trait OfComparison[A]:
def less(x: A, y: A): A
def equals(x: A, y: A): A
enum Comparison:
case Less(x: Comparison, y: Comparison)
case Equals(x: Comparison, y: Comparison)
trait `OfBools & OfNumbers & OfComparison`[A]:
def True: A
def False: A
def Not(x: A): A
def And(x: A, y: A): A
def Or(x: A, y: A): A
def fromInt(x: Int): A
def plus(x: Int, y: Int): A
def multiply(x: Int, y: Int): A
def less(x: A, y: A): A
def equals(x: A, y: A): A
enum Expr:
case True
case False
case Not(x: Expr)
case And(x: Expr, y: Expr)
case Or(x: Expr, y: Expr)
case FromInt(x: Int)
case Plus(x: Expr, y: Expr)
case Multiply(x: Expr, y: Expr)
case Less(x: Expr, y: Expr)
case Equals(x: Expr, y: Expr)
val expr: Repr[OfNumbers && OfComparison] = new {
def apply[A](L: OfNumbers[A] & OfComparison[A]) =
L.equals(
L.fromInt(4),
L.plus(
L.fromInt(1),
L.fromInt(3)
)
)
}
<expr xmlns:n="lambda::days::numbers"
xmlns:c="lambda::days::comparison">
<c:equals>
<n:fromInt>4</n:fromInt>
<n:plus>
<n:fromInt>1</n:fromInt>
<n:fromInt>3</n:fromInt>
</n:plus>
</c:equals>
</expr>
val expr1: Repr[OfNumbers && OfComparison && OfBools] = expr
trait FromNat[A]:
def Zero: A
def Suc(prev: A): A
object FromNat extends FromNat[Repr[FromNat]]:
def Zero: Repr[FromNat] =
new { def apply[A](f: FromNat[A]) = f.Zero }
def Suc(prev: Repr[FromNat]): Repr[FromNat] =
new { def apply[A](f: FromNat[A]) = f.Suc(prev(f)) }
trait FromNat[A]:
def Zero: A
def Suc(prev: A): A
def prev(n: Repr[FromNat]): Repr[FromNat] = ???
trait FromNat[A]:
def Zero: A
def Suc(prev: A): A
def prev(n: Repr[FromNat]): Repr[FromNat] =
n(new FromNat[(Repr[FromNat], Repr[FromNat])] {
def Zero: (Repr[FromNat], Repr[FromNat]) =
(FromNat.Zero, FromNat.Zero)
def Suc(prev: (Repr[FromNat], Repr[FromNat])) =
(prev._2, FromNat.Suc(prev._1))
})._1
final case class Fix[F[_]](value: F[Fix[F]]):
def fold[A](f: F[A] => A)(using Functor[F]): A = f(value.map(_.fold(f)))
def foldEval[A](f: F[A] => Eval[A])(using Traverse[F]): Eval[A] =
value.traverse(_.foldEval(f)).flatMap(f)
def foldTail[A](f: F[A] => A)(using Traverse[F]): A =
foldEval[A](fx => Eval.later(f(fx))).value
object Fix:
def unfold[F[_]: Functor, A](init: A)(f: A => F[A]): Fix[F] =
Fix(f(init).map(Fix.unfold(_)(f)))
def unfoldEval[F[_]: Traverse, A](init: A)(f: A => Eval[F[A]]): Eval[Fix[F]] =
f(init).flatMap(_.traverse(Fix.unfoldEval(_)(f))).map(Fix(_)).defer
def unfoldTail[F[_]: Traverse, A](init: A)(f: A => F[A]): Fix[F] =
unfoldEval(init)(a => Eval.later(f(a))).value
final case class Fix[+F[+_]](value: F[Fix[F]]):
def fold[A, F1[x] >: F[x]: Functor](f: F1[A] => A): A = f(value.map(_.fold(f)))
def foldEval[A, F1[x] >: F[x]: Traverse](f: F1[A] => Eval[A]): Eval[A] =
value.traverse(_.foldEval(f)).flatMap(f).defer
def foldTail[A, F1[x] >: F[x]: Traverse](f: F1[A] => A): A =
foldEval[A, F1](fx => Eval.later(f(fx))).value
object Fix:
def unfold[F[+_]: Functor, A](init: A)(f: A => F[A]): Fix[F] =
Fix(f(init).map(Fix.unfold(_)(f)))
def unfoldEval[F[+_]: Traverse, A](init: A)(f: A => Eval[F[A]]): Eval[Fix[F]] =
f(init).flatMap(_.traverse(Fix.unfoldEval(_)(f))).map(Fix(_)).defer
def unfoldTail[F[+_]: Traverse, A](init: A)(f: A => F[A]): Fix[F] =
unfoldEval(init)(a => Eval.later(f(a))).value
enum Bools[+A] derives Traverse:
case True
case False
case Not(x: A)
case And(x: A, y: A)
case Or(x: A, y: A)
enum Numbers[+A] derives Traverse:
case FromInt(x: Int)
case Plus(x: A, y: A)
case Multiply(x: A, y: A)
enum Comparison[+A] derives Traverse:
case Less(x: A, y: A)
case Equals(x: A, y: A)
val expr: Fix[Numbers || Comparison] =
Fix(Comparison.Equals(
Fix(Numbers.FromInt(4)),
Fix(Numbers.Plus(
Fix(Numbers.FromInt(1)),
Fix(Numbers.FromInt(3))
))
))
val expr1: Fix[Numbers || Comparison || Bools] = expr
summon[Traverse[Numbers || Comparison || Bools]](using ???)
def handing(x: Int): Int =
try {
2 / x + handing(x - 1)
} catch {
case _: ArithmeticException => 0
}
def handing(x: Int): Int =
try {
2 / x + handing(x - 1)
} catch {
case _: ArithmeticException => 0
}
def handle[F[+_], H[+_]](
fix: Fix[F || H]
)(
handler: H[Fix[F || H]] => Fix[F]
): Fix[F]
def handle[F[+_], H[+_]](
fix: Fix[F || H]
)(
handler: H[Fix[F || H]] => Fix[F]
)(using
Typeable[H[Fix[F || H]]],
Typeable[F[Fix[F || H]]],
Functor[F]
): Fix[F] =
fix.value match
case h: H[Fix[F || H]] => handler(h)
case f: F[Fix[F || H]] => Fix(f.map(handle(_)(handler)))
trait FromUser[R]:
def anonymous: R
def authorized(name: String, email: String, friends: Vector[R]): R
def admin(key: Seq[Byte]): R
trait FromUser[-I, +O]:
def anonymous: O
def authorized(name: String, email: String, friends: Vector[I]): O
def admin(key: Seq[Byte]): O
enum UserF[+A]:
case Anonymous
case Authorized(name: String, email: String, friends: Vector[A])
case Admin(key: Seq[Byte])
trait Layer[-P[-_, +_]]:
def unwrap[A](f: P[Layer[P], A]): A
trait Wrapped[+F[+_]]:
def patMat[A](f: F[Wrapped[F]] => A): A
F[Wrapped[F]]
Fix[F]
Layer[FromUser]
trait WrappedUser:
def patMat[A](f: UserF[WrappedUser] => A): A
UserF[WrappedUser]
trait FromUser[-I, +O]:
def anonymous: O
def authorized(
name: String,
email: String,
friends: Vector[I]
): O
def admin(key: Seq[Byte]): O
enum UserF[+R]:
case Anonymous
case Authorized(
name: String,
email: String,
friends: Vector[R]
)
case Admin(key: Seq[Byte])
Fix[UserF]
trait ProRepresentable[P[_, _]]:
type F[_]
def tabulate[A, B](f: F[A] => B): P[A, B]
def index[A, B](p: P[A, B])(fa: F[A]): B
trait ProRep[P[_, _], B]:
def apply[A](p: P[A, B]): B
trait ProRepresentable[P[_, _]]:
def tabulate[A, B](f: ProRep[P, A] => B): P[A, B]
trait ProLeftMap[P[_, _]]:
def leftMap[A, B, L](pab: P[A, B])(f: L => A): P[L, B]
trait ProSequence[P[_, _]]:
def sequence[A, B, F[_]: Applicative](pab: P[A, B]): P[F[A], F[B]]
def sequence[A, B, F[_]: Applicative](f: Base[A] => B): Base[F[A]] => F[B]
P[A, B]
Base[A] => B
trait ProTraverseRep[P[_, _]]
extends ProRepresentable[P] with ProLeftMap[P] with ProSequence[P]:
def proTraverse[L, A, B, F[_]: Applicative](
fromRep: ProRep[P, A] => B,
f: L => A
): P[F[L], F[B]]
trait ProTraverseRep[P[_, _]]
extends ProRepresentable[P] with ProLeftMap[P] with ProSequence[P]:
def proTraverse[L, A, B, F[_]](
fromRep: ProRep[P, A] => B,
f: L => A
): P[F[L], F[B]]
override def leftMap[A, B, L](pab: P[A, B])(f: L => A): P[L, B] =
proTraverse[L, A, B, [x] =>> x](_(pab), f)
override def sequence[A, B, F[_]: Applicative](pab: P[A, B]): P[F[A], F[B]] =
proTraverse[A, A, B, F](_(pab), identity)
override def tabulate[A, B](f: ProRep[P, A] => B): P[A, B] =
proTraverse[A, A, B, [x] =>> x](f, identity)
trait Layer[-P[-_, +_]]:
def unwrap[A](f: P[Layer[P], A]): A
def fold[A, P1[x, y] <: P[x, y]](f: P1[A, A])(using ProLeftMap[P1]): A =
unwrap(f.lmap[Layer[P]](_.fold(f)))
def foldEval[A, P1[x, y] <: P[x, y]](f: P1[Eval[A], Eval[A]])(using ProLeftMap[P1]): Eval[A] =
unwrap(f.lmap(_.foldEval(f))).defer
def foldTail[A, P1[x, y] <: P[x, y]](f: P1[A, A])(using ProTraverseRep[P1]): A =
foldEval(f.seq[Eval]).value
object Layer:
def unfold[A, P[-_, +_]](ca: Coalgebra[P, A])(init: A)(using ProLeftMap[P]): Layer[P] =
new:
def unwrap[X](f: P[Layer[P], X]): X =
ca(init, f.lmap[A](Layer.unfold(ca)))
def apply[P[-_, +_], Q[-i, +o] <: P[i, o]](using P: ProTraverseRep[P]): P[Layer[Q], Layer[Q]] =
P.tabulate(rep => new { def unwrap[A](pla: Q[Layer[Q], A]) = rep(pla) })
trait Bools[-I, +O]
derives ProTraverseRep:
def True: O
def False: O
def Not(x: I): O
def And(x: I, y: I): O
def Or(x: I, y: I): O
trait Numbers[-I, +O]
derives ProTraverseRep:
def fromInt(x: Int): O
def plus(x: I, y: I): O
def multiply(x: I, y: I): O
trait Comparison[-I, +O]
derives ProTraverseRep:
def less(x: I, y: I): O
def equals(x: I, y: I): O
type L[-i, +o] = (Numbers &&& Comparison)[i, o]
val expr: Layer[L] =
Layer[Comparison, L].equals(
Layer[Numbers, L].fromInt(4),
Layer[Numbers, L].plus(
Layer[Numbers, L].fromInt(1),
Layer[Numbers, L].fromInt(3)
)
)
type L2[-i, +o] = (Numbers &&& Comparison &&& Bools)[i, o]
val expr1: Layer[L2] = expr
case class Dictionary(selectDynamic: Map[String, Any]) extends Selectable:
def as[T]: Dictionary & T = this.asInstanceOf[Dictionary & T]
type Person = {
val name: String
val age: Int
}
val x = Dictionary(Map("age" -> 87, "name" -> "Aragorn")).as[Person]
println(x.age: Int)
println(x.name: String)
case class Dictionary(selectDynamic: Map[String, Any]) extends Selectable:
type Underlying
def as[T]: Dictionary & T { type Underlying <: T } =
this.asInstanceOf[Dictionary & T & { type Underlying <: T }]
def merge[Q](other: Dictionary & Q) =
Dictionary(selectDynamic ++ other.selectDynamic).as[Underlying & Q]
type Person = {
val name: String
val age: Int
}
val x = Dictionary(Map("age" -> 87, "name" -> "Aragorn")).as[Person]
type Friendly = {
val friends: List[String]
}
val y = Dictionary(Map("friends" -> List("Frodo", "Legolas", "Gimli"))).as[Friendly]
val z = x merge y
println(z.age: Int)
println(z.name: String)
println(z.friends: List[String])
case class Pro[P[-_, +_], -I, +O](p: P[I, O], instance: ProTraverseRep[P])
case class Multi[-I, +O](pros: Map[String, Pro[?, I, O]]) extends Selectable:
def selectDynamic(name: String): Pro[?, I, O] = pros(name)
type &&&[P[-_, +_], Q[-_, +_]] = [a, b] =>> P[a, b] & Q[a, b]
trait OfBool[-I, +O]
derives ProTraverseRep:
def True: O
def False: O
def Not(x: I): O
def And(x: I, y: I): O
def Or(x: I, y: I): O
type Bools[-I, +O] =
Multi[I, O] & {
val bools: Pro[OfBool, I, O]
}
trait OfNumber[-I, +O]
derives ProTraverseRep:
def fromInt(x: Int): O
def plus(x: I, y: I): O
def multiply(x: I, y: I): O
type Numbers[-I, +O] =
Multi[I, O] & {
val numbers: Pro[OfNumber, I, O]
}
trait OfCompare[-I, +O]
derives ProTraverseRep:
def less(x: I, y: I): O
def equals(x: I, y: I): O
type Compare[-I, +O] =
Multi[I, O] & {
val comparison: OfCompare[I, O]
}
case class Pro[P[-_, +_], -I, +O](p: P[I, O], instance: ProTraverseRep[P])
case class Multi[-I, +O](pros: Map[String, Pro[?, I, O]]) extends Selectable:
def selectDynamic(name: String): Pro[?, I, O] = pros(name)
type &&&[P[-_, +_], Q[-_, +_]] = [a, b] =>> P[a, b] & Q[a, b]
case class Pro[P[-_, +_], -I, +O](p: P[I, O], instance: ProTraverseRep[P])
case class Multi[-I, +O](pros: Map[String, Pro[?, I, O]]) extends Selectable:
def selectDynamic(name: String): Pro[?, I, O] = pros(name)
type &&&[P[-_, +_], Q[-_, +_]] = [a, b] =>> P[a, b] & Q[a, b]
trait Layer[-P[-_, +_]]:
def unwrap[O](p: P[ProData[P], O]): O
case class Pro[P[-_, +_], -I, +O](p: P[I, O], instance: ProTraverseRep[P])
case class Multi[-I, +O](pros: Map[String, Pro[?, I, O]]) extends Selectable:
def selectDynamic(name: String): Pro[?, I, O] = pros(name)
type &&&[P[-_, +_], Q[-_, +_]] = [a, b] =>> P[a, b] & Q[a, b]
trait Layer[-P[-_, +_]]:
def unwrap[O](p: P[ProData[P], O]): O
trait Handler[From[-_, +_], -To[-_, +_]]:
def handle[P[-i, +o]]: From[ProData[P &&& From], ProData[P &&& To]]
case class Pro[P[-_, +_], -I, +O](p: P[I, O], instance: ProTraverseRep[P])
case class Multi[-I, +O](pros: Map[String, Pro[?, I, O]]) extends Selectable:
def selectDynamic(name: String): Pro[?, I, O] = pros(name)
type &&&[P[-_, +_], Q[-_, +_]] = [a, b] =>> P[a, b] & Q[a, b]
trait Layer[-P[-_, +_]]:
def unwrap[O](p: P[ProData[P], O]): O
trait Handler[From[-_, +_], -To[-_, +_]]:
def handle[P[-i, +o]]: From[ProData[P &&& From], ProData[P &&& To]]
enum ProData[-P[-_, +_]]:
case Construct(layer: Layer[P])
case Eliminate[-P[-_, +_], Q[-_, +_]](
data: ProData[P &&& Q],
handler: Handler[Q, P]
) extends ProData[P]
trait Handler[From[-_, +_], -To[-_, +_]]:
def handle[P[-i, +o]]: From[ProData[P &&& From], ProData[P &&& To]]
object Handler:
def recursive[From[-i, +o], To[-_, +_]](handler: Handler[From, From &&& To]): Handler[From, To]
Order
Customer
Product
Cart
Order
Database
Customer
Product
Cart
RPC Client
Message Broker
Order
Database
Customer
Product
Cart
RPC Client
Message Broker
Network
Concurrent Framework
Order
Database
Customer
Product
Cart
RPC Client
Message Broker
Network
Concurrent Framework
Network
Concurrent Framework
trait Repr[Alg[f[_]], A]:
def apply[F[_]](alg: Alg[F]): F[A]
trait Bools[F[_]]:
def True: F[Boolean]
def False: F[Boolean]
def Not(x: F[Boolean]): F[Boolean]
def And(x: F[Boolean], y: F[Boolean]): F[Boolean]
def Or(x: F[Boolean], y: F[Boolean]): F[Boolean]
trait Numbers[F[_]]:
def fromInt(x: Int): F[Int]
def plus(x: F[Int], y: F[Int]): F[Int]
def multiply(x: F[Int], y: F[Int]): F[Int]
trait Comparison[F[_]]:
def less(x: F[Int], y: F[Int]): F[Boolean]
def equals(x: F[Int], y: F[Int]): F[Boolean]
trait TraverseHK[Alg[f[_], _]]:
def traverse[A, F[_], X[_], Y[_]](alg: Alg[X, A])(f: [a] => X[a] => F[Y[a]]): Alg[Y, A]
case class Fix[+Alg[+_[_], _], R](alg: Alg[Fix[Alg, *], R])
enum Bools[+F[_], A] derives TraverseHK:
case True extends Bools[Nothing, Boolean]
case False extends Bools[Nothing, Boolean]
case Not[F[_]](x: F[Boolean]) extends Bools[F, Boolean]
case And[F[_]](x: F[Boolean], y: F[Boolean]) extends Bools[F, Boolean]
case Or[F[_]](x: F[Boolean], y: F[Boolean]) extends Bools[F, Boolean]
enum Numbers[+F[_], A] derives TraverseHK:
case FromInt(x: Int) extends Numbers[Nothing, Int]
case Plus(x: F[Int], y: F[Int]) extends Numbers[Nothing, Int]
case Multiply(x: F[Int], y: F[Int]) extends Numbers[Nothing, Int]
enum Comparison[+F[_], A] derives TraverseHK:
case Less(x: F[Int], y: F[Int]) extends Comparison[F, Boolean]
case Equals(x: F[Int], y: F[Int]) extends Comparison[F, Boolean]
trait Bools[-I[_], +O[_]]:
def True: O[Boolean]
def False: O[Boolean]
def Not(x: I[Boolean]): O[Boolean]
def And(x: I[Boolean], y: I[Boolean]): O[Boolean]
def Or(x: I[Boolean], y: I[Boolean]): O[Boolean]
trait Numbers[-I[_], +O[_]]:
def fromInt(x: Int): O[Int]
def plus(x: I[Int], y: I[Int]): O[Int]
def multiply(x: I[Int], y: I[Int]): O[Int]
trait Comparison[-I[_], +O[_]]:
def less(x: I[Int], y: I[Int]): O[Boolean]
def equals(x: I[Int], y: I[Int]): O[Boolean]
trait ProRepHK[P[_[_], _[_]], I[_], A]:
def apply[O[_]](p: P[I, O]): O[A]
trait ProRepresentableHK[P[_[_], _[_]]]:
def tabulate[I[_], O[_]](f: [A] => ProRepHK[P, I, A] => O[A]): P[I, O]
trait ProLeftMapHK[P[_[_], _[_]]]:
def leftMap[I[_], O[_], L[_]](pab: P[I, O])(f: [A] => L[A] => I[A]): P[L, O]
trait ProSequenceHK[P[_[_], _[_]]]:
def sequence[I[_], O[_], F[_]: Applicative](pab: P[I, O]): P[[A] =>> F[I[A]], [A] =>> F[O[A]]]
trait ProTraverseRepHK[P[_[_], _[_]]]
extends ProRepresentableHK[P] with ProLeftMapHK[P] with ProSequenceHK[P]:
def proTraverse[L[_], I[_], O[_], F[_]: Applicative](
fromRep: [A] => ProRepHK[P, I, A] => O[A],
f: [A] => L[A] => I[A]
): P[[A] =>> F[L[A]], [A] =>> F[O[A]]]
trait LayerHK[-P[-_[_], +_[_]], A]:
def unwrap[O[_]](f: P[LayerHK[P, *], O]): O[A]
def fold[R[_], P1[i[_], o[_]] <: P[i, o]](f: P1[R, R])(using ProLeftMapHK[P1]): R[A] =
unwrap(f.lmap[LayerHK[P, *]]([A] => (l: LayerHK[P, A]) => l.fold(f)))
def foldEval[R[_], P1[i[_], o[_]] <: P[i, o]](f: P1[[A] =>> Eval[R[A]], [A] =>> Eval[R[A]]])(using
ProLeftMapHK[P1]
): Eval[R[A]] =
unwrap(f.lmap([A] => (l: LayerHK[P, A]) => l.foldEval(f))).defer
def foldTail[R[_], P1[i[_], o[_]] <: P[i, o]](f: P1[R, R])(using ProTraverseRepHK[P1]): R[A] =
foldEval(f.seq[Eval]).value
end LayerHK
trait CoalgebraHK[P[-_[_], +_[_]], I[_]]:
def apply[O[_], A](a: I[A], p: P[I, O]): O[A]
object LayerHK:
def unfold[I[_], A, P[-_[_], +_[_]]](ca: CoalgebraHK[P, I])(init: I[A])(using
ProLeftMapHK[P]
): LayerHK[P, A] =
new:
def unwrap[O[_]](f: P[LayerHK[P, *], O]): O[A] =
ca(init, f.lmap[I]([B] => (ia: I[B]) => LayerHK.unfold(ca)(ia)))
telegram: @odomontois
twitter: @odomontois