SlideShare a Scribd company logo
type Encoder[A] = A => Json
type Decoder[A] = Json => Either[Error, A]
sealed trait SchemaF[A]
sealed trait Employee
final case class Subordinate(
name:String,
age:Int,
boss: Employee
) extends Employee
final case class Boss(
name:String,
isActive:Boolean
) extends Employee
def toEncoder[A](schema:SchemaF[A]):Encoder[A] = ???
SchemaF ~> Encoder
sealed trait MyPrim[A]
final case object IntP extends MyPrim[Int]
final case object StringP extends MyPrim[String]
final case object BooleanP extends MyPrim[Boolean]
sealed trait SchemaF[A]
final case class PrimF[A](prim:MyPrim[A]) extends SchemaF[A]
sealed trait SchemaF[Prim[_], A]
final case class PrimS[Prim[_], A](prim:Prim[A]) extends SchemaF[Prim, A]
//MyPrim[A] => Encoder[A] ---- Prim ~> Encoder
def toPrimEnc[A](prim:MyPrim[A]):Encoder[A] = prim match {
case IntP => (i:Int) => i.toString
case StringP => (s:String) => s""""$s""""
case BooleanP => (b:Boolean) => if (b) "true" else "false"
}
def toEnc[Prim[_], A](schema:SchemaF[Prim, A], toPrimEnc: Prim ~> Encoder):Encoder[A] = schema match
{
case PrimS(p) => toPrimEnc(p)
}
val intSchema:SchemaF[MyPrim, Int] = PrimS(IntP)
val strSchema:SchemaF[MyPrim, String] = PrimS(StringP)
val booleanSchema:SchemaF[MyPrim, Boolean] = PrimS(BooleanP)
val nt: MyPrim ~> Encoder = new NaturalTransformation[MyPrim, Encoder]{
override def apply[A](prim:MyPrim[A]):Encoder[A] = toPrimEnc(prim)
}
val encoder: Encoder[Int] = toEnc(intSchema, nt)
sealed trait SchemaF[Prim[_], A]
final case class PrimS[Prim[_],A](prim:Prim[A]) extends SchemaF[Prim, A]
final case class ProdS[Prim[_],A,B](l:SchemaF[Prim, A], r:SchemaF[Prim, B]) extends SchemaF[Prim, (A,B)]
final case class SumS[Prim[_],A,B](l:SchemaF[Prim, A], r:SchemaF[Prim, B]) extends SchemaF[Prim, A/B]
val productSumSchema:SchemaF[MyPrim, (Int, (String, (Boolean / Int)))] =
ProdS(intSchema, ProdS(strSchema, SumS(booleanSchema, intSchema)))
def toEnc[Prim[_], A](schema:SchemaF[Prim, A], toPrimEnc: Prim ~> Encoder):Encoder[A] = schema match {
case PrimS(p) => toPrimEnc(p)
case prod:ProdS[Prim, x, y] => (tpl:(x,y)) =>
toEnc(prod.l, toPrimEnc)(tpl._1) + "," + toEnc(prod.r, toPrimEnc)(tpl._2)
}
def toEnc[Prim[_], A](schema:SchemaF[Prim, A], toPrimEnc: Prim ~> Encoder):Encoder[A] = schema match {
case PrimS(p) => toPrimEnc(p)
case prod:ProdS[Prim, x, y] => (tpl:(x,y)) =>
toEnc(prod.l, toPrimEnc)(tpl._1) + "," + toEnc(prod.r, toPrimEnc)(tpl._2)
case sum:SumS[Prim, x, y] => (e:x / y) => e.fold(
lx => toEnc(sum.l, toPrimEnc)(lx),
ry => toEnc(sum.r, toPrimEnc)(ry)
)
}
sealed trait SchemaF[Prim[_], A]
final case class PrimS[Prim[_],A](prim:Prim[A]) extends SchemaF[Prim, A]
final case class ProdS[Prim[_],A,B](l:SchemaF[Prim, A], r:SchemaF[Prim, B]) extends SchemaF[Prim, (A,B)]
final case class SumS[Prim[_],A,B](l:SchemaF[Prim, A], r:SchemaF[Prim, B]) extends SchemaF[Prim, A/B]
final case class UnionS[Prim[_],B,A](base:SchemaF[Prim, B], iso:Iso[B,A]) extends SchemaF[Prim, A]
final case class RecordS[Prim[_],B,A](base:SchemaF[Prim, B], iso:Iso[B,A]) extends SchemaF[Prim, A]
final case class IsoS[Prim[_],B,A](base:SchemaF[Prim, B], iso:Iso[B,A]) extends SchemaF[Prim, A]
def toEnc[Prim[_], A](schema:SchemaF[Prim, A], toPrimEnc: Prim ~> Encoder):Encoder[A] = schema match {
case PrimS(p) => toPrimEnc(p)
case prod:ProdS[Prim, x, y] => (tpl:(x,y)) =>
toEnc(prod.l, toPrimEnc)(tpl._1) + "," + toEnc(prod.r, toPrimEnc)(tpl._2)
case sum:SumS[Prim, x, y] => (e:x / y) => e.fold(
lx => toEnc(sum.l, toPrimEnc)(lx),
ry => toEnc(sum.r, toPrimEnc)(ry)
)
case isoS:IsoS[Prim, b, A] => (a:A) =>
toEnc(isoS.base, toPrimEnc)(isoS.iso.reverseGet(a))
case union:UnionS[Prim, b, A] => (a:A) =>
toEnc(union.base, toPrimEnc)(union.iso.reverseGet(a))
case record:RecordS[Prim, b, A] => (a:A) =>
toEnc(record.base, toPrimEnc)(record.iso.reverseGet(a))
}
sealed trait SchemaF[Prim[_], SumTermId, ProductTermId, A]
...
final case class FieldS[Prim[_], SumTermId, ProductTermId, A](
id:ProductTermId,
base:SchemaF[Prim,SumTermId, ProductTermId, A]
) extends SchemaF[Prim, SumTermId, ProductTermId, A]
final case class BranchS[Prim[_], SumTermId, ProductTermId, A](
id:SumTermId,
base:SchemaF[Prim,SumTermId, ProductTermId, A]
) extends SchemaF[Prim, SumTermId, ProductTermId, A]
//Schema[A] => Encoder[A]
def toEnc[Prim[_], SumTermId, ProductTermId, A](
schema:SchemaF[Prim,SumTermId, ProductTermId, A],
toPrimEnc: Prim ~> Encoder,
sidToString: SumTermId => String,
pidToString: ProductTermId => String
):Encoder[A] = schema match {
...
case field:FieldS[Prim,SumTermId, ProductTermId, A] => (a:A) =>
s""""${pidToString(field.id)}":${toEnc(field.base, toPrimEnc, sidToString, pidToString)(a)}"""
case branch:BranchS[Prim,SumTermId, ProductTermId, A] => (a:A) =>
s"""{"${sidToString(branch.id)}":{${toEnc(branch.base, toPrimEnc, sidToString, pidToString)(a)}}}"""
}
//Schema[A] => Encoder[A]
def toEnc[Prim[_], SumTermId, ProductTermId, A](
schema:SchemaF[Prim,SumTermId, ProductTermId, A],
toPrimEnc: Prim ~> Encoder,
sidToString: SumTermId => String,
pidToString: ProductTermId => String
):Encoder[A] = schema match {
...
case field:FieldS[Prim,SumTermId, ProductTermId, A] => (a:A) =>
s""""${pidToString(field.id)}":${toEnc(field.base, toPrimEnc, sidToString, pidToString)(a)}"""
case branch:BranchS[Prim,SumTermId, ProductTermId, A] => (a:A) =>
s"""{"${sidToString(branch.id)}":{${toEnc(branch.base, toPrimEnc, sidToString, pidToString)(a)}}}"""
}
sealed trait SchemaF[Prim[_], SumTermId, ProductTermId, A]
...
final case class SeqS[Prim[_], SumTermId, ProductTermId, A(
element:SchemaF[Prim,SumTermId, ProductTermId, A]
) extends SchemaF[Prim, SumTermId, ProductTermId, List[A]]
//Schema[A] => Encoder[A]
def toEnc[Prim[_], SumTermId, ProductTermId, A](
schema:SchemaF[Prim,SumTermId, ProductTermId, A],
toPrimEnc: Prim ~> Encoder,
sidToString: SumTermId => String,
pidToString: ProductTermId => String
):Encoder[A] = schema match {
...
case seq:SeqS[Prim,SumTermId, ProductTermId, A] =>
(as:List[A]) =>
as.map(toEnc(seq.element, toPrimEnc, sidToString, pidToString)).mkString("[",",","]")
}
sealed trait SchemaF[Prim[_], SumTermId, ProductTermId, A]
...
final case class RecursiveS[Prim[_], SumTermId, ProductTermId, A](
base: () => SchemaF[Prim,SumTermId, ProductTermId, A]
) extends SchemaF[Prim, SumTermId, ProductTermId, A]
def toEnc[Prim[_], SumTermId, ProductTermId, A](
schema:SchemaF[Prim,SumTermId, ProductTermId, A],
toPrimEnc: Prim ~> Encoder,
sidToString: SumTermId => String,
pidToString: ProductTermId => String
):Encoder[A] = schema match {
...
case self:RecursiveS[Prim,SumTermId, ProductTermId, A] =>
(a:A) => toEnc(self.base(), toPrimEnc, sidToString, pidToString)(a)
}
final case class One[Prim[_], SumTermId, ProductTermId]()
extends Schema[Prim, SumTermId, ProductTermId, Unit]
def toEnc[Prim[_], SumTermId, ProductTermId, A](
schema:Schema[Prim,SumTermId, ProductTermId, A],
toPrimEnc: Prim ~> Encoder,
sidToString: SumTermId => String,
pidToString: ProductTermId => String
):Encoder[A] = schema match {
...
case _:One[Prim,SumTermId,ProductTermId] => _ => "null"
}
def optional[Prim[_], SumTermId, ProductTermId, A](
schema:SchemaF[Prim, SumTermId, ProductTermId, A]
):SchemaF[Prim, SumTermId, ProductTermId, Option[A]] =
IsoS(
SumS(
One[Prim,SumTermId,ProductTermId](),
schema
),
Iso[Unit / A, Option[A]](
_.fold(_ => Option.empty[A],Option(_))
)(
_.fold(().left[A])(a => a.right[Unit])
)
)
trait Realisation {
type Prim[A]
type SumTermId
type ProductTermId
}
trait SchemaModule[R <: Realisation] {
val R: R
type Schema[A] = SchemaF[R.Prim, R.SumTermId, R.ProductTermId, A]
type Sum[A, B] = SumS[R.Prim, R.SumTermId, R.ProductTermId, A, B]
// and all the other needed aliases
}
trait SchemaModule[R <: Realisation] {
val R: R
final def unit: Schema[Unit]
final def prim[A](prim: R.Prim[A]): Schema[A]
final def union[A, AE](choices: Schema[AE], iso: Iso[AE, A]): Schema[A]
final def optional[A](aSchema: Schema[A]): Schema[Option[A]]
final def record[A, An](terms: Schema[An], isoA: Iso[An, A]): Schema[A]
final def seq[A](element: Schema[A]): Schema[List[A]]
final def iso[A0, A](base: Schema[A0],iso: Iso[A0, A]): Schema[A]
final def self[A](root: => Schema[A]): Schema[A]
}
trait SchemaModule[R <: Realisation] {
val R: R
implicit final class SchemaSyntax[A](schema: Schema[A]) {
def :*: [B](left: Schema[B]): Schema[(B, A)]
def :+: [B](left: Schema[B]): Schema[B / A]
def -*>: (id: R.ProductTermId): Schema[A]
def -+>: (id: R.SumTermId): Schema[A]
def imap[B](_iso: Iso[A, B]): Schema[B]
}
}
object JsonSchema extends Realisation {
type Prim[A] = JsonPrim[A]
type ProductTermId = String
type SumTermId = String
sealed trait JsonPrim[A]
final case object JsonString extends JsonPrim[String]
final case object JsonNumber extends JsonPrim[BigDecimal]
final case object JsonBool extends JsonPrim[Boolean]
final case object JsonNull extends JsonPrim[Unit]
}
trait JsonModule[R <: Realisation] extends SchemaModule[R] {
def toEnc[A](
schema:Schema[A],
toPrimEnc: R.Prim ~> Encoder,
sidToString: R.SumTermId => String,
pidToString: R.ProductTermId => String
):Encoder[A] = schema match {...}
}
object module extends JsonModule[JsonSchema.type] {
val R = JsonSchema
import R._
}
sealed trait Employee
final case class Subordinate(
name:String,
age:Int,
boss: Employee
) extends Employee
final case class Boss(
name:String,
isActive:Boolean
) extends Employee
def subordinateSchema = record(
"name" -*>: prim(JsonSchema.JsonString) :*:
"age" -*>: prim(JsonSchema.JsonNumber) :*:
"boss" -*>: self(employeeSchema),
Iso[(String, (BigDecimal, Employee)), Subordinate](
tpl => Subordinate(tpl._1, tpl._2._1, tpl._2._2)
)(s => (s.name, (s.age, s.boss)))
)
def bossSchema = record(
"name" -*>: prim(JsonSchema.JsonString) :*:
"isActive" -*>: prim(JsonSchema.JsonBool),
Iso[(String, Boolean), Boss]((Boss.apply _).tupled)(b => (b.name, b.isActive))
)
def employeeSchema = union(
"subordinate" -+>: subordinateSchema :+:
"boss" -+>: bossSchema,
Iso[Subordinate / Boss, Employee] {
case -/(s) => s
case /-(b) => b
} {
case s: Subordinate => -/(s)
case b: Boss => /-(b)
}
)
object Representation {
type RSum[RA, A, RB, B]
type RProd[RA, A, RB, B]
type RIso[RA, A, B]
type RSelf[A]
type RSeq[R, A]
type -*>[K, V]
type -+>[K, V]
type RRecord[RA, An, A]
type RUnion[RA, An, A]
}
sealed trait SchemaF[Prim[_], SumTermId, ProductTermId, R, A]
final case class One[...]() extends SchemaF[... Unit, Unit]
final case class SumF[...](...) extends SchemaF[... RSum[RA, A, RB, B], A / B]
final case class ProdF[...](...) extends SchemaF[... RProd[RA, A, RB, B], (A, B)]
final case class BranchF[...](...) extends SchemaF[... -+>[SumTermId, RA], A]
final case class UnionF[... RA: IsUnion ...](...) extends SchemaF[... RUnion[RA, AE, A], A]
final case class FieldF[...](...) extends SchemaF[... -*>[ProductTermId, RA], A]
final case class RecordF[...RA: IsRecord...](...) extends SchemaF[... RRecord[RA, AP, A], A]
final case class SeqF[...](...) extends SchemaF[... RSeq[RA, A], List[A]]
final case class IsoSchemaF[...](...) extends SchemaF[... RIso[RA, A0, A], A]
final case class SelfReference[...](...) extends SchemaF[... RSelf[A], A]
final case class Boss(name:String, isActive:Boolean) extends Employee
def bossSchema = record(
"name" -*>: prim(JsonSchema.JsonString) :*:
"isActive" -*>: prim(JsonSchema.JsonBool),
Iso[(String, Boolean), Boss]((Boss.apply _).tupled)(b => (b.name, b.isActive))
)
RRecord[
RProd[
String -*> String,
String,
String -*> Boolean,
Boolean
],
(String, Boolean),
Boss
]
sealed trait SchemaF[Prim[_], SumTermId, ProductTermId, R, A]
final case class One[...]() extends SchemaF[... Unit, Unit]
final case class SumF[...](...) extends SchemaF[... RSum[RA, A, RB, B], A / B]
final case class ProdF[...](...) extends SchemaF[... RProd[RA, A, RB, B], (A, B)]
final case class BranchF[...](...) extends SchemaF[... -+>[SumTermId, RA], A]
final case class UnionF[... RA: IsUnion ...](...) extends SchemaF[... RUnion[RA, AE, A], A]
final case class FieldF[...](...) extends SchemaF[... -*>[ProductTermId, RA], A]
final case class RecordF[...RA: IsRecord...](...) extends SchemaF[... RRecord[RA, AP, A], A]
final case class SeqF[...](...) extends SchemaF[... RSeq[RA, A], List[A]]
final case class IsoSchemaF[...](...) extends SchemaF[... RIso[RA, A0, A], A]
final case class SelfReference[...](...) extends SchemaF[... RSelf[A], A]
@implicitNotFound(
msg = "It seems like the following representation type isn't isomorphic to a product of named
fields: ${A}"
)
trait IsRecord[A]
object IsRecord {
implicit def singleFieldIsRecord[K, V]: IsRecord[K -*> V] = new IsRecord[K -*> V] {}
implicit def productIsRecord[L: IsRecord, R: IsRecord, X, Y]: IsRecord[RProd[L, X, R, Y]] =
new IsRecord[RProd[L, X, R, Y]] {}
implicit def isoIsRecord[R: IsRecord, A0, A]: IsRecord[RIso[R, A0, A]] =
new IsRecord[RIso[R, A0, A]] {}
}
SchemaF ~> Encoder
sealed trait SchemaF[Prim[_], SumTermId, ProductTermId, F[_, _], R, A] {
def hmap[G[_, _]](nt: F ~~> G): SchemaF[Prim, SumTermId, ProductTermId, G, R, A]
}
…
final case class SumF[F[_, _], RA, RB, A, B, Prim[_], SumTermId, ProductTermId](
left: F[RA, A],
right: F[RB, B]
) extends SchemaF[Prim, SumTermId, ProductTermId, F, RSum[RA, A, RB, B], A / B] {
def hmap[G[_, _]](
nt: F ~~> G
): SchemaF[Prim, SumTermId, ProductTermId, G, RSum[RA, A, RB, B], A / B] =
}
...
sealed trait SchemaF[Prim[_], SumTermId, ProductTermId, F[_, _], R, A] {
def hmap[G[_, _]](nt: F ~~> G): SchemaF[Prim, SumTermId, ProductTermId, G, R, A]
}
…
final case class SumF[F[_, _], RA, RB, A, B, Prim[_], SumTermId, ProductTermId](
left: F[RA, A],
right: F[RB, B]
) extends SchemaF[Prim, SumTermId, ProductTermId, F, RSum[RA, A, RB, B], A / B] {
def hmap[G[_, _]](
nt: F ~~> G
): SchemaF[Prim, SumTermId, ProductTermId, G, RSum[RA, A, RB, B], A / B] =
}
...
trait Interpreter[F[_, _], F[_, _]] { self =>
def interpret: F ~~> G
def compose[H[_, _]](nt: H ~~> F) = self match {
case i: ComposedInterpreter[h, G, F] => ComposedInterpreter(i.underlying, i.nt.compose(nt))
case x => ComposedInterpreter(x, nt)
}
}
implicit final def encoderInterpreter(
implicit primNT: R.Prim ~> EncoderA,
fieldLabel: R.ProductTermId <~< String,
branchLabel: R.SumTermId <~< String
): RInterpreter[Encoder] =
Interpreter.cata[RSchema, Encoder](new (RSchema[Encoder, ?, ?] ~~> Encoder) {
//Implementation of Schema to Encoder here
})
case p: RPrim[Encoder, a] => primNT(p.prim)
case ProdF(left, right) => (a => left(a._1) + "," + right(a._2))
case SumF(left, right) => (a => a.fold(left, right))
case i: IsoSchema[Encoder, r, _, a] =>
i.base.compose(i.iso.reverseGet)
case r: Record[Encoder, r, _, a] =>
encloseInBraces.compose(r.fields).compose(r.iso.reverseGet)
case SeqF(element) => (a => a.map(element).mkString("[", ",", "]"))
case FieldF(id, base) => makeField(fieldLabel(id)).compose(base)
case u: Union[Encoder, r, _, a] =>
encloseInBraces.compose(u.choices).compose(u.iso.reverseGet)
case BranchF(id, base) => makeField(branchLabel(id)).compose(base)
case One() => (_ => "null")
case ref @ SelfReference(_, _) => (a => ref.unroll(a.asInstanceOf[A with Repr]))
trait SchemaModule[R <: Realisation] {
val R: R
implicit final class SchemaSyntax[A](schema: Schema[A]) {
def to[F[_, _]](implicit interpreter: RInterpreter[F]): F[_, A]
}
}
val employeeEncoder:Encoder[Employee] = employeeSchema.to[Encoder]
@jdegoes @ValentinKasas @GrafBlutwurst
Lambdaconf2019 talk

More Related Content

What's hot

Fp in scala part 1
Fp in scala part 1Fp in scala part 1
Fp in scala part 1
Hang Zhao
 
Scalaz
ScalazScalaz
Scalaz
mpilquist
 
Refactoring Functional Type Classes
Refactoring Functional Type ClassesRefactoring Functional Type Classes
Refactoring Functional Type Classes
John De Goes
 
Why The Free Monad isn't Free
Why The Free Monad isn't FreeWhy The Free Monad isn't Free
Why The Free Monad isn't Free
Kelley Robinson
 
Principled Error Handling with FP
Principled Error Handling with FPPrincipled Error Handling with FP
Principled Error Handling with FP
Luka Jacobowitz
 
L4 functions
L4 functionsL4 functions
L4 functions
mondalakash2012
 
Type classes 101 - classification beyond inheritance
Type classes 101 - classification beyond inheritanceType classes 101 - classification beyond inheritance
Type classes 101 - classification beyond inheritance
Alexey Raga
 
Effective way to code in Scala
Effective way to code in ScalaEffective way to code in Scala
Effective way to code in Scala
Knoldus Inc.
 
Type Parameterization
Type ParameterizationType Parameterization
Type Parameterization
Knoldus Inc.
 
02 arrays
02 arrays02 arrays
02 arrays
Rajan Gautam
 
Writing DSL with Applicative Functors
Writing DSL with Applicative FunctorsWriting DSL with Applicative Functors
Writing DSL with Applicative Functors
David Galichet
 
Functions In Scala
Functions In Scala Functions In Scala
Functions In Scala
Knoldus Inc.
 
Deriving Scalaz
Deriving ScalazDeriving Scalaz
Deriving Scalaz
nkpart
 
1D Array
1D Array1D Array
1D Array
A. S. M. Shafi
 
Scala by Luc Duponcheel
Scala by Luc DuponcheelScala by Luc Duponcheel
Scala by Luc Duponcheel
Stephan Janssen
 
Testing in the World of Functional Programming
Testing in the World of Functional ProgrammingTesting in the World of Functional Programming
Testing in the World of Functional Programming
Luka Jacobowitz
 
Atomically { Delete Your Actors }
Atomically { Delete Your Actors }Atomically { Delete Your Actors }
Atomically { Delete Your Actors }
John De Goes
 
Oh, All the things you'll traverse
Oh, All the things you'll traverseOh, All the things you'll traverse
Oh, All the things you'll traverse
Luka Jacobowitz
 
The Ring programming language version 1.8 book - Part 29 of 202
The Ring programming language version 1.8 book - Part 29 of 202The Ring programming language version 1.8 book - Part 29 of 202
The Ring programming language version 1.8 book - Part 29 of 202
Mahmoud Samir Fayed
 

What's hot (19)

Fp in scala part 1
Fp in scala part 1Fp in scala part 1
Fp in scala part 1
 
Scalaz
ScalazScalaz
Scalaz
 
Refactoring Functional Type Classes
Refactoring Functional Type ClassesRefactoring Functional Type Classes
Refactoring Functional Type Classes
 
Why The Free Monad isn't Free
Why The Free Monad isn't FreeWhy The Free Monad isn't Free
Why The Free Monad isn't Free
 
Principled Error Handling with FP
Principled Error Handling with FPPrincipled Error Handling with FP
Principled Error Handling with FP
 
L4 functions
L4 functionsL4 functions
L4 functions
 
Type classes 101 - classification beyond inheritance
Type classes 101 - classification beyond inheritanceType classes 101 - classification beyond inheritance
Type classes 101 - classification beyond inheritance
 
Effective way to code in Scala
Effective way to code in ScalaEffective way to code in Scala
Effective way to code in Scala
 
Type Parameterization
Type ParameterizationType Parameterization
Type Parameterization
 
02 arrays
02 arrays02 arrays
02 arrays
 
Writing DSL with Applicative Functors
Writing DSL with Applicative FunctorsWriting DSL with Applicative Functors
Writing DSL with Applicative Functors
 
Functions In Scala
Functions In Scala Functions In Scala
Functions In Scala
 
Deriving Scalaz
Deriving ScalazDeriving Scalaz
Deriving Scalaz
 
1D Array
1D Array1D Array
1D Array
 
Scala by Luc Duponcheel
Scala by Luc DuponcheelScala by Luc Duponcheel
Scala by Luc Duponcheel
 
Testing in the World of Functional Programming
Testing in the World of Functional ProgrammingTesting in the World of Functional Programming
Testing in the World of Functional Programming
 
Atomically { Delete Your Actors }
Atomically { Delete Your Actors }Atomically { Delete Your Actors }
Atomically { Delete Your Actors }
 
Oh, All the things you'll traverse
Oh, All the things you'll traverseOh, All the things you'll traverse
Oh, All the things you'll traverse
 
The Ring programming language version 1.8 book - Part 29 of 202
The Ring programming language version 1.8 book - Part 29 of 202The Ring programming language version 1.8 book - Part 29 of 202
The Ring programming language version 1.8 book - Part 29 of 202
 

Similar to Lambdaconf2019 talk

Beginning Scala Svcc 2009
Beginning Scala Svcc 2009Beginning Scala Svcc 2009
Beginning Scala Svcc 2009
David Pollak
 
Python programming workshop session 3
Python programming workshop session 3Python programming workshop session 3
Python programming workshop session 3
Abdul Haseeb
 
Mbd2
Mbd2Mbd2
Scala Functional Patterns
Scala Functional PatternsScala Functional Patterns
Scala Functional Patterns
league
 
Java8
Java8Java8
Functional Programming In Java
Functional Programming In JavaFunctional Programming In Java
Functional Programming In Java
Andrei Solntsev
 
Machine-level Composition of Modularized Crosscutting Concerns
Machine-level Composition of Modularized Crosscutting ConcernsMachine-level Composition of Modularized Crosscutting Concerns
Machine-level Composition of Modularized Crosscutting Concerns
saintiss
 
Go ahead, make my day
Go ahead, make my dayGo ahead, make my day
Go ahead, make my day
Tor Ivry
 
Ray Tracing with ZIO
Ray Tracing with ZIORay Tracing with ZIO
Ray Tracing with ZIO
Pierangelo Cecchetto
 
Stacks.ppt
Stacks.pptStacks.ppt
Stacks.ppt
OliverKane3
 
Stacks.ppt
Stacks.pptStacks.ppt
Stacks.ppt
OliverKane3
 
Berlin meetup
Berlin meetupBerlin meetup
Berlin meetup
Wiem Zine Elabidine
 
MATLAB-Cheat-Sheet-for-Data-Science_LondonSchoolofEconomics (1).pdf
MATLAB-Cheat-Sheet-for-Data-Science_LondonSchoolofEconomics (1).pdfMATLAB-Cheat-Sheet-for-Data-Science_LondonSchoolofEconomics (1).pdf
MATLAB-Cheat-Sheet-for-Data-Science_LondonSchoolofEconomics (1).pdf
Central university of Haryana
 
Unit 3 arrays and_string
Unit 3 arrays and_stringUnit 3 arrays and_string
Unit 3 arrays and_string
kirthika jeyenth
 
The Essence of the Iterator Pattern
The Essence of the Iterator PatternThe Essence of the Iterator Pattern
The Essence of the Iterator Pattern
Eric Torreborre
 
Post-Free: Life After Free Monads
Post-Free: Life After Free MonadsPost-Free: Life After Free Monads
Post-Free: Life After Free Monads
John De Goes
 
Bw14
Bw14Bw14
Imugi: Compiler made with Python
Imugi: Compiler made with PythonImugi: Compiler made with Python
Imugi: Compiler made with Python
Han Lee
 
Deep learning study 3
Deep learning study 3Deep learning study 3
Deep learning study 3
San Kim
 
SDC - Einführung in Scala
SDC - Einführung in ScalaSDC - Einführung in Scala
SDC - Einführung in Scala
Christian Baranowski
 

Similar to Lambdaconf2019 talk (20)

Beginning Scala Svcc 2009
Beginning Scala Svcc 2009Beginning Scala Svcc 2009
Beginning Scala Svcc 2009
 
Python programming workshop session 3
Python programming workshop session 3Python programming workshop session 3
Python programming workshop session 3
 
Mbd2
Mbd2Mbd2
Mbd2
 
Scala Functional Patterns
Scala Functional PatternsScala Functional Patterns
Scala Functional Patterns
 
Java8
Java8Java8
Java8
 
Functional Programming In Java
Functional Programming In JavaFunctional Programming In Java
Functional Programming In Java
 
Machine-level Composition of Modularized Crosscutting Concerns
Machine-level Composition of Modularized Crosscutting ConcernsMachine-level Composition of Modularized Crosscutting Concerns
Machine-level Composition of Modularized Crosscutting Concerns
 
Go ahead, make my day
Go ahead, make my dayGo ahead, make my day
Go ahead, make my day
 
Ray Tracing with ZIO
Ray Tracing with ZIORay Tracing with ZIO
Ray Tracing with ZIO
 
Stacks.ppt
Stacks.pptStacks.ppt
Stacks.ppt
 
Stacks.ppt
Stacks.pptStacks.ppt
Stacks.ppt
 
Berlin meetup
Berlin meetupBerlin meetup
Berlin meetup
 
MATLAB-Cheat-Sheet-for-Data-Science_LondonSchoolofEconomics (1).pdf
MATLAB-Cheat-Sheet-for-Data-Science_LondonSchoolofEconomics (1).pdfMATLAB-Cheat-Sheet-for-Data-Science_LondonSchoolofEconomics (1).pdf
MATLAB-Cheat-Sheet-for-Data-Science_LondonSchoolofEconomics (1).pdf
 
Unit 3 arrays and_string
Unit 3 arrays and_stringUnit 3 arrays and_string
Unit 3 arrays and_string
 
The Essence of the Iterator Pattern
The Essence of the Iterator PatternThe Essence of the Iterator Pattern
The Essence of the Iterator Pattern
 
Post-Free: Life After Free Monads
Post-Free: Life After Free MonadsPost-Free: Life After Free Monads
Post-Free: Life After Free Monads
 
Bw14
Bw14Bw14
Bw14
 
Imugi: Compiler made with Python
Imugi: Compiler made with PythonImugi: Compiler made with Python
Imugi: Compiler made with Python
 
Deep learning study 3
Deep learning study 3Deep learning study 3
Deep learning study 3
 
SDC - Einführung in Scala
SDC - Einführung in ScalaSDC - Einführung in Scala
SDC - Einführung in Scala
 

Recently uploaded

Oracle 23c New Features For DBAs and Developers.pptx
Oracle 23c New Features For DBAs and Developers.pptxOracle 23c New Features For DBAs and Developers.pptx
Oracle 23c New Features For DBAs and Developers.pptx
Remote DBA Services
 
Introducing Crescat - Event Management Software for Venues, Festivals and Eve...
Introducing Crescat - Event Management Software for Venues, Festivals and Eve...Introducing Crescat - Event Management Software for Venues, Festivals and Eve...
Introducing Crescat - Event Management Software for Venues, Festivals and Eve...
Crescat
 
socradar-q1-2024-aviation-industry-report.pdf
socradar-q1-2024-aviation-industry-report.pdfsocradar-q1-2024-aviation-industry-report.pdf
socradar-q1-2024-aviation-industry-report.pdf
SOCRadar
 
UI5con 2024 - Boost Your Development Experience with UI5 Tooling Extensions
UI5con 2024 - Boost Your Development Experience with UI5 Tooling ExtensionsUI5con 2024 - Boost Your Development Experience with UI5 Tooling Extensions
UI5con 2024 - Boost Your Development Experience with UI5 Tooling Extensions
Peter Muessig
 
E-commerce Application Development Company.pdf
E-commerce Application Development Company.pdfE-commerce Application Development Company.pdf
E-commerce Application Development Company.pdf
Hornet Dynamics
 
GreenCode-A-VSCode-Plugin--Dario-Jurisic
GreenCode-A-VSCode-Plugin--Dario-JurisicGreenCode-A-VSCode-Plugin--Dario-Jurisic
GreenCode-A-VSCode-Plugin--Dario-Jurisic
Green Software Development
 
Automated software refactoring with OpenRewrite and Generative AI.pptx.pdf
Automated software refactoring with OpenRewrite and Generative AI.pptx.pdfAutomated software refactoring with OpenRewrite and Generative AI.pptx.pdf
Automated software refactoring with OpenRewrite and Generative AI.pptx.pdf
timtebeek1
 
OpenMetadata Community Meeting - 5th June 2024
OpenMetadata Community Meeting - 5th June 2024OpenMetadata Community Meeting - 5th June 2024
OpenMetadata Community Meeting - 5th June 2024
OpenMetadata
 
SMS API Integration in Saudi Arabia| Best SMS API Service
SMS API Integration in Saudi Arabia| Best SMS API ServiceSMS API Integration in Saudi Arabia| Best SMS API Service
SMS API Integration in Saudi Arabia| Best SMS API Service
Yara Milbes
 
Using Query Store in Azure PostgreSQL to Understand Query Performance
Using Query Store in Azure PostgreSQL to Understand Query PerformanceUsing Query Store in Azure PostgreSQL to Understand Query Performance
Using Query Store in Azure PostgreSQL to Understand Query Performance
Grant Fritchey
 
What is Master Data Management by PiLog Group
What is Master Data Management by PiLog GroupWhat is Master Data Management by PiLog Group
What is Master Data Management by PiLog Group
aymanquadri279
 
Empowering Growth with Best Software Development Company in Noida - Deuglo
Empowering Growth with Best Software  Development Company in Noida - DeugloEmpowering Growth with Best Software  Development Company in Noida - Deuglo
Empowering Growth with Best Software Development Company in Noida - Deuglo
Deuglo Infosystem Pvt Ltd
 
LORRAINE ANDREI_LEQUIGAN_HOW TO USE ZOOM
LORRAINE ANDREI_LEQUIGAN_HOW TO USE ZOOMLORRAINE ANDREI_LEQUIGAN_HOW TO USE ZOOM
LORRAINE ANDREI_LEQUIGAN_HOW TO USE ZOOM
lorraineandreiamcidl
 
ALGIT - Assembly Line for Green IT - Numbers, Data, Facts
ALGIT - Assembly Line for Green IT - Numbers, Data, FactsALGIT - Assembly Line for Green IT - Numbers, Data, Facts
ALGIT - Assembly Line for Green IT - Numbers, Data, Facts
Green Software Development
 
Revolutionizing Visual Effects Mastering AI Face Swaps.pdf
Revolutionizing Visual Effects Mastering AI Face Swaps.pdfRevolutionizing Visual Effects Mastering AI Face Swaps.pdf
Revolutionizing Visual Effects Mastering AI Face Swaps.pdf
Undress Baby
 
Graspan: A Big Data System for Big Code Analysis
Graspan: A Big Data System for Big Code AnalysisGraspan: A Big Data System for Big Code Analysis
Graspan: A Big Data System for Big Code Analysis
Aftab Hussain
 
Why Choose Odoo 17 Community & How it differs from Odoo 17 Enterprise Edition
Why Choose Odoo 17 Community & How it differs from Odoo 17 Enterprise EditionWhy Choose Odoo 17 Community & How it differs from Odoo 17 Enterprise Edition
Why Choose Odoo 17 Community & How it differs from Odoo 17 Enterprise Edition
Envertis Software Solutions
 
GraphSummit Paris - The art of the possible with Graph Technology
GraphSummit Paris - The art of the possible with Graph TechnologyGraphSummit Paris - The art of the possible with Graph Technology
GraphSummit Paris - The art of the possible with Graph Technology
Neo4j
 
Artificia Intellicence and XPath Extension Functions
Artificia Intellicence and XPath Extension FunctionsArtificia Intellicence and XPath Extension Functions
Artificia Intellicence and XPath Extension Functions
Octavian Nadolu
 
Hand Rolled Applicative User Validation Code Kata
Hand Rolled Applicative User ValidationCode KataHand Rolled Applicative User ValidationCode Kata
Hand Rolled Applicative User Validation Code Kata
Philip Schwarz
 

Recently uploaded (20)

Oracle 23c New Features For DBAs and Developers.pptx
Oracle 23c New Features For DBAs and Developers.pptxOracle 23c New Features For DBAs and Developers.pptx
Oracle 23c New Features For DBAs and Developers.pptx
 
Introducing Crescat - Event Management Software for Venues, Festivals and Eve...
Introducing Crescat - Event Management Software for Venues, Festivals and Eve...Introducing Crescat - Event Management Software for Venues, Festivals and Eve...
Introducing Crescat - Event Management Software for Venues, Festivals and Eve...
 
socradar-q1-2024-aviation-industry-report.pdf
socradar-q1-2024-aviation-industry-report.pdfsocradar-q1-2024-aviation-industry-report.pdf
socradar-q1-2024-aviation-industry-report.pdf
 
UI5con 2024 - Boost Your Development Experience with UI5 Tooling Extensions
UI5con 2024 - Boost Your Development Experience with UI5 Tooling ExtensionsUI5con 2024 - Boost Your Development Experience with UI5 Tooling Extensions
UI5con 2024 - Boost Your Development Experience with UI5 Tooling Extensions
 
E-commerce Application Development Company.pdf
E-commerce Application Development Company.pdfE-commerce Application Development Company.pdf
E-commerce Application Development Company.pdf
 
GreenCode-A-VSCode-Plugin--Dario-Jurisic
GreenCode-A-VSCode-Plugin--Dario-JurisicGreenCode-A-VSCode-Plugin--Dario-Jurisic
GreenCode-A-VSCode-Plugin--Dario-Jurisic
 
Automated software refactoring with OpenRewrite and Generative AI.pptx.pdf
Automated software refactoring with OpenRewrite and Generative AI.pptx.pdfAutomated software refactoring with OpenRewrite and Generative AI.pptx.pdf
Automated software refactoring with OpenRewrite and Generative AI.pptx.pdf
 
OpenMetadata Community Meeting - 5th June 2024
OpenMetadata Community Meeting - 5th June 2024OpenMetadata Community Meeting - 5th June 2024
OpenMetadata Community Meeting - 5th June 2024
 
SMS API Integration in Saudi Arabia| Best SMS API Service
SMS API Integration in Saudi Arabia| Best SMS API ServiceSMS API Integration in Saudi Arabia| Best SMS API Service
SMS API Integration in Saudi Arabia| Best SMS API Service
 
Using Query Store in Azure PostgreSQL to Understand Query Performance
Using Query Store in Azure PostgreSQL to Understand Query PerformanceUsing Query Store in Azure PostgreSQL to Understand Query Performance
Using Query Store in Azure PostgreSQL to Understand Query Performance
 
What is Master Data Management by PiLog Group
What is Master Data Management by PiLog GroupWhat is Master Data Management by PiLog Group
What is Master Data Management by PiLog Group
 
Empowering Growth with Best Software Development Company in Noida - Deuglo
Empowering Growth with Best Software  Development Company in Noida - DeugloEmpowering Growth with Best Software  Development Company in Noida - Deuglo
Empowering Growth with Best Software Development Company in Noida - Deuglo
 
LORRAINE ANDREI_LEQUIGAN_HOW TO USE ZOOM
LORRAINE ANDREI_LEQUIGAN_HOW TO USE ZOOMLORRAINE ANDREI_LEQUIGAN_HOW TO USE ZOOM
LORRAINE ANDREI_LEQUIGAN_HOW TO USE ZOOM
 
ALGIT - Assembly Line for Green IT - Numbers, Data, Facts
ALGIT - Assembly Line for Green IT - Numbers, Data, FactsALGIT - Assembly Line for Green IT - Numbers, Data, Facts
ALGIT - Assembly Line for Green IT - Numbers, Data, Facts
 
Revolutionizing Visual Effects Mastering AI Face Swaps.pdf
Revolutionizing Visual Effects Mastering AI Face Swaps.pdfRevolutionizing Visual Effects Mastering AI Face Swaps.pdf
Revolutionizing Visual Effects Mastering AI Face Swaps.pdf
 
Graspan: A Big Data System for Big Code Analysis
Graspan: A Big Data System for Big Code AnalysisGraspan: A Big Data System for Big Code Analysis
Graspan: A Big Data System for Big Code Analysis
 
Why Choose Odoo 17 Community & How it differs from Odoo 17 Enterprise Edition
Why Choose Odoo 17 Community & How it differs from Odoo 17 Enterprise EditionWhy Choose Odoo 17 Community & How it differs from Odoo 17 Enterprise Edition
Why Choose Odoo 17 Community & How it differs from Odoo 17 Enterprise Edition
 
GraphSummit Paris - The art of the possible with Graph Technology
GraphSummit Paris - The art of the possible with Graph TechnologyGraphSummit Paris - The art of the possible with Graph Technology
GraphSummit Paris - The art of the possible with Graph Technology
 
Artificia Intellicence and XPath Extension Functions
Artificia Intellicence and XPath Extension FunctionsArtificia Intellicence and XPath Extension Functions
Artificia Intellicence and XPath Extension Functions
 
Hand Rolled Applicative User Validation Code Kata
Hand Rolled Applicative User ValidationCode KataHand Rolled Applicative User ValidationCode Kata
Hand Rolled Applicative User Validation Code Kata
 

Lambdaconf2019 talk

  • 1.
  • 2.
  • 3. type Encoder[A] = A => Json type Decoder[A] = Json => Either[Error, A]
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 15. sealed trait Employee final case class Subordinate( name:String, age:Int, boss: Employee ) extends Employee final case class Boss( name:String, isActive:Boolean ) extends Employee
  • 18.
  • 19. sealed trait MyPrim[A] final case object IntP extends MyPrim[Int] final case object StringP extends MyPrim[String] final case object BooleanP extends MyPrim[Boolean]
  • 20. sealed trait SchemaF[A] final case class PrimF[A](prim:MyPrim[A]) extends SchemaF[A]
  • 21.
  • 22. sealed trait SchemaF[Prim[_], A] final case class PrimS[Prim[_], A](prim:Prim[A]) extends SchemaF[Prim, A]
  • 23. //MyPrim[A] => Encoder[A] ---- Prim ~> Encoder def toPrimEnc[A](prim:MyPrim[A]):Encoder[A] = prim match { case IntP => (i:Int) => i.toString case StringP => (s:String) => s""""$s"""" case BooleanP => (b:Boolean) => if (b) "true" else "false" }
  • 24. def toEnc[Prim[_], A](schema:SchemaF[Prim, A], toPrimEnc: Prim ~> Encoder):Encoder[A] = schema match { case PrimS(p) => toPrimEnc(p) }
  • 25. val intSchema:SchemaF[MyPrim, Int] = PrimS(IntP) val strSchema:SchemaF[MyPrim, String] = PrimS(StringP) val booleanSchema:SchemaF[MyPrim, Boolean] = PrimS(BooleanP)
  • 26. val nt: MyPrim ~> Encoder = new NaturalTransformation[MyPrim, Encoder]{ override def apply[A](prim:MyPrim[A]):Encoder[A] = toPrimEnc(prim) } val encoder: Encoder[Int] = toEnc(intSchema, nt)
  • 27.
  • 28. sealed trait SchemaF[Prim[_], A] final case class PrimS[Prim[_],A](prim:Prim[A]) extends SchemaF[Prim, A] final case class ProdS[Prim[_],A,B](l:SchemaF[Prim, A], r:SchemaF[Prim, B]) extends SchemaF[Prim, (A,B)] final case class SumS[Prim[_],A,B](l:SchemaF[Prim, A], r:SchemaF[Prim, B]) extends SchemaF[Prim, A/B]
  • 29. val productSumSchema:SchemaF[MyPrim, (Int, (String, (Boolean / Int)))] = ProdS(intSchema, ProdS(strSchema, SumS(booleanSchema, intSchema)))
  • 30.
  • 31. def toEnc[Prim[_], A](schema:SchemaF[Prim, A], toPrimEnc: Prim ~> Encoder):Encoder[A] = schema match { case PrimS(p) => toPrimEnc(p) case prod:ProdS[Prim, x, y] => (tpl:(x,y)) => toEnc(prod.l, toPrimEnc)(tpl._1) + "," + toEnc(prod.r, toPrimEnc)(tpl._2) }
  • 32. def toEnc[Prim[_], A](schema:SchemaF[Prim, A], toPrimEnc: Prim ~> Encoder):Encoder[A] = schema match { case PrimS(p) => toPrimEnc(p) case prod:ProdS[Prim, x, y] => (tpl:(x,y)) => toEnc(prod.l, toPrimEnc)(tpl._1) + "," + toEnc(prod.r, toPrimEnc)(tpl._2) case sum:SumS[Prim, x, y] => (e:x / y) => e.fold( lx => toEnc(sum.l, toPrimEnc)(lx), ry => toEnc(sum.r, toPrimEnc)(ry) ) }
  • 33.
  • 34.
  • 35. sealed trait SchemaF[Prim[_], A] final case class PrimS[Prim[_],A](prim:Prim[A]) extends SchemaF[Prim, A] final case class ProdS[Prim[_],A,B](l:SchemaF[Prim, A], r:SchemaF[Prim, B]) extends SchemaF[Prim, (A,B)] final case class SumS[Prim[_],A,B](l:SchemaF[Prim, A], r:SchemaF[Prim, B]) extends SchemaF[Prim, A/B] final case class UnionS[Prim[_],B,A](base:SchemaF[Prim, B], iso:Iso[B,A]) extends SchemaF[Prim, A] final case class RecordS[Prim[_],B,A](base:SchemaF[Prim, B], iso:Iso[B,A]) extends SchemaF[Prim, A] final case class IsoS[Prim[_],B,A](base:SchemaF[Prim, B], iso:Iso[B,A]) extends SchemaF[Prim, A]
  • 36.
  • 37. def toEnc[Prim[_], A](schema:SchemaF[Prim, A], toPrimEnc: Prim ~> Encoder):Encoder[A] = schema match { case PrimS(p) => toPrimEnc(p) case prod:ProdS[Prim, x, y] => (tpl:(x,y)) => toEnc(prod.l, toPrimEnc)(tpl._1) + "," + toEnc(prod.r, toPrimEnc)(tpl._2) case sum:SumS[Prim, x, y] => (e:x / y) => e.fold( lx => toEnc(sum.l, toPrimEnc)(lx), ry => toEnc(sum.r, toPrimEnc)(ry) ) case isoS:IsoS[Prim, b, A] => (a:A) => toEnc(isoS.base, toPrimEnc)(isoS.iso.reverseGet(a)) case union:UnionS[Prim, b, A] => (a:A) => toEnc(union.base, toPrimEnc)(union.iso.reverseGet(a)) case record:RecordS[Prim, b, A] => (a:A) => toEnc(record.base, toPrimEnc)(record.iso.reverseGet(a)) }
  • 38.
  • 39.
  • 40. sealed trait SchemaF[Prim[_], SumTermId, ProductTermId, A] ... final case class FieldS[Prim[_], SumTermId, ProductTermId, A]( id:ProductTermId, base:SchemaF[Prim,SumTermId, ProductTermId, A] ) extends SchemaF[Prim, SumTermId, ProductTermId, A] final case class BranchS[Prim[_], SumTermId, ProductTermId, A]( id:SumTermId, base:SchemaF[Prim,SumTermId, ProductTermId, A] ) extends SchemaF[Prim, SumTermId, ProductTermId, A]
  • 41.
  • 42. //Schema[A] => Encoder[A] def toEnc[Prim[_], SumTermId, ProductTermId, A]( schema:SchemaF[Prim,SumTermId, ProductTermId, A], toPrimEnc: Prim ~> Encoder, sidToString: SumTermId => String, pidToString: ProductTermId => String ):Encoder[A] = schema match { ... case field:FieldS[Prim,SumTermId, ProductTermId, A] => (a:A) => s""""${pidToString(field.id)}":${toEnc(field.base, toPrimEnc, sidToString, pidToString)(a)}""" case branch:BranchS[Prim,SumTermId, ProductTermId, A] => (a:A) => s"""{"${sidToString(branch.id)}":{${toEnc(branch.base, toPrimEnc, sidToString, pidToString)(a)}}}""" }
  • 43. //Schema[A] => Encoder[A] def toEnc[Prim[_], SumTermId, ProductTermId, A]( schema:SchemaF[Prim,SumTermId, ProductTermId, A], toPrimEnc: Prim ~> Encoder, sidToString: SumTermId => String, pidToString: ProductTermId => String ):Encoder[A] = schema match { ... case field:FieldS[Prim,SumTermId, ProductTermId, A] => (a:A) => s""""${pidToString(field.id)}":${toEnc(field.base, toPrimEnc, sidToString, pidToString)(a)}""" case branch:BranchS[Prim,SumTermId, ProductTermId, A] => (a:A) => s"""{"${sidToString(branch.id)}":{${toEnc(branch.base, toPrimEnc, sidToString, pidToString)(a)}}}""" }
  • 44.
  • 45. sealed trait SchemaF[Prim[_], SumTermId, ProductTermId, A] ... final case class SeqS[Prim[_], SumTermId, ProductTermId, A( element:SchemaF[Prim,SumTermId, ProductTermId, A] ) extends SchemaF[Prim, SumTermId, ProductTermId, List[A]]
  • 46. //Schema[A] => Encoder[A] def toEnc[Prim[_], SumTermId, ProductTermId, A]( schema:SchemaF[Prim,SumTermId, ProductTermId, A], toPrimEnc: Prim ~> Encoder, sidToString: SumTermId => String, pidToString: ProductTermId => String ):Encoder[A] = schema match { ... case seq:SeqS[Prim,SumTermId, ProductTermId, A] => (as:List[A]) => as.map(toEnc(seq.element, toPrimEnc, sidToString, pidToString)).mkString("[",",","]") }
  • 47.
  • 48. sealed trait SchemaF[Prim[_], SumTermId, ProductTermId, A] ... final case class RecursiveS[Prim[_], SumTermId, ProductTermId, A]( base: () => SchemaF[Prim,SumTermId, ProductTermId, A] ) extends SchemaF[Prim, SumTermId, ProductTermId, A]
  • 49. def toEnc[Prim[_], SumTermId, ProductTermId, A]( schema:SchemaF[Prim,SumTermId, ProductTermId, A], toPrimEnc: Prim ~> Encoder, sidToString: SumTermId => String, pidToString: ProductTermId => String ):Encoder[A] = schema match { ... case self:RecursiveS[Prim,SumTermId, ProductTermId, A] => (a:A) => toEnc(self.base(), toPrimEnc, sidToString, pidToString)(a) }
  • 50.
  • 51.
  • 52.
  • 53. final case class One[Prim[_], SumTermId, ProductTermId]() extends Schema[Prim, SumTermId, ProductTermId, Unit]
  • 54. def toEnc[Prim[_], SumTermId, ProductTermId, A]( schema:Schema[Prim,SumTermId, ProductTermId, A], toPrimEnc: Prim ~> Encoder, sidToString: SumTermId => String, pidToString: ProductTermId => String ):Encoder[A] = schema match { ... case _:One[Prim,SumTermId,ProductTermId] => _ => "null" }
  • 55. def optional[Prim[_], SumTermId, ProductTermId, A]( schema:SchemaF[Prim, SumTermId, ProductTermId, A] ):SchemaF[Prim, SumTermId, ProductTermId, Option[A]] = IsoS( SumS( One[Prim,SumTermId,ProductTermId](), schema ), Iso[Unit / A, Option[A]]( _.fold(_ => Option.empty[A],Option(_)) )( _.fold(().left[A])(a => a.right[Unit]) ) )
  • 56.
  • 57.
  • 58. trait Realisation { type Prim[A] type SumTermId type ProductTermId }
  • 59. trait SchemaModule[R <: Realisation] { val R: R type Schema[A] = SchemaF[R.Prim, R.SumTermId, R.ProductTermId, A] type Sum[A, B] = SumS[R.Prim, R.SumTermId, R.ProductTermId, A, B] // and all the other needed aliases }
  • 60. trait SchemaModule[R <: Realisation] { val R: R final def unit: Schema[Unit] final def prim[A](prim: R.Prim[A]): Schema[A] final def union[A, AE](choices: Schema[AE], iso: Iso[AE, A]): Schema[A] final def optional[A](aSchema: Schema[A]): Schema[Option[A]] final def record[A, An](terms: Schema[An], isoA: Iso[An, A]): Schema[A] final def seq[A](element: Schema[A]): Schema[List[A]] final def iso[A0, A](base: Schema[A0],iso: Iso[A0, A]): Schema[A] final def self[A](root: => Schema[A]): Schema[A] }
  • 61. trait SchemaModule[R <: Realisation] { val R: R implicit final class SchemaSyntax[A](schema: Schema[A]) { def :*: [B](left: Schema[B]): Schema[(B, A)] def :+: [B](left: Schema[B]): Schema[B / A] def -*>: (id: R.ProductTermId): Schema[A] def -+>: (id: R.SumTermId): Schema[A] def imap[B](_iso: Iso[A, B]): Schema[B] } }
  • 62. object JsonSchema extends Realisation { type Prim[A] = JsonPrim[A] type ProductTermId = String type SumTermId = String sealed trait JsonPrim[A] final case object JsonString extends JsonPrim[String] final case object JsonNumber extends JsonPrim[BigDecimal] final case object JsonBool extends JsonPrim[Boolean] final case object JsonNull extends JsonPrim[Unit] }
  • 63. trait JsonModule[R <: Realisation] extends SchemaModule[R] { def toEnc[A]( schema:Schema[A], toPrimEnc: R.Prim ~> Encoder, sidToString: R.SumTermId => String, pidToString: R.ProductTermId => String ):Encoder[A] = schema match {...} }
  • 64. object module extends JsonModule[JsonSchema.type] { val R = JsonSchema import R._ }
  • 65. sealed trait Employee final case class Subordinate( name:String, age:Int, boss: Employee ) extends Employee final case class Boss( name:String, isActive:Boolean ) extends Employee
  • 66. def subordinateSchema = record( "name" -*>: prim(JsonSchema.JsonString) :*: "age" -*>: prim(JsonSchema.JsonNumber) :*: "boss" -*>: self(employeeSchema), Iso[(String, (BigDecimal, Employee)), Subordinate]( tpl => Subordinate(tpl._1, tpl._2._1, tpl._2._2) )(s => (s.name, (s.age, s.boss))) ) def bossSchema = record( "name" -*>: prim(JsonSchema.JsonString) :*: "isActive" -*>: prim(JsonSchema.JsonBool), Iso[(String, Boolean), Boss]((Boss.apply _).tupled)(b => (b.name, b.isActive)) ) def employeeSchema = union( "subordinate" -+>: subordinateSchema :+: "boss" -+>: bossSchema, Iso[Subordinate / Boss, Employee] { case -/(s) => s case /-(b) => b } { case s: Subordinate => -/(s) case b: Boss => /-(b) } )
  • 67.
  • 68.
  • 69.
  • 70. object Representation { type RSum[RA, A, RB, B] type RProd[RA, A, RB, B] type RIso[RA, A, B] type RSelf[A] type RSeq[R, A] type -*>[K, V] type -+>[K, V] type RRecord[RA, An, A] type RUnion[RA, An, A] }
  • 71. sealed trait SchemaF[Prim[_], SumTermId, ProductTermId, R, A] final case class One[...]() extends SchemaF[... Unit, Unit] final case class SumF[...](...) extends SchemaF[... RSum[RA, A, RB, B], A / B] final case class ProdF[...](...) extends SchemaF[... RProd[RA, A, RB, B], (A, B)] final case class BranchF[...](...) extends SchemaF[... -+>[SumTermId, RA], A] final case class UnionF[... RA: IsUnion ...](...) extends SchemaF[... RUnion[RA, AE, A], A] final case class FieldF[...](...) extends SchemaF[... -*>[ProductTermId, RA], A] final case class RecordF[...RA: IsRecord...](...) extends SchemaF[... RRecord[RA, AP, A], A] final case class SeqF[...](...) extends SchemaF[... RSeq[RA, A], List[A]] final case class IsoSchemaF[...](...) extends SchemaF[... RIso[RA, A0, A], A] final case class SelfReference[...](...) extends SchemaF[... RSelf[A], A]
  • 72. final case class Boss(name:String, isActive:Boolean) extends Employee def bossSchema = record( "name" -*>: prim(JsonSchema.JsonString) :*: "isActive" -*>: prim(JsonSchema.JsonBool), Iso[(String, Boolean), Boss]((Boss.apply _).tupled)(b => (b.name, b.isActive)) )
  • 73. RRecord[ RProd[ String -*> String, String, String -*> Boolean, Boolean ], (String, Boolean), Boss ]
  • 74. sealed trait SchemaF[Prim[_], SumTermId, ProductTermId, R, A] final case class One[...]() extends SchemaF[... Unit, Unit] final case class SumF[...](...) extends SchemaF[... RSum[RA, A, RB, B], A / B] final case class ProdF[...](...) extends SchemaF[... RProd[RA, A, RB, B], (A, B)] final case class BranchF[...](...) extends SchemaF[... -+>[SumTermId, RA], A] final case class UnionF[... RA: IsUnion ...](...) extends SchemaF[... RUnion[RA, AE, A], A] final case class FieldF[...](...) extends SchemaF[... -*>[ProductTermId, RA], A] final case class RecordF[...RA: IsRecord...](...) extends SchemaF[... RRecord[RA, AP, A], A] final case class SeqF[...](...) extends SchemaF[... RSeq[RA, A], List[A]] final case class IsoSchemaF[...](...) extends SchemaF[... RIso[RA, A0, A], A] final case class SelfReference[...](...) extends SchemaF[... RSelf[A], A]
  • 75. @implicitNotFound( msg = "It seems like the following representation type isn't isomorphic to a product of named fields: ${A}" ) trait IsRecord[A] object IsRecord { implicit def singleFieldIsRecord[K, V]: IsRecord[K -*> V] = new IsRecord[K -*> V] {} implicit def productIsRecord[L: IsRecord, R: IsRecord, X, Y]: IsRecord[RProd[L, X, R, Y]] = new IsRecord[RProd[L, X, R, Y]] {} implicit def isoIsRecord[R: IsRecord, A0, A]: IsRecord[RIso[R, A0, A]] = new IsRecord[RIso[R, A0, A]] {} }
  • 76.
  • 77.
  • 78.
  • 79.
  • 81.
  • 82. sealed trait SchemaF[Prim[_], SumTermId, ProductTermId, F[_, _], R, A] { def hmap[G[_, _]](nt: F ~~> G): SchemaF[Prim, SumTermId, ProductTermId, G, R, A] } … final case class SumF[F[_, _], RA, RB, A, B, Prim[_], SumTermId, ProductTermId]( left: F[RA, A], right: F[RB, B] ) extends SchemaF[Prim, SumTermId, ProductTermId, F, RSum[RA, A, RB, B], A / B] { def hmap[G[_, _]]( nt: F ~~> G ): SchemaF[Prim, SumTermId, ProductTermId, G, RSum[RA, A, RB, B], A / B] = } ...
  • 83. sealed trait SchemaF[Prim[_], SumTermId, ProductTermId, F[_, _], R, A] { def hmap[G[_, _]](nt: F ~~> G): SchemaF[Prim, SumTermId, ProductTermId, G, R, A] } … final case class SumF[F[_, _], RA, RB, A, B, Prim[_], SumTermId, ProductTermId]( left: F[RA, A], right: F[RB, B] ) extends SchemaF[Prim, SumTermId, ProductTermId, F, RSum[RA, A, RB, B], A / B] { def hmap[G[_, _]]( nt: F ~~> G ): SchemaF[Prim, SumTermId, ProductTermId, G, RSum[RA, A, RB, B], A / B] = } ...
  • 84. trait Interpreter[F[_, _], F[_, _]] { self => def interpret: F ~~> G def compose[H[_, _]](nt: H ~~> F) = self match { case i: ComposedInterpreter[h, G, F] => ComposedInterpreter(i.underlying, i.nt.compose(nt)) case x => ComposedInterpreter(x, nt) } }
  • 85. implicit final def encoderInterpreter( implicit primNT: R.Prim ~> EncoderA, fieldLabel: R.ProductTermId <~< String, branchLabel: R.SumTermId <~< String ): RInterpreter[Encoder] = Interpreter.cata[RSchema, Encoder](new (RSchema[Encoder, ?, ?] ~~> Encoder) { //Implementation of Schema to Encoder here })
  • 86. case p: RPrim[Encoder, a] => primNT(p.prim) case ProdF(left, right) => (a => left(a._1) + "," + right(a._2)) case SumF(left, right) => (a => a.fold(left, right)) case i: IsoSchema[Encoder, r, _, a] => i.base.compose(i.iso.reverseGet) case r: Record[Encoder, r, _, a] => encloseInBraces.compose(r.fields).compose(r.iso.reverseGet) case SeqF(element) => (a => a.map(element).mkString("[", ",", "]")) case FieldF(id, base) => makeField(fieldLabel(id)).compose(base) case u: Union[Encoder, r, _, a] => encloseInBraces.compose(u.choices).compose(u.iso.reverseGet) case BranchF(id, base) => makeField(branchLabel(id)).compose(base) case One() => (_ => "null") case ref @ SelfReference(_, _) => (a => ref.unroll(a.asInstanceOf[A with Repr]))
  • 87. trait SchemaModule[R <: Realisation] { val R: R implicit final class SchemaSyntax[A](schema: Schema[A]) { def to[F[_, _]](implicit interpreter: RInterpreter[F]): F[_, A] } }
  • 88. val employeeEncoder:Encoder[Employee] = employeeSchema.to[Encoder]
  • 89.
  • 90.
  • 91.