21
Flexible Data Representation with Fixpoint Types Dave Cleaver January 24th, 2017

Flexible Data Representation with Fixpoint Types

Embed Size (px)

Citation preview

Page 1: Flexible Data Representation with Fixpoint Types

Flexible Data Representation with Fixpoint Types

Dave CleaverJanuary 24th, 2017

Page 2: Flexible Data Representation with Fixpoint Types

2

Some Simple Datacase class Employee(first: String, last: String, manages: List[Employee] = List.empty)

Page 3: Flexible Data Representation with Fixpoint Types

3

Some Simple Datacase class Employee(first: String, last: String, manages: List[Employee] = List.empty)

Employee("Nina", "McInroe", List( Employee("Bill", "Lumbergh", List( Employee("Peter", "Gibbons"), Employee("Samir", "Nagheenanajar"), Employee("Michael", "Bolton"))), Employee("Dom", "Portwood")))

Page 4: Flexible Data Representation with Fixpoint Types

4

Storing Employeescase class StoredEmployee (first: String, last: String, manages: List[String] = List.empty)

Page 5: Flexible Data Representation with Fixpoint Types

5

Storing Employeescase class StoredEmployee (first: String, last: String, manages: List[String] = List.empty)

StoredEmployee("Nina", "McInroe", List("blumbergh", "dportwood"))StoredEmployee("Bill", "Lumbergh", List("pgibbons", "snagheenanajar", "mbolton"))StoredEmployee("Peter", "Gibbons")StoredEmployee("Samir", "Nagheenanajar") StoredEmployee("Michael", "Bolton") StoredEmployee("Dom", "Portwood")

Page 6: Flexible Data Representation with Fixpoint Types

6

Abstract out the Typecase class EmployeeF[A](first: String, last: String, manages: List[A] = List.empty)

Page 7: Flexible Data Representation with Fixpoint Types

7

Works for the Simple Typetype StoredEmployee = EmployeeF[String]

Page 8: Flexible Data Representation with Fixpoint Types

8

Works for the Simple Typetype StoredEmployee = EmployeeF[String]

EmployeeF("Nina", "McInroe", List("blumbergh", "dportwood"))EmployeeF("Bill", "Lumbergh", List("pgibbons", "snagheenanajar", "mbolton"))EmployeeF("Peter", "Gibbons")EmployeeF("Samir", "Nagheenanajar") EmployeeF("Michael", "Bolton") EmployeeF("Dom", "Portwood")

Page 9: Flexible Data Representation with Fixpoint Types

9

But the Recursive Type…type Employee = EmployeeF[EmployeeF[EmployeeF[...]]]

Page 10: Flexible Data Representation with Fixpoint Types

10

Generalized Recursion at the Value Leveldef fix[A](f: (=> A) => A): A = { lazy val a: A = f(a) a }

Page 11: Flexible Data Representation with Fixpoint Types

11

Generalized Recursion at the Value Leveldef fix[A](f: (=> A) => A): A = { lazy val a: A = f(a) a }

val factorial = fix[Int => Int](factorial => n => { if(n == 1) 1 else n * factorial.apply(n - 1) } )

Page 12: Flexible Data Representation with Fixpoint Types

12

Fix at the Type Levelcase class Fix[F[_]](unfix: F[Fix[F]])

Page 13: Flexible Data Representation with Fixpoint Types

13

Employee Fixedtype Employee = Fix[EmployeeF]

Page 14: Flexible Data Representation with Fixpoint Types

14

Employee Fixedtype Employee = Fix[EmployeeF]

Fix[EmployeeF](EmployeeF("Nina", "McInroe", List(Fix(EmployeeF("Bill", "Lumbergh", List( Fix(EmployeeF("Peter", "Gibbons")), Fix(EmployeeF("Samir", "Nagheenanajar")), Fix(EmployeeF("Michael", "Bolton"))))), Fix(EmployeeF("Dom", "Portwood"))))

Page 15: Flexible Data Representation with Fixpoint Types

15

Simple JSON Encodingimplicit def encodeEmployee[A: Encoder]: Encoder[EmployeeF[A]] = Encoder.forProduct3("first", "last", "manages")(e =>

(e.first, e.last, e.manages))

Page 16: Flexible Data Representation with Fixpoint Types

16

Encoding Fixdef encodeFix[F[_]](fEncoder: Encoder[Fix[F]] => Encoder[F[Fix[F]]]): Encoder[Fix[F]] = new Encoder[Fix[F]] { final def apply(fixF: Fix[F]) = fEncoder(this).apply(fixF.unfix) }

Page 17: Flexible Data Representation with Fixpoint Types

17

Encoding Fixdef encodeFix[F[_]](fEncoder: Encoder[Fix[F]] => Encoder[F[Fix[F]]]): Encoder[Fix[F]] = new Encoder[Fix[F]] { final def apply(fixF: Fix[F]) = fEncoder(this).apply(fixF.unfix) }

implicit val fixedEncoder = encodeFix(encodeEmployee(_: Encoder[Fix[EmployeeF]]))

Page 18: Flexible Data Representation with Fixpoint Types

18

EmployeeF is a Functorimplicit object EmployeeFunctor extends Functor[EmployeeF] { def map[A, B](fa: EmployeeF[A])(f: A => B): EmployeeF[B] = fa.copy(manages = fa.manages.map(f)) }

Page 19: Flexible Data Representation with Fixpoint Types

19

Programs and Datatype EmployeeTask[A] = Task[EmployeeF[A]]

def fetch(id: String): EmployeeTask[String] = ???

Page 20: Flexible Data Representation with Fixpoint Types

20

Programs and Datatype EmployeeTask[A] = Task[EmployeeF[A]]

def fetch(id: String): EmployeeTask[String] = ???

def loadEmployee(id: String): Fix[EmployeeTask] = Fix[EmployeeTask](fetch(id).map(_.map(loadEmployee)))

Page 21: Flexible Data Representation with Fixpoint Types

21

Flexible Data Representation with Fixpoint Types

• Abstract your data- Reduce duplicate data types- While gaining extra power

• Other useful Recursive Types- case class Free[F[_], A](run: Either[A, F[Free[F, A]])- case class Cofree[F[_], A](head: A, tail: F[Cofree[F, A]])

• Twitter: @dscleaver