SlideShare a Scribd company logo
1 of 93
Download to read offline
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 1Hang Zhao
 
Refactoring Functional Type Classes
Refactoring Functional Type ClassesRefactoring Functional Type Classes
Refactoring Functional Type ClassesJohn 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 FreeKelley Robinson
 
Principled Error Handling with FP
Principled Error Handling with FPPrincipled Error Handling with FP
Principled Error Handling with FPLuka Jacobowitz
 
Type classes 101 - classification beyond inheritance
Type classes 101 - classification beyond inheritanceType classes 101 - classification beyond inheritance
Type classes 101 - classification beyond inheritanceAlexey Raga
 
Effective way to code in Scala
Effective way to code in ScalaEffective way to code in Scala
Effective way to code in ScalaKnoldus Inc.
 
Type Parameterization
Type ParameterizationType Parameterization
Type ParameterizationKnoldus Inc.
 
Writing DSL with Applicative Functors
Writing DSL with Applicative FunctorsWriting DSL with Applicative Functors
Writing DSL with Applicative FunctorsDavid Galichet
 
Functions In Scala
Functions In Scala Functions In Scala
Functions In Scala Knoldus Inc.
 
Deriving Scalaz
Deriving ScalazDeriving Scalaz
Deriving Scalaznkpart
 
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 ProgrammingLuka 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 traverseLuka 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 202Mahmoud 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 2009David Pollak
 
Python programming workshop session 3
Python programming workshop session 3Python programming workshop session 3
Python programming workshop session 3Abdul Haseeb
 
Scala Functional Patterns
Scala Functional PatternsScala Functional Patterns
Scala Functional Patternsleague
 
Functional Programming In Java
Functional Programming In JavaFunctional Programming In Java
Functional Programming In JavaAndrei 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 Concernssaintiss
 
Go ahead, make my day
Go ahead, make my dayGo ahead, make my day
Go ahead, make my dayTor Ivry
 
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).pdfCentral university of Haryana
 
The Essence of the Iterator Pattern
The Essence of the Iterator PatternThe Essence of the Iterator Pattern
The Essence of the Iterator PatternEric Torreborre
 
Post-Free: Life After Free Monads
Post-Free: Life After Free MonadsPost-Free: Life After Free Monads
Post-Free: Life After Free MonadsJohn De Goes
 
Imugi: Compiler made with Python
Imugi: Compiler made with PythonImugi: Compiler made with Python
Imugi: Compiler made with PythonHan Lee
 
Deep learning study 3
Deep learning study 3Deep learning study 3
Deep learning study 3San Kim
 

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

EY_Graph Database Powered Sustainability
EY_Graph Database Powered SustainabilityEY_Graph Database Powered Sustainability
EY_Graph Database Powered SustainabilityNeo4j
 
Automate your Kamailio Test Calls - Kamailio World 2024
Automate your Kamailio Test Calls - Kamailio World 2024Automate your Kamailio Test Calls - Kamailio World 2024
Automate your Kamailio Test Calls - Kamailio World 2024Andreas Granig
 
What is Fashion PLM and Why Do You Need It
What is Fashion PLM and Why Do You Need ItWhat is Fashion PLM and Why Do You Need It
What is Fashion PLM and Why Do You Need ItWave PLM
 
Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)OPEN KNOWLEDGE GmbH
 
Cloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEECloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEEVICTOR MAESTRE RAMIREZ
 
The Evolution of Karaoke From Analog to App.pdf
The Evolution of Karaoke From Analog to App.pdfThe Evolution of Karaoke From Analog to App.pdf
The Evolution of Karaoke From Analog to App.pdfPower Karaoke
 
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...soniya singh
 
Implementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with AzureImplementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with AzureDinusha Kumarasiri
 
Folding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth in a seriesFolding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth in a seriesPhilip Schwarz
 
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASEBATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASEOrtus Solutions, Corp
 
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...MyIntelliSource, Inc.
 
Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...OnePlan Solutions
 
Salesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantSalesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantAxelRicardoTrocheRiq
 
Professional Resume Template for Software Developers
Professional Resume Template for Software DevelopersProfessional Resume Template for Software Developers
Professional Resume Template for Software DevelopersVinodh Ram
 
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer DataAdobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer DataBradBedford3
 
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样umasea
 
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...gurkirankumar98700
 
MYjobs Presentation Django-based project
MYjobs Presentation Django-based projectMYjobs Presentation Django-based project
MYjobs Presentation Django-based projectAnoyGreter
 

Recently uploaded (20)

EY_Graph Database Powered Sustainability
EY_Graph Database Powered SustainabilityEY_Graph Database Powered Sustainability
EY_Graph Database Powered Sustainability
 
Automate your Kamailio Test Calls - Kamailio World 2024
Automate your Kamailio Test Calls - Kamailio World 2024Automate your Kamailio Test Calls - Kamailio World 2024
Automate your Kamailio Test Calls - Kamailio World 2024
 
What is Fashion PLM and Why Do You Need It
What is Fashion PLM and Why Do You Need ItWhat is Fashion PLM and Why Do You Need It
What is Fashion PLM and Why Do You Need It
 
Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)
 
Cloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEECloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEE
 
The Evolution of Karaoke From Analog to App.pdf
The Evolution of Karaoke From Analog to App.pdfThe Evolution of Karaoke From Analog to App.pdf
The Evolution of Karaoke From Analog to App.pdf
 
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
 
Implementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with AzureImplementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with Azure
 
Call Girls In Mukherjee Nagar 📱 9999965857 🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...
Call Girls In Mukherjee Nagar 📱  9999965857  🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...Call Girls In Mukherjee Nagar 📱  9999965857  🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...
Call Girls In Mukherjee Nagar 📱 9999965857 🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...
 
Folding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth in a seriesFolding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth in a series
 
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASEBATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
 
Hot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort Service
Hot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort ServiceHot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort Service
Hot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort Service
 
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
 
Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...
 
Salesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantSalesforce Certified Field Service Consultant
Salesforce Certified Field Service Consultant
 
Professional Resume Template for Software Developers
Professional Resume Template for Software DevelopersProfessional Resume Template for Software Developers
Professional Resume Template for Software Developers
 
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer DataAdobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
 
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
 
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
 
MYjobs Presentation Django-based project
MYjobs Presentation Django-based projectMYjobs Presentation Django-based project
MYjobs Presentation Django-based project
 

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.