Profunctorial
Data
by Oleg Nizhnikov
from
Trees
(1 + x) < 4 AND y == 6
Syntax Trees
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)
Abstract Syntax Trees
Modularity
Order
Database
Customer
Product
Cart
RPC Client
Message Broker
Network
Concurrent Framework
Equivalence
Equivalence
B
A
to
from
to(from(b)) = b
from(to(a)) = a
Equivalence
Vector[A]
List[A]
.toVector
.toList
v.toList.toVector == v
l.toVector.toList == l
Equivalence
Boolean => A
(A, A)
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))
Equivalence
() => A
A
capture
eval
def capture[A](a: A) = () => a
def eval[A](t: () => A) = t()
Equivalence
A
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
Representation
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
Representable Functor
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
Representable Function
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))
Representable Tuple
enum User:
case Anonymous
case Authorized(name: String, email: String)
case Admin(key: Seq[Byte])
Data
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])
Representable Data
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))
Representable Data
Repr
trait Lazy[A]:
def use[B](f: A => B): B
trait Repr[F[_]]:
def apply[B](fb: F[B]): B
A => B
F[B]
Repr[F]
A
trait Representable[F[_]] extends Functor[F]:
def tabulate[A](f: Repr[F] => A): F[A]
Representable Functor
def index[F[_], A](f: F[A]): Repr[F] => A = _(f)
Representable Data
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
Non-representable non-functor
enum User:
case Anonymous
case Authorized(name: String, email: String, friends: List[User])
case Admin(key: Seq[Byte])
Repr[FromUser] ~ User
Non-representable non-functor
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)
})
-
Church
-
Boehm-Berarducci
-
Tagless-final
Encoding names
enum Bool:
case False, True
trait FromBool[A]:
def False: A
def True: A
-
Church
-
Boehm-Berarducci
-
Tagless-final
Encoding names
enum Nat:
case Zero
case Suc(prev: Nat)
trait FromNat[A]:
def Zero: A
def Suc(prev: A): A
-
Church
-
Boehm-Berarducci
-
Tagless-final
Encoding names
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
-
Church
-
Boehm-Berarducci
-
Tagless-final
Encoding names
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
Contravariance
trait Repr[F[_]]:
def apply[B](fb: F[B]): B
Contravariance
trait Repr[-F[_]]:
def apply[B](fb: F[B]): B
Contravariance
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)
for non-recursive F[_] and G[_]
Repr[F & G] = Repr[F] | Repr[G]
Intersection
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)
Intersection
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
Extensibility
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>
Extensibility
val expr1: Repr[OfNumbers && OfComparison && OfBools] = expr
Construction
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)) }
Matching Problem
trait FromNat[A]:
def Zero: A
def Suc(prev: A): A
def prev(n: Repr[FromNat]): Repr[FromNat] = ???
Matching Problem
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
Recursion
Fixpoint
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
Fixpoint
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
Tree Nodes
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)
Fixpoint
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
Instances
summon[Traverse[Numbers || Comparison || Bools]](using ???)
Handling
def handing(x: Int): Int =
try {
2 / x + handing(x - 1)
} catch {
case _: ArithmeticException => 0
}
Handling
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]
Handling
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)))
Profunctorial
In
trait FromUser[R]:
def anonymous: R
def authorized(name: String, email: String, friends: Vector[R]): R
def admin(key: Seq[Byte]): R
Variant
Di
trait FromUser[-I, +O]:
def anonymous: O
def authorized(name: String, email: String, friends: Vector[I]): O
def admin(key: Seq[Byte]): O
Variant
enum UserF[+A]:
case Anonymous
case Authorized(name: String, email: String, friends: Vector[A])
case Admin(key: Seq[Byte])
FromUser[I, O]
UserF[I] => O
Layer
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
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]
~
Instances
for some F[_]
-
P[A, B] is equivalent to F[A] => B
-
F[_] is Functor
-
F[_] is Traversable
Instances
P[A, B] is equivalent to F[A] => B
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
Instances
P[A, B] is equivalent to 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]
Instances
F[_] is a Functor
trait ProLeftMap[P[_, _]]:
def leftMap[A, B, L](pab: P[A, B])(f: L => A): P[L, B]
Instances
F[_] is Traversable
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
Instances
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]]
-
P[A, B] is equivalent to ProRep[P, A] => B
-
ProRep[P, _] is Functor
-
ProRep[P, _] is Traversable
Instances
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)
Generalized Recursion
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) })
Extensibility
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
Extensibility
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
Open Questions
- How to combine traverse instances
- How to partially handle effects
- What to do with GADT
Profunctorial Effects
Script of Types
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)
Script of Mergeable Types
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]
Script of Mergeable Types
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])
Extensibility
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]
Extensibility
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]
}
Profunctorial Effects
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]
Profunctorial Effects
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
Profunctorial Effects
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]]
Profunctorial Effects
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]
Profunctorial Handlers
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]
Elimination
Order
Customer
Product
Cart
Elimination
Order
Database
Customer
Product
Cart
RPC Client
Message Broker
Elimination
Order
Database
Customer
Product
Cart
RPC Client
Message Broker
Network
Concurrent Framework
Elimination
Order
Database
Customer
Product
Cart
RPC Client
Message Broker
Network
Concurrent Framework
Elimination
Network
Concurrent Framework
Higher Kinds
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]
Indexed Church Encoding
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]
Indexed Initial Fixpoint
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]
Indexed Profunctorial Modules
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]]]
Indexed Profunctorial Typeclasses
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)))
Indexed Profunctorial Encoding
Thank you!
Question time!
telegram: @odomontois
twitter: @odomontois
profdata
By Oleg Nizhnik
profdata
- 1,249