Profunctorial
Data
by Oleg Nizhnikov
from

Trees
(1 + x) < 4 AND y == 6Syntax 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): BRepresentation
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 RepresentableRepresentable 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 = fRepresentable 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]): Renum 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): Btrait Repr[F[_]]:
  def apply[B](fb: F[B]): BA => 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]): RNon-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]): RContravariance
trait Repr[F[_]]:
  def apply[B](fb: F[B]): BContravariance
trait Repr[-F[_]]:
  def apply[B](fb: F[B]): BContravariance
trait OfNotFound[R]:
  def notFound(id: String): Rcase class NotFound(id: String)trait OfAlreadyExists[R]:
  def alreadyExists(id: String): Rcase class AlreadyExists(id String)
trait `OfNotFound & OfAlreadyExits`[R]:
  def notFound(id: String): R
  def alreadyExists(id: String): Renum `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): Aenum 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): Aenum 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): Aenum 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): AExtensibility
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))).valueFixpoint
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))).valueTree 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] = exprInstances
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]): RVariant
Di
trait FromUser[-I, +O]:
  def anonymous: O
  def authorized(name: String, email: String, friends: Vector[I]): O
  def admin(key: Seq[Byte]): OVariant
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]): Atrait 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]): Oenum 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]): BInstances
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): Otrait Numbers[-I, +O] 
  derives ProTraverseRep:
  def fromInt(x: Int): O
  def plus(x: I, y: I): O
  def multiply(x: I, y: I): Otrait Comparison[-I, +O] 
  derives ProTraverseRep:
  def less(x: I, y: I): O
  def equals(x: I, y: I): OExtensibility
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] = exprOpen 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,629
 
   
  