Successfully reported this slideshow.

Going bananas with recursion schemes for fixed point data types

5

Share

Upcoming SlideShare
Recursion schemes in Scala
Recursion schemes in Scala
Loading in …3
×
1 of 147
1 of 147

More Related Content

Related Books

Free with a 14 day trial from Scribd

See all

Related Audiobooks

Free with a 14 day trial from Scribd

See all

Going bananas with recursion schemes for fixed point data types

  1. 1. “Going bananas with recursion schemes for fixed point data types” Pawel Szulc email: paul.szulc@gmail.com twitter: @rabbitonweb github: https://github.com/rabbitonweb/
  2. 2. Software Engineering
  3. 3. Software engineering “In late 1967 the Study Group recommended the holding of a working conference on Software Engineering. The phrase ‘software engineering’ was deliberately chosen as being provocative, in implying the need for software manufacture to be based on the types of theoretical foundations and practical disciplines, that are traditional in the established branches of engineering.” [NATO68]
  4. 4. Elegance of Functional Programming “Programming notation can be expressed by “formulæ and equations (...) which share the elegance of those which underlie physics and chemistry or any other branch of basic science”. -- [BdM97]
  5. 5. Recursion “Recursion is where Functional Programming hits the bottom” - Greg Pfeil
  6. 6. Recursion Schemes “Functional Programming with Bananas, Lenses, Envelopes and Barbed Wire” by Erik Meijer Maarten, Maarten Fokkinga and Ross Paterson [MFP91]
  7. 7. Recursion Schemes “Functional Programming with Bananas, Lenses, Envelopes and Barbed Wire” by Erik Meijer Maarten, Maarten Fokkinga and Ross Paterson [MFP91] Describes: ● Simple, composable combinators (recursion schemes) ● Process of traversing recursive structures
  8. 8. Real world application https://github.com/quasar-analytics/quasar https://github.com/slamdata/matryoshka
  9. 9. Recursive Structures are common
  10. 10. Recursive Structures are common ● Simplest examples ○ List: ■ Cons(a, List) ■ Nil ○ Binary Tree ■ Node(a, Tree, Tree) ■ Leaf(a)
  11. 11. Recursive Structures are common ● Simplest examples ○ List: ■ Cons(a, List) ■ Nil ○ Binary Tree ■ Node(a, Tree, Tree) ■ Leaf(a) ● To name few examples: ○ File systems ○ 3D Graphics ○ Databases
  12. 12. Recursive Structures are common ● Simplest examples ○ List: ■ Cons(a, List) ■ Nil ○ Binary Tree ■ Node(a, Tree, Tree) ■ Leaf(a) ● To name few examples: ○ File systems ○ 3D Graphics ○ Databases ● Any nested, inductively defined type
  13. 13. Expressions! Our example 102 + 20.5 * 14.5
  14. 14. Expressions! Sum ( Square( IntValue(10) ) Multiply( DecValue(20.5), DecValue(14.5) ), ) Our example 102 + 20.5 * 14.5
  15. 15. Expressions! Sum ( Square( IntValue(10) ) Multiply( DecValue(20.5), DecValue(14.5) ), ) Our example 102 + 20.5 * 14.5
  16. 16. Expressions! Sum ( Square( IntValue(10) ) Multiply( DecValue(20.5), DecValue(14.5) ), ) Our example 102 + 20.5 * 14.5
  17. 17. Expressions! Sum ( Square( IntValue(10) ) Multiply( DecValue(20.5), DecValue(14.5) ), ) Our example 102 + 20.5 * 14.5
  18. 18. Expressions! Sum ( Square( IntValue(10) ) Multiply( DecValue(20.5), DecValue(14.5) ), ) Our example 102 + 20.5 * 14.5
  19. 19. Expressions! Sum ( Square( IntValue(10) ) Multiply( DecValue(20.5), DecValue(14.5) ), Our example 102 + 20.5 * 14.5
  20. 20. Expressions! Sum ( Square( IntValue(10) ) Multiply( DecValue(20.5), DecValue(14.5) ), ) Our example 102 + 20.5 * 14.5
  21. 21. Expressions! Square ( Sum ( Square( IntValue(10) ) Multiply( DecValue(20.5), DecValue(14.5) ), ) ) Our example (102 + 20.5 * 14.5)2
  22. 22. Expressions! Our example (102 + 20.5 * 14.5)2 Square Sum Square 10 Multiply 10 10
  23. 23. data Exp = IntVal Int | DecVal Double | Sum Exp Exp | Multiply Exp Exp | Divide Exp Exp | Square Exp
  24. 24. data Exp = IntVal Int | DecVal Double | Sum Exp Exp | Multiply Exp Exp | Divide Exp Exp | Square Exp sealed trait Exp final case class IntValue(v: Int) extends Exp final case class DecValue(v: Double) extends Exp final case class Sum(exp1: Exp, exp2: Exp) extends Exp final case class Multiply(exp1: Exp, exp2: Exp) extends Exp final case class Divide(exp1: Exp, exp2: Exp) extends Exp final case class Square(exp: Exp) extends Exp
  25. 25. data Exp = IntVal Int | DecVal Double | Sum Exp Exp | Multiply Exp Exp | Divide Exp Exp | Square Exp sealed trait Exp final case class IntValue(v: Int) extends Exp final case class DecValue(v: Double) extends Exp final case class Sum(exp1: Exp, exp2: Exp) extends Exp final case class Multiply(exp1: Exp, exp2: Exp) extends Exp final case class Divide(exp1: Exp, exp2: Exp) extends Exp final case class Square(exp: Exp) extends Exp
  26. 26. sealed trait Exp final case class IntValue(v: Int) extends Exp final case class DecValue(v: Double) extends Exp final case class Sum(exp1: Exp, exp2: Exp) extends Exp final case class Multiply(exp1: Exp, exp2: Exp) extends Exp final case class Divide(exp1: Exp, exp2: Exp) extends Exp final case class Square(exp: Exp) extends Exp val evaluate: Exp => Double =
  27. 27. sealed trait Exp final case class IntValue(v: Int) extends Exp final case class DecValue(v: Double) extends Exp final case class Sum(exp1: Exp, exp2: Exp) extends Exp final case class Multiply(exp1: Exp, exp2: Exp) extends Exp final case class Divide(exp1: Exp, exp2: Exp) extends Exp final case class Square(exp: Exp) extends Exp val evaluate: Exp => Double = { case IntValue(v) => v.toDouble case DecValue(v) => v case Sum(exp1, exp2) => evaluate(exp1) + evaluate(exp2) case Multiply(exp1, exp2) => evaluate(exp1) * evaluate(exp2) case Square(exp) => val v = evaluate(exp) v * v case Divide(exp1, exp2) => evaluate(exp1) / evaluate(exp2) }
  28. 28. sealed trait Exp final case class IntValue(v: Int) extends Exp final case class DecValue(v: Double) extends Exp final case class Sum(exp1: Exp, exp2: Exp) extends Exp final case class Multiply(exp1: Exp, exp2: Exp) extends Exp final case class Divide(exp1: Exp, exp2: Exp) extends Exp final case class Square(exp: Exp) extends Exp val mkString: Exp => String = { case IntValue(v) => v.toString case DecValue(v) => v.toString case Sum(exp1, exp2) => s"( ${mkStr(exp1)} + ${mkStr(exp2)})" case Multiply(exp1, exp2) => s"( ${mkStr(exp1)} * ${mkStr(exp2)})" case Square(exp) => s"(${mkStr(exp)})^2" case Divide(exp1, exp2) => s"( ${mkStr(exp1)} / ${mkStr(exp2)})" }
  29. 29. sealed trait Exp final case class IntValue(v: Int) extends Exp final case class DecValue(v: Double) extends Exp final case class Sum(exp1: Exp, exp2: Exp) extends Exp final case class Multiply(exp1: Exp, exp2: Exp) extends Exp final case class Divide(exp1: Exp, exp2: Exp) extends Exp final case class Square(exp: Exp) extends Exp val optimize: Exp => Exp = { case Multiply(exp1, exp2) if(exp1 == exp2) => Square(optimize(exp1))
  30. 30. sealed trait Exp final case class IntValue(v: Int) extends Exp final case class DecValue(v: Double) extends Exp final case class Sum(exp1: Exp, exp2: Exp) extends Exp final case class Multiply(exp1: Exp, exp2: Exp) extends Exp final case class Divide(exp1: Exp, exp2: Exp) extends Exp final case class Square(exp: Exp) extends Exp val optimize: Exp => Exp = { case Multiply(exp1, exp2) if(exp1 == exp2) => Square(optimize(exp1)) case IntValue(v) => IntValue(v) case DecValue(v) => DecValue(v) case Sum(exp1, exp2) => Sum(optimize(exp1), optimize(exp2)) case Multiply(exp1, exp2) => Multiply(optimize(exp1), optimize(exp2)) case Square(exp) => Square(optimize(exp)) case Divide(exp1, exp2) => Divide(optimize(exp1), optimize(exp2)) }
  31. 31. sealed trait Exp final case class IntValue(v: Int) extends Exp final case class DecValue(v: Double) extends Exp final case class Sum(exp1: Exp, exp2: Exp) extends Exp final case class Multiply(exp1: Exp, exp2: Exp) extends Exp final case class Divide(exp1: Exp, exp2: Exp) extends Exp final case class Square(exp: Exp) extends Exp val optimize: Exp => Exp = { case Multiply(exp1, exp2) if(exp1 == exp2) => Square(optimize(exp1)) case IntValue(v) => IntValue(v) case DecValue(v) => DecValue(v) case Sum(exp1, exp2) => Sum(optimize(exp1), optimize(exp2)) case Multiply(exp1, exp2) => Multiply(exp1, optimize(exp2)) case Square(exp) => Square(optimize(exp)) case Divide(exp1, exp2) => Divide(optimize(exp1), optimize(exp2)) }
  32. 32. sealed trait Exp final case class IntValue(v: Int) extends Exp final case class DecValue(v: Double) extends Exp final case class Sum(exp1: Exp, exp2: Exp) extends Exp final case class Multiply(exp1: Exp, exp2: Exp) extends Exp final case class Divide(exp1: Exp, exp2: Exp) extends Exp final case class Square(exp: Exp) extends Exp val optimize: Exp => Exp = { case Multiply(exp1, exp2) if(exp1 == exp2) => Square(optimize(exp1)) case IntValue(v) => optimize(IntValue(v)) case DecValue(v) => optimize(DecValue(v)) case Sum(exp1, exp2) => Sum(optimize(exp1), optimize(exp2)) case Multiply(exp1, exp2) => Multiply(optimize(exp1), optimize(exp2)) case Square(exp) => Square(optimize(exp)) case Divide(exp1, exp2) => Divide(optimize(exp1), optimize(exp2)) }
  33. 33. val evaluate: Exp => Double = { case IntValue(v) => v.toDouble case DecValue(v) => v case Sum(exp1, exp2) => evaluate(exp1) + evaluate(exp2) case Multiply(exp1, exp2) => evaluate(exp1) * evaluate(exp2) case Square(exp) => val v = evaluate(exp) v * v case Divide(exp1, exp2) => evaluate(exp1) / evaluate(exp2) } val exp = Multiply( Sum(IntValue(10), DecValue(2.5)), Divide(DecValue(5.2), Sum(IntValue(10), IntValue(5)) ) ) Multiply Sum Divide Int(10) Dec(2.5) Dec(5.2) Sum Int(10) Int(5)
  34. 34. val evaluate: Exp => Double = { case IntValue(v) => v.toDouble case DecValue(v) => v case Sum(exp1, exp2) => evaluate(exp1) + evaluate(exp2) case Multiply(exp1, exp2) => evaluate(exp1) * evaluate(exp2) case Square(exp) => val v = evaluate(exp) v * v case Divide(exp1, exp2) => evaluate(exp1) / evaluate(exp2) } val exp = Multiply( Sum(IntValue(10), DecValue(2.5)), Divide(DecValue(5.2), Sum(IntValue(10), IntValue(5)) ) ) Multiply Sum Divide Int(10) Dec(2.5) Dec(5.2) Sum Int(10) Int(5)
  35. 35. val evaluate: Exp => Double = { case IntValue(v) => v.toDouble case DecValue(v) => v case Sum(exp1, exp2) => evaluate(exp1) + evaluate(exp2) case Multiply(exp1, exp2) => evaluate(exp1) * evaluate(exp2) case Square(exp) => val v = evaluate(exp) v * v case Divide(exp1, exp2) => evaluate(exp1) / evaluate(exp2) } val exp = Multiply( Sum(IntValue(10), DecValue(2.5)), Divide(DecValue(5.2), Sum(IntValue(10), IntValue(5)) ) ) Multiply Sum Divide Int(10) Dec(2.5) Dec(5.2) Sum Int(10) Int(5)
  36. 36. val evaluate: Exp => Double = { case IntValue(v) => v.toDouble case DecValue(v) => v case Sum(exp1, exp2) => evaluate(exp1) + evaluate(exp2) case Multiply(exp1, exp2) => evaluate(exp1) * evaluate(exp2) case Square(exp) => val v = evaluate(exp) v * v case Divide(exp1, exp2) => evaluate(exp1) / evaluate(exp2) } val exp = Multiply( Sum(IntValue(10), DecValue(2.5)), Divide(DecValue(5.2), Sum(IntValue(10), IntValue(5)) ) ) Multiply Sum Divide Int(10) Dec(2.5) Dec(5.2) Sum Int(10) Int(5)
  37. 37. val evaluate: Exp => Double = { case IntValue(v) => v.toDouble case DecValue(v) => v case Sum(exp1, exp2) => evaluate(exp1) + evaluate(exp2) case Multiply(exp1, exp2) => evaluate(exp1) * evaluate(exp2) case Square(exp) => val v = evaluate(exp) v * v case Divide(exp1, exp2) => evaluate(exp1) / evaluate(exp2) } val exp = Multiply( Sum(IntValue(10), DecValue(2.5)), Divide(DecValue(5.2), Sum(IntValue(10), IntValue(5)) ) ) Multiply Sum Divide Int(10) Dec(2.5) Dec(5.2) Sum Int(10) Int(5)
  38. 38. val evaluate: Exp => Double = { case IntValue(v) => v.toDouble case DecValue(v) => v case Sum(exp1, exp2) => evaluate(exp1) + evaluate(exp2) case Multiply(exp1, exp2) => evaluate(exp1) * evaluate(exp2) case Square(exp) => val v = evaluate(exp) v * v case Divide(exp1, exp2) => evaluate(exp1) / evaluate(exp2) } val exp = Multiply( Sum(IntValue(10), DecValue(2.5)), Divide(DecValue(5.2), Sum(IntValue(10), IntValue(5)) ) ) Multiply Sum Divide Int(10) Dec(2.5) Dec(5.2) Sum Int(10) Int(5)
  39. 39. val evaluate: Exp => Double = { case IntValue(v) => v.toDouble case DecValue(v) => v case Sum(exp1, exp2) => evaluate(exp1) + evaluate(exp2) case Multiply(exp1, exp2) => evaluate(exp1) * evaluate(exp2) case Square(exp) => val v = evaluate(exp) v * v case Divide(exp1, exp2) => evaluate(exp1) / evaluate(exp2) } val exp = Multiply( Sum(IntValue(10), DecValue(2.5)), Divide(DecValue(5.2), Sum(IntValue(10), IntValue(5)) ) ) Multiply Sum Divide Int(10) Dec(2.5) Dec(5.2) Sum Int(10) Int(5)
  40. 40. val evaluate: Exp => Double = { case IntValue(v) => v.toDouble case DecValue(v) => v case Sum(exp1, exp2) => evaluate(exp1) + evaluate(exp2) case Multiply(exp1, exp2) => evaluate(exp1) * evaluate(exp2) case Square(exp) => val v = evaluate(exp) v * v case Divide(exp1, exp2) => evaluate(exp1) / evaluate(exp2) } val exp = Multiply( Sum(IntValue(10), DecValue(2.5)), Divide(DecValue(5.2), Sum(IntValue(10), IntValue(5)) ) ) Multiply Sum Divide Int(10) Dec(2.5) Dec(5.2) Sum Int(10) Int(5)
  41. 41. val evaluate: Exp => Double = { case IntValue(v) => v.toDouble case DecValue(v) => v case Sum(exp1, exp2) => evaluate(exp1) + evaluate(exp2) case Multiply(exp1, exp2) => evaluate(exp1) * evaluate(exp2) case Square(exp) => val v = evaluate(exp) v * v case Divide(exp1, exp2) => evaluate(exp1) / evaluate(exp2) } val exp = Multiply( Sum(IntValue(10), DecValue(2.5)), Divide(DecValue(5.2), Sum(IntValue(10), IntValue(5)) ) ) Multiply Sum Divide Int(10) Dec(2.5) Dec(5.2) Sum Int(10) Int(5)
  42. 42. val evaluate: Exp => Double = { case IntValue(v) => v.toDouble case DecValue(v) => v case Sum(exp1, exp2) => evaluate(exp1) + evaluate(exp2) case Multiply(exp1, exp2) => evaluate(exp1) * evaluate(exp2) case Square(exp) => val v = evaluate(exp) v * v case Divide(exp1, exp2) => evaluate(exp1) / evaluate(exp2) } val exp = Multiply( Sum(IntValue(10), DecValue(2.5)), Divide(DecValue(5.2), Sum(IntValue(10), IntValue(5)) ) ) Multiply Sum Divide Int(10) Dec(2.5) Dec(5.2) Sum Int(10) Int(5)
  43. 43. val evaluate: Exp => Double = { case IntValue(v) => v.toDouble case DecValue(v) => v case Sum(exp1, exp2) => evaluate(exp1) + evaluate(exp2) case Multiply(exp1, exp2) => evaluate(exp1) * evaluate(exp2) case Square(exp) => val v = evaluate(exp) v * v case Divide(exp1, exp2) => evaluate(exp1) / evaluate(exp2) } val exp = Multiply( Sum(IntValue(10), DecValue(2.5)), Divide(DecValue(5.2), Sum(IntValue(10), IntValue(5)) ) ) Multiply Sum Divide Int(10) Dec(2.5) Dec(5.2) Sum Int(10) Int(5)
  44. 44. val evaluate: Exp => Double = { case IntValue(v) => v.toDouble case DecValue(v) => v case Sum(exp1, exp2) => evaluate(exp1) + evaluate(exp2) case Multiply(exp1, exp2) => evaluate(exp1) * evaluate(exp2) case Square(exp) => val v = evaluate(exp) v * v case Divide(exp1, exp2) => evaluate(exp1) / evaluate(exp2) } val exp = Multiply( Sum(IntValue(10), DecValue(2.5)), Divide(DecValue(5.2), Sum(IntValue(10), IntValue(5)) ) ) Multiply Sum Divide Int(10) Dec(2.5) Dec(5.2) Sum Int(10) Int(5)
  45. 45. val evaluate: Exp => Double = { case IntValue(v) => v.toDouble case DecValue(v) => v case Sum(exp1, exp2) => evaluate(exp1) + evaluate(exp2) case Multiply(exp1, exp2) => evaluate(exp1) * evaluate(exp2) case Square(exp) => val v = evaluate(exp) v * v case Divide(exp1, exp2) => evaluate(exp1) / evaluate(exp2) } val exp = Multiply( Sum(IntValue(10), DecValue(2.5)), Divide(DecValue(5.2), Sum(IntValue(10), IntValue(5)) ) ) Multiply Sum Divide Int(10) Dec(2.5) Dec(5.2) Sum Int(10) Int(5)
  46. 46. val evaluate: Exp => Double = { case IntValue(v) => v.toDouble case DecValue(v) => v case Sum(exp1, exp2) => evaluate(exp1) + evaluate(exp2) case Multiply(exp1, exp2) => evaluate(exp1) * evaluate(exp2) case Square(exp) => val v = evaluate(exp) v * v case Divide(exp1, exp2) => evaluate(exp1) / evaluate(exp2) } val exp = Multiply( Sum(IntValue(10), DecValue(2.5)), Divide(DecValue(5.2), Sum(IntValue(10), IntValue(5)) ) ) Multiply Sum Divide Int(10) Dec(2.5) Dec(5.2) Sum Int(10) Int(5)
  47. 47. val mkString: Exp => String = { case IntValue(v) => v.toString case DecValue(v) => v.toString case Sum(exp1, exp2) => s"(${mkStr(exp1)} + ${mkStr(exp2)})" case Multiply(exp1, exp2) => s"(${mkStr(exp1)} * ${mkStr(exp2)})" case Square(exp) => s"(${mkStr(exp)})^2" case Divide(exp1, exp2) => s"( ${mkStr(exp1)} / ${mkStr(exp2)})" } val exp = Multiply( Sum(IntValue(10), DecValue(2.5)), Divide(DecValue(5.2), Sum(IntValue(10), IntValue(5)) ) ) Multiply Sum Divide Int(10) Dec(2.5) Dec(5.2) Sum Int(10) Int(5)
  48. 48. val evaluate: Exp => Double = { case IntValue(v) => v.toDouble case DecValue(v) => v case Sum(exp1, exp2) => evaluate(exp1) + evaluate(exp2) case Multiply(exp1, exp2) => evaluate(exp1) * evaluate(exp2) case Square(exp) => val v = evaluate(exp) v * v case Divide(exp1, exp2) => evaluate(exp1) / evaluate(exp2) } val exp = Multiply( Sum(IntValue(10), DecValue(2.5)), Divide(DecValue(5.2), Sum(IntValue(10), IntValue(5)) ) ) Multiply Sum Divide Int(10) Dec(2.5) Dec(5.2) Sum Int(10) Int(5)
  49. 49. sealed trait Exp final case class IntValue(v: Int) extends Exp final case class DecValue(v: Double) extends Exp final case class Sum(exp1: Exp, exp2: Exp) extends Exp final case class Multiply(exp1: Exp, exp2: Exp) extends Exp final case class Divide(exp1: Exp, exp2: Exp) extends Exp final case class Square(exp: Exp) extends Exp
  50. 50. sealed trait Exp final case class IntValue(v: Int) extends Exp final case class DecValue(v: Double) extends Exp final case class Sum(exp1: Exp, exp2: Exp) extends Exp final case class Multiply(exp1: Exp, exp2: Exp) extends Exp final case class Divide(exp1: Exp, exp2: Exp) extends Exp final case class Square(exp: Exp) extends Exp sealed trait Exp[A] final case class IntValue[A](v: Int) extends Exp[A] final case class DecValue[A](v: Double) extends Exp[A] final case class Sum[A](exp1: A, exp2: A) extends Exp[A] final case class Multiply[A](exp1: A, exp2: A) extends Exp[A] final case class Divide[A](exp1: A, exp2: A) extends Exp[A] final case class Square[A](exp: A) extends Exp[A]
  51. 51. sealed trait Exp[A] final case class IntValue[A](v: Int) extends Exp[A] final case class DecValue[A](v: Double) extends Exp[A] final case class Sum[A](exp1: A, exp2: A) extends Exp[A] final case class Multiply[A](exp1: A, exp2: A) extends Exp[A] final case class Divide[A](exp1: A, exp2: A) extends Exp[A] final case class Square[A](exp: A) extends Exp[A] val exp1: Exp = Sum(IntValue(10), IntValue(5)) ) val exp1: Exp[?] = Sum[?](IntValue[?](10), IntValue[?](5)) )
  52. 52. sealed trait Exp[A] final case class IntValue[A](v: Int) extends Exp[A] final case class DecValue[A](v: Double) extends Exp[A] final case class Sum[A](exp1: A, exp2: A) extends Exp[A] final case class Multiply[A](exp1: A, exp2: A) extends Exp[A] final case class Divide[A](exp1: A, exp2: A) extends Exp[A] final case class Square[A](exp: A) extends Exp[A] val exp1: Exp = Sum(IntValue(10), IntValue(5)) ) val exp1: Exp[?] = Sum[?](IntValue[Unit](10), IntValue[Unit](5)) )
  53. 53. sealed trait Exp[A] final case class IntValue[A](v: Int) extends Exp[A] final case class DecValue[A](v: Double) extends Exp[A] final case class Sum[A](exp1: A, exp2: A) extends Exp[A] final case class Multiply[A](exp1: A, exp2: A) extends Exp[A] final case class Divide[A](exp1: A, exp2: A) extends Exp[A] final case class Square[A](exp: A) extends Exp[A] val exp1: Exp = Sum(IntValue(10), IntValue(5)) ) val exp1: Exp[?] = Sum[?](IntValue[Unit](10), IntValue[Unit](5)) ) Exp[Unit]
  54. 54. sealed trait Exp[A] final case class IntValue[A](v: Int) extends Exp[A] final case class DecValue[A](v: Double) extends Exp[A] final case class Sum[A](exp1: A, exp2: A) extends Exp[A] final case class Multiply[A](exp1: A, exp2: A) extends Exp[A] final case class Divide[A](exp1: A, exp2: A) extends Exp[A] final case class Square[A](exp: A) extends Exp[A] val exp1: Exp = Sum(IntValue(10), IntValue(5)) ) val exp1: Exp[?] = Sum[?](IntValue[Unit](10), IntValue[Unit](5)) ) Exp[Unit]
  55. 55. sealed trait Exp[A] final case class IntValue[A](v: Int) extends Exp[A] final case class DecValue[A](v: Double) extends Exp[A] final case class Sum[A](exp1: A, exp2: A) extends Exp[A] final case class Multiply[A](exp1: A, exp2: A) extends Exp[A] final case class Divide[A](exp1: A, exp2: A) extends Exp[A] final case class Square[A](exp: A) extends Exp[A] val exp1: Exp = Sum(IntValue(10), IntValue(5)) ) val exp1: Exp[?] = Sum[?](IntValue[Unit](10), IntValue[Unit](5)) )
  56. 56. sealed trait Exp[A] final case class IntValue[A](v: Int) extends Exp[A] final case class DecValue[A](v: Double) extends Exp[A] final case class Sum[A](exp1: A, exp2: A) extends Exp[A] final case class Multiply[A](exp1: A, exp2: A) extends Exp[A] final case class Divide[A](exp1: A, exp2: A) extends Exp[A] final case class Square[A](exp: A) extends Exp[A] val exp1: Exp = Sum(IntValue(10), IntValue(5)) ) val exp1: Exp[?] = Sum[Exp[Unit]](IntValue[Unit](10), IntValue[Unit](5)) )
  57. 57. sealed trait Exp[A] final case class IntValue[A](v: Int) extends Exp[A] final case class DecValue[A](v: Double) extends Exp[A] final case class Sum[A](exp1: A, exp2: A) extends Exp[A] final case class Multiply[A](exp1: A, exp2: A) extends Exp[A] final case class Divide[A](exp1: A, exp2: A) extends Exp[A] final case class Square[A](exp: A) extends Exp[A] val exp1: Exp = Sum(IntValue(10), IntValue(5)) ) val exp1: Exp[Exp[Unit]] = Sum[Exp[Unit]](IntValue[Unit](10), IntValue[Unit](5)) )
  58. 58. sealed trait Exp[A] final case class IntValue[A](v: Int) extends Exp[A] final case class DecValue[A](v: Double) extends Exp[A] final case class Sum[A](exp1: A, exp2: A) extends Exp[A] final case class Multiply[A](exp1: A, exp2: A) extends Exp[A] final case class Divide[A](exp1: A, exp2: A) extends Exp[A] final case class Square[A](exp: A) extends Exp[A] val exp1: Exp = Sum(IntValue(10), IntValue(5)) ) val exp2: Exp = Divide( DecValue(5.2), Sum(IntValue(10), IntValue(5)) ) ) val exp1: Exp[Exp[Unit]] = Sum[Exp[Unit]](IntValue[Unit](10), IntValue[Unit](5)) ) val exp2: Exp[?] = Divide[?]( DecValue[?](5.2), Sum[?](IntValue[?](10), IntValue[?](5)) ) )
  59. 59. sealed trait Exp[A] final case class IntValue[A](v: Int) extends Exp[A] final case class DecValue[A](v: Double) extends Exp[A] final case class Sum[A](exp1: A, exp2: A) extends Exp[A] final case class Multiply[A](exp1: A, exp2: A) extends Exp[A] final case class Divide[A](exp1: A, exp2: A) extends Exp[A] final case class Square[A](exp: A) extends Exp[A] val exp1: Exp = Sum(IntValue(10), IntValue(5)) ) val exp2: Exp = Divide( DecValue(5.2), Sum(IntValue(10), IntValue(5)) ) ) val exp1: Exp[Exp[Unit]] = Sum[Exp[Unit]](IntValue[Unit](10), IntValue[Unit](5)) ) val exp2: Exp[?] = Divide[?]( DecValue[?](5.2), Sum[?](IntValue[Unit](10), IntValue[Unit](5)) ) )
  60. 60. sealed trait Exp[A] final case class IntValue[A](v: Int) extends Exp[A] final case class DecValue[A](v: Double) extends Exp[A] final case class Sum[A](exp1: A, exp2: A) extends Exp[A] final case class Multiply[A](exp1: A, exp2: A) extends Exp[A] final case class Divide[A](exp1: A, exp2: A) extends Exp[A] final case class Square[A](exp: A) extends Exp[A] val exp1: Exp = Sum(IntValue(10), IntValue(5)) ) val exp2: Exp = Divide( DecValue(5.2), Sum(IntValue(10), IntValue(5)) ) ) val exp1: Exp[Exp[Unit]] = Sum[Exp[Unit]](IntValue[Unit](10), IntValue[Unit](5)) ) val exp2: Exp[?] = Divide[?]( DecValue[?](5.2), Sum[Exp[Unit]](IntValue[Unit](10), IntValue[Unit](5)) ) )
  61. 61. sealed trait Exp[A] final case class IntValue[A](v: Int) extends Exp[A] final case class DecValue[A](v: Double) extends Exp[A] final case class Sum[A](exp1: A, exp2: A) extends Exp[A] final case class Multiply[A](exp1: A, exp2: A) extends Exp[A] final case class Divide[A](exp1: A, exp2: A) extends Exp[A] final case class Square[A](exp: A) extends Exp[A] val exp1: Exp = Sum(IntValue(10), IntValue(5)) ) val exp2: Exp = Divide( DecValue(5.2), Sum(IntValue(10), IntValue(5)) ) ) val exp1: Exp[Exp[Unit]] = Sum[Exp[Unit]](IntValue[Unit](10), IntValue[Unit](5)) ) val exp2: Exp[?] = Divide[?]( DecValue[Exp[Unit]](5.2), Sum[Exp[Unit]](IntValue[Unit](10), IntValue[Unit](5)) ) )
  62. 62. sealed trait Exp[A] final case class IntValue[A](v: Int) extends Exp[A] final case class DecValue[A](v: Double) extends Exp[A] final case class Sum[A](exp1: A, exp2: A) extends Exp[A] final case class Multiply[A](exp1: A, exp2: A) extends Exp[A] final case class Divide[A](exp1: A, exp2: A) extends Exp[A] final case class Square[A](exp: A) extends Exp[A] val exp1: Exp = Sum(IntValue(10), IntValue(5)) ) val exp2: Exp = Divide( DecValue(5.2), Sum(IntValue(10), IntValue(5)) ) ) val exp1: Exp[Exp[Unit]] = Sum[Exp[Unit]](IntValue[Unit](10), IntValue[Unit](5)) ) val exp2: Exp[?] = Divide[Exp[Exp[Unit]]]( DecValue[Exp[Unit]](5.2), Sum[Exp[Unit]](IntValue[Unit](10), IntValue[Unit](5)) ) )
  63. 63. sealed trait Exp[A] final case class IntValue[A](v: Int) extends Exp[A] final case class DecValue[A](v: Double) extends Exp[A] final case class Sum[A](exp1: A, exp2: A) extends Exp[A] final case class Multiply[A](exp1: A, exp2: A) extends Exp[A] final case class Divide[A](exp1: A, exp2: A) extends Exp[A] final case class Square[A](exp: A) extends Exp[A] val exp1: Exp = Sum(IntValue(10), IntValue(5)) ) val exp2: Exp = Divide( DecValue(5.2), Sum(IntValue(10), IntValue(5)) ) ) val exp1: Exp[Exp[Unit]] = Sum[Exp[Unit]](IntValue[Unit](10), IntValue[Unit](5)) ) val exp2: Exp[Exp[Exp[Unit]]] = Divide[Exp[Exp[Unit]]]( DecValue[Exp[Unit]](5.2), Sum[Exp[Unit]](IntValue[Unit](10), IntValue[Unit](5)) ) )
  64. 64. sealed trait Exp[A] final case class IntValue[A](v: Int) extends Exp[A] final case class DecValue[A](v: Double) extends Exp[A] final case class Sum[A](exp1: A, exp2: A) extends Exp[A] final case class Multiply[A](exp1: A, exp2: A) extends Exp[A] final case class Divide[A](exp1: A, exp2: A) extends Exp[A] final case class Square[A](exp: A) extends Exp[A] val exp1: Exp = Sum(IntValue(10), IntValue(5)) ) val exp2: Exp = Divide( DecValue(5.2), Sum(IntValue(10), IntValue(5)) ) ) val exp1: Exp[Exp[Unit]] = Sum[Exp[Unit]](IntValue[Unit](10), IntValue[Unit](5)) ) val exp2: Exp[Exp[Exp[Unit]]] = Divide[Exp[Exp[Unit]]]( DecValue[Exp[Unit]](5.2), Sum[Exp[Unit]](IntValue[Unit](10), IntValue[Unit](5)) ) )
  65. 65. sealed trait Exp[A] final case class IntValue[A](v: Int) extends Exp[A] final case class DecValue[A](v: Double) extends Exp[A] final case class Sum[A](exp1: A, exp2: A) extends Exp[A] final case class Multiply[A](exp1: A, exp2: A) extends Exp[A] final case class Divide[A](exp1: A, exp2: A) extends Exp[A] final case class Square[A](exp: A) extends Exp[A] val exp1: Exp = Sum(IntValue(10), IntValue(5)) ) val exp2: Exp = Divide( DecValue(5.2), Sum(IntValue(10), IntValue(5)) ) ) val exp1: Exp[Exp[Unit]] = Sum[Exp[Unit]](IntValue[Unit](10), IntValue[Unit](5)) ) val exp2: Exp[Exp[Exp[Unit]]] = Divide[Exp[Exp[Unit]]]( DecValue[Exp[Unit]](5.2), Sum[Exp[Unit]](IntValue[Unit](10), IntValue[Unit](5)) ) )
  66. 66. sealed trait Exp[A] final case class IntValue[A](v: Int) extends Exp[A] final case class DecValue[A](v: Double) extends Exp[A] final case class Sum[A](exp1: A, exp2: A) extends Exp[A] final case class Multiply[A](exp1: A, exp2: A) extends Exp[A] final case class Divide[A](exp1: A, exp2: A) extends Exp[A] final case class Square[A](exp: A) extends Exp[A] val exp1: Exp = Sum(IntValue(10), IntValue(5)) ) val exp2: Exp = Divide( DecValue(5.2), Sum(IntValue(10), IntValue(5)) ) ) val exp3: Exp = from(input) val exp1: Exp[Exp[Unit]] = Sum[Exp[Unit]](IntValue[Unit](10), IntValue[Unit](5)) ) val exp2: Exp[Exp[Exp[Unit]]] = Divide[Exp[Exp[Unit]]]( DecValue[Exp[Unit]](5.2), Sum[Exp[Unit]](IntValue[Unit](10), IntValue[Unit](5)) ) ) val exp3: Exp[?] = from(input)
  67. 67. sealed trait Exp[A] final case class IntValue[A](v: Int) extends Exp[A] final case class DecValue[A](v: Double) extends Exp[A] final case class Sum[A](exp1: A, exp2: A) extends Exp[A] final case class Multiply[A](exp1: A, exp2: A) extends Exp[A] final case class Divide[A](exp1: A, exp2: A) extends Exp[A] final case class Square[A](exp: A) extends Exp[A] val exp1: Exp = Sum(IntValue(10), IntValue(5)) ) val exp2: Exp = Divide( DecValue(5.2), Sum(IntValue(10), IntValue(5)) ) ) val exp3: Exp = from(input) val exp1: Exp[Exp[Unit]] = Sum[Exp[Unit]](IntValue[Unit](10), IntValue[Unit](5)) ) val exp2: Exp[Exp[Exp[Unit]]] = Divide[Exp[Exp[Unit]]]( DecValue[Exp[Unit]](5.2), Sum[Exp[Unit]](IntValue[Unit](10), IntValue[Unit](5)) ) ) val exp3: Exp[Exp[Exp[Exp[Exp[Exp[Exp[Exp[Exp[Ex
  68. 68. Introducing: fix point data types!
  69. 69. Fix
  70. 70. case class Fix[F[_]](unFix: F[Fix[F]])
  71. 71. case class Fix[F[_]](unFix: F[Fix[F]]) val exp1: Exp[Exp[Unit]] = Sum[Exp[Unit]]( IntValue[Unit](10), IntValue[Unit](5) )
  72. 72. case class Fix[F[_]](unFix: F[Fix[F]]) val exp1: Exp[Exp[Unit]] = Sum[Exp[Unit]]( Fix(IntValue[Unit](10)), Fix(IntValue[Unit](5)) )
  73. 73. case class Fix[F[_]](unFix: F[Fix[F]]) val exp1: Exp[Exp[Unit]] = Sum[Exp[Unit]]( Fix(IntValue[Fix[Exp]](10)), Fix(IntValue[Fix[Exp]](5)) )
  74. 74. case class Fix[F[_]](unFix: F[Fix[F]]) val exp1: Exp[Exp[Unit]] = Sum[Fix[Exp]]( Fix(IntValue[Fix[Exp]](10)), Fix(IntValue[Fix[Exp]](5)) )
  75. 75. case class Fix[F[_]](unFix: F[Fix[F]]) val exp1: Exp[Exp[Unit]] = Fix(Sum[Fix[Exp]]( Fix(IntValue[Fix[Exp]](10)), Fix(IntValue[Fix[Exp]](5)) ))
  76. 76. case class Fix[F[_]](unFix: F[Fix[F]]) val exp1: Fix[Exp] = Fix(Sum[Fix[Exp]]( Fix(IntValue[Fix[Exp]](10)), Fix(IntValue[Fix[Exp]](5)) ))
  77. 77. case class Fix[F[_]](unFix: F[Fix[F]]) val exp1: Fix[Exp] = Fix(Sum[Fix[Exp]]( Fix(IntValue[Fix[Exp]](10)), Fix(IntValue[Fix[Exp]](5)) )) val exp2: Exp[Exp[Exp[Unit]]] = Divide[Exp[Exp[Unit]]]( DecValue[Exp[Unit]](5.2), Sum[Exp[Unit]]( IntValue[Unit](10), IntValue[Unit](5)) ) )
  78. 78. case class Fix[F[_]](unFix: F[Fix[F]]) val exp1: Fix[Exp] = Fix(Sum[Fix[Exp]]( Fix(IntValue[Fix[Exp]](10)), Fix(IntValue[Fix[Exp]](5)) )) val exp2: Exp[Exp[Exp[Unit]]] = Divide[Exp[Exp[Unit]]]( DecValue[Exp[Unit]](5.2), Sum[Exp[Unit]]( Fix(IntValue[Fix[Exp]](10)), Fix(IntValue[Fix[Exp]](5))) ) )
  79. 79. case class Fix[F[_]](unFix: F[Fix[F]]) val exp1: Fix[Exp] = Fix(Sum[Fix[Exp]]( Fix(IntValue[Fix[Exp]](10)), Fix(IntValue[Fix[Exp]](5)) )) val exp2: Exp[Exp[Exp[Unit]]] = Divide[Exp[Exp[Unit]]]( DecValue[Exp[Unit]](5.2), Sum[Fix[Exp]]( Fix(IntValue[Fix[Exp]](10)), Fix(IntValue[Fix[Exp]](5))) ) )
  80. 80. case class Fix[F[_]](unFix: F[Fix[F]]) val exp1: Fix[Exp] = Fix(Sum[Fix[Exp]]( Fix(IntValue[Fix[Exp]](10)), Fix(IntValue[Fix[Exp]](5)) )) val exp2: Exp[Exp[Exp[Unit]]] = Divide[Exp[Exp[Unit]]]( Fix(DecValue[Fix[Exp]](5.2)), Sum[Fix[Exp]]( Fix(IntValue[Fix[Exp]](10)), Fix(IntValue[Fix[Exp]](5))) ) )
  81. 81. case class Fix[F[_]](unFix: F[Fix[F]]) val exp1: Fix[Exp] = Fix(Sum[Fix[Exp]]( Fix(IntValue[Fix[Exp]](10)), Fix(IntValue[Fix[Exp]](5)) )) val exp2: Exp[Exp[Exp[Unit]]] = Divide[Exp[Exp[Unit]]]( Fix(DecValue[Fix[Exp]](5.2)), Fix(Sum[Fix[Exp]]( Fix(IntValue[Fix[Exp]](10)), Fix(IntValue[Fix[Exp]](5))) )) )
  82. 82. case class Fix[F[_]](unFix: F[Fix[F]]) val exp1: Fix[Exp] = Fix(Sum[Fix[Exp]]( Fix(IntValue[Fix[Exp]](10)), Fix(IntValue[Fix[Exp]](5)) )) val exp2: Exp[Exp[Exp[Unit]]] = Fix(Divide[Fix[Exp]]( Fix(DecValue[Fix[Exp]](5.2)), Fix(Sum[Fix[Exp]]( Fix(IntValue[Fix[Exp]](10)), Fix(IntValue[Fix[Exp]](5))) )) ))
  83. 83. case class Fix[F[_]](unFix: F[Fix[F]]) val exp1: Fix[Exp] = Fix(Sum[Fix[Exp]]( Fix(IntValue[Fix[Exp]](10)), Fix(IntValue[Fix[Exp]](5)) )) val exp2: Fix[Exp] = Fix(Divide[Fix[Exp]]( Fix(DecValue[Fix[Exp]](5.2)), Fix(Sum[Fix[Exp]]( Fix(IntValue[Fix[Exp]](10)), Fix(IntValue[Fix[Exp]](5))) )) ))
  84. 84. case class Fix[F[_]](unFix: F[Fix[F]]) val exp1: Fix[Exp] = Fix(Sum[Fix[Exp]]( Fix(IntValue[Fix[Exp]](10)), Fix(IntValue[Fix[Exp]](5)) )) val exp2: Fix[Exp] = Fix(Divide[Fix[Exp]]( Fix(DecValue[Fix[Exp]](5.2)), Fix(Sum[Fix[Exp]]( Fix(IntValue[Fix[Exp]](10)), Fix(IntValue[Fix[Exp]](5))) )) ))
  85. 85. case class Fix[F[_]](unFix: F[Fix[F]]) val exp1: Fix[Exp] = Fix(Sum( Fix(IntValue(10)), Fix(IntValue(5)) )) val exp2: Fix[Exp] = Fix(Divide( Fix(DecValue(5.2)), Fix(Sum( Fix(IntValue(10)), Fix(IntValue(5)) )) ))
  86. 86. case class Fix[F[_]](unFix: F[Fix[F]]) val exp1: Fix[Exp] = Fix(Sum( Fix(IntValue(10)), Fix(IntValue(5)) )) val exp2: Fix[Exp] = Fix(Divide( Fix(DecValue(5.2)), Fix(Sum( Fix(IntValue(10)), Fix(IntValue(5)) )) ))
  87. 87. case class Fix[F[_]](unFix: F[Fix[F]]) val exp1: Fix[Exp] = Fix(Sum( Fix(IntValue(10)), Fix(IntValue(5)) )) val exp2: Fix[Exp] = Fix(Divide( Fix(DecValue(5.2)), Fix(Sum( Fix(IntValue(10)), Fix(IntValue(5)) )) ))
  88. 88. case class Fix[F[_]](unFix: F[Fix[F]]) val exp1: Fix[Exp] = Fix(Sum( Fix(IntValue(10)), Fix(IntValue(5)) )) val exp2: Fix[Exp] = Fix(Divide( Fix(DecValue(5.2)), Fix(Sum( Fix(IntValue(10)), Fix(IntValue(5)) )) )) val exp3: Fix[Exp] = from(input)
  89. 89. val evaluate: Exp => Double = { case IntValue(v) => v.toDouble case DecValue(v) => v case Sum(exp1, exp2) => evaluate(exp1) + evaluate(exp2) case Multiply(exp1, exp2) => evaluate(exp1) * evaluate(exp2) case Square(exp) => val v = evaluate(exp) v * v case Divide(exp1, exp2) => evaluate(exp1) / evaluate(exp2) } val exp = Multiply( Sum(IntValue(10), DecValue(2.5)), Divide(DecValue(5.2), Sum(IntValue(10), IntValue(5)) ) ) Multiply Sum Divide Int(10) Dec(2.5) Dec(5.2) Sum Int(10) Int(5)
  90. 90. Need something that will traverse the structure…
  91. 91. Catamorphism greek κατα -“downwards” as in “catastrophe”
  92. 92. Missing Ingredients 1. Functor 2. Our Function a. a thing that is actually doing stuff
  93. 93. Functor 101
  94. 94. Functor 101 trait Functor[F[_]] { def map[A, B](fa: F[A])(f: A => B): F[B] }
  95. 95. Functor 101 trait Functor[F[_]] { def map[A, B](fa: F[A])(f: A => B): F[B] } def foo[A[_], T](a: A[T])
  96. 96. Functor 101 trait Functor[F[_]] { def map[A, B](fa: F[A])(f: A => B): F[B] } def foo[A[_], T](a: A[T])(trans: T => Int)
  97. 97. Functor 101 trait Functor[F[_]] { def map[A, B](fa: F[A])(f: A => B): F[B] } def foo[A[_], T](a: A[T])(trans: T => Int): A[Int] = ???
  98. 98. Functor 101 trait Functor[F[_]] { def map[A, B](fa: F[A])(f: A => B): F[B] } def foo[A[_] : Functor, T](a: A[T])(trans: T => Int): A[Int] = ???
  99. 99. Functor 101 trait Functor[F[_]] { def map[A, B](fa: F[A])(f: A => B): F[B] } def foo[A[_] : Functor, T](a: A[T])(trans: T => Int): A[Int] = a.map(trans)
  100. 100. Functor 101 trait Functor[F[_]] { def map[A, B](fa: F[A])(f: A => B): F[B] } def foo[A[_] : Functor, T](a: A[T])(trans: T => Int): A[Int] = a.map(trans) case class Container[T](t: T) val r: Container[Int] = foo[Container, String](Container("bar"))(str => str.length)
  101. 101. Functor 101 trait Functor[F[_]] { def map[A, B](fa: F[A])(f: A => B): F[B] } def foo[A[_] : Functor, T](a: A[T])(trans: T => Int): A[Int] = a.map(trans) implicit val functor: Functor[Container] = new Functor[Container] { def map[A, B](c: Container[A])(f: A => B): Container[B] = Container(f(c.t)) } case class Container[T](t: T) val r: Container[Int] = foo[Container, String](Container("bar"))(str => str.length)
  102. 102. sealed trait Exp final case class IntValue(v: Int) extends Exp final case class DecValue(v: Double) extends Exp final case class Sum(exp1: Exp, exp2: Exp) extends Exp final case class Multiply(exp1: Exp, exp2: Exp) extends Exp final case class Divide(exp1: Exp, exp2: Exp) extends Exp final case class Square(exp: Exp) extends Exp implicit val functor: Functor[Exp] = new Functor[Exp] { def map[A, B](exp: Exp[A])(f: A => B): Exp[B] =
  103. 103. sealed trait Exp final case class IntValue(v: Int) extends Exp final case class DecValue(v: Double) extends Exp final case class Sum(exp1: Exp, exp2: Exp) extends Exp final case class Multiply(exp1: Exp, exp2: Exp) extends Exp final case class Divide(exp1: Exp, exp2: Exp) extends Exp final case class Square(exp: Exp) extends Exp implicit val functor: Functor[Exp] = new Functor[Exp] { def map[A, B](exp: Exp[A])(f: A => B): Exp[B] = exp match { case Sum(a1, a2) => Sum(f(a1), f(a2)) case Multiply(a1, a2) => Multiply(f(a1), f(a2)) case Divide(a1, a2) => Divide(f(a1), f(a2)) case Square(a) => Square(f(a)) case IntValue(v) => IntValue(v) case DecValue(v) => DecValue(v) } }
  104. 104. Missing Ingredients 1. Functor 2. Our Function
  105. 105. Missing Ingredients 1. Functor 2. Our Function
  106. 106. Missing Ingredients 1. Functor 2. F-Algebra
  107. 107. F-algebra type Algebra[F[_], A] = F[A] => A
  108. 108. type Algebra[F[_], A] = F[A] => A val evaluate: Algebra[Exp, Double] = { // Exp[Double] => Double case IntValue(v) => v.toDouble case DecValue(v) => v case Sum(a1, a2) => a1 + a2 case Multiply(a1, a2) => a1 * a2 case Square(a) => a * a case Divide(a1, a2) => a1 / a2 }
  109. 109. type Algebra[F[_], A] = F[A] => A val evaluate: Algebra[Exp, Double] = { // Exp[Double] => Double case IntValue(v) => v.toDouble case DecValue(v) => v case Sum(a1, a2) => a1 + a2 case Multiply(a1, a2) => a1 * a2 case Square(a) => a * a case Divide(a1, a2) => a1 / a2 } val mkStr: Algebra[Exp, String] = { case IntValue(v) => v.toString case DecValue(v) => v.toString case Sum(a1, a2) => s"($a1 + $a2)" case Multiply(a1, a2) => s"($a1 + $a2)" case Square(a) => s"($a)^2" case Divide(a1, a2) => s"($a1 + $a2)" }
  110. 110. val evaluate: Algebra[Exp, Double] = { // Exp[Double] => Double case IntValue(v) => v.toDouble case DecValue(v) => v case Sum(a1, a2) => a1 + a2 case Multiply(a1, a2) => a1 * a2 case Square(a) => a * a case Divide(a1, a2) => a1 / a2 }
  111. 111. val evaluate: Algebra[Exp, Double] = { // Exp[Double] => Double case IntValue(v) => v.toDouble case DecValue(v) => v case Sum(a1, a2) => a1 + a2 case Multiply(a1, a2) => a1 * a2 case Square(a) => a * a case Divide(a1, a2) => a1 / a2 } val exp2: Fix[Exp] = Fix(Divide( Fix(DecValue(5.2)), Fix(Sum( Fix(IntValue(10)), Fix(IntValue(5)) )) ))
  112. 112. val evaluate: Algebra[Exp, Double] = { // Exp[Double] => Double case IntValue(v) => v.toDouble case DecValue(v) => v case Sum(a1, a2) => a1 + a2 case Multiply(a1, a2) => a1 * a2 case Square(a) => a * a case Divide(a1, a2) => a1 / a2 } val exp2: Fix[Exp] = Fix(Divide( Fix(DecValue(5.2)), Fix(Sum( Fix(IntValue(10)), Fix(IntValue(5)) )) )) > exp2.cata(evaluate) 0.3466666666666667
  113. 113. val mkStr: Algebra[Exp, String] = { // Exp[String] => String case IntValue(v) => v.toString case DecValue(v) => v.toString case Sum(a1, a2) => s"($a1 + $a2)" case Multiply(a1, a2) => s"($a1 + $a2)" case Square(a) => s"($a)^2" case Divide(a1, a2) => s"($a1 + $a2)" }
  114. 114. val mkStr: Algebra[Exp, String] = { // Exp[String] => String case IntValue(v) => v.toString case DecValue(v) => v.toString case Sum(a1, a2) => s"($a1 + $a2)" case Multiply(a1, a2) => s"($a1 + $a2)" case Square(a) => s"($a)^2" case Divide(a1, a2) => s"($a1 + $a2)" } val exp2: Fix[Exp] = Fix(Divide( Fix(DecValue(5.2)), Fix(Sum( Fix(IntValue(10)), Fix(IntValue(5)) )) ))
  115. 115. val mkStr: Algebra[Exp, String] = { // Exp[String] => String case IntValue(v) => v.toString case DecValue(v) => v.toString case Sum(a1, a2) => s"($a1 + $a2)" case Multiply(a1, a2) => s"($a1 + $a2)" case Square(a) => s"($a)^2" case Divide(a1, a2) => s"($a1 + $a2)" } val exp2: Fix[Exp] = Fix(Divide( Fix(DecValue(5.2)), Fix(Sum( Fix(IntValue(10)), Fix(IntValue(5)) )) )) > exp2.cata(mkStr) (5.2 + (10 + 5))
  116. 116. val optimize: Exp => Exp = { case Multiply(exp1, exp2) if(exp1 == exp2) => Square(optimize(exp1)) case IntValue(v) => IntValue(v) case DecValue(v) => DecValue(v) case Sum(exp1, exp2) => Sum(optimize(exp1), optimize(exp2)) case Multiply(exp1, exp2) => Multiply(optimize(exp1), optimize(exp2)) case Square(exp) => Square(optimize(exp)) case Divide(exp1, exp2) => Divide(optimize(exp1), optimize(exp2)) }
  117. 117. val optimize: Exp => Exp = { case Multiply(exp1, exp2) if(exp1 == exp2) => Square(optimize(exp1)) case IntValue(v) => IntValue(v) case DecValue(v) => DecValue(v) case Sum(exp1, exp2) => Sum(optimize(exp1), optimize(exp2)) case Multiply(exp1, exp2) => Multiply(optimize(exp1), optimize(exp2)) case Square(exp) => Square(optimize(exp)) case Divide(exp1, exp2) => Divide(optimize(exp1), optimize(exp2)) } val optimize: Algebra[Exp, Fix[Exp]] = { // Exp[Fix[Exp]] => Fix[Exp] case Multiply(Fix(a1), Fix(a2)) if(a1 == a2) => Fix(Square(Fix(a1))) case other => Fix(other) }
  118. 118. val optimize: Algebra[Exp, Fix[Exp]] = { // Exp[Fix[Exp]] => Fix[Exp] case Multiply(Fix(a1), Fix(a2)) if(a1 == a2) => Fix(Square(Fix(a1))) case other => Fix(other) }
  119. 119. val optimize: Algebra[Exp, Fix[Exp]] = { // Exp[Fix[Exp]] => Fix[Exp] case Multiply(Fix(a1), Fix(a2)) if(a1 == a2) => Fix(Square(Fix(a1))) case other => Fix(other) } val aTimesAExp: Fix[Exp] = Fix(Multiply( Fix(Sum( Fix(IntValue[Fix[Exp]](10)), Fix(IntValue[Fix[Exp]](20)) )), Fix(Sum( Fix(IntValue[Fix[Exp]](10)), Fix(IntValue[Fix[Exp]](20)) )) ))
  120. 120. val optimize: Algebra[Exp, Fix[Exp]] = { // Exp[Fix[Exp]] => Fix[Exp] case Multiply(Fix(a1), Fix(a2)) if(a1 == a2) => Fix(Square(Fix(a1))) case other => Fix(other) } val aTimesAExp: Fix[Exp] = Fix(Multiply( Fix(Sum( Fix(IntValue[Fix[Exp]](10)), Fix(IntValue[Fix[Exp]](20)) )), Fix(Sum( Fix(IntValue[Fix[Exp]](10)), Fix(IntValue[Fix[Exp]](20)) )) )) > aTimesAExp.cata(optimize) Fix(Square(Fix(Sum(Fix(IntValue(10)),Fix(IntValue(20))))))
  121. 121. ZOO of morphisims anamorphism & hylomorphism
  122. 122. Anamorphism ● Constructs a structure from a value
  123. 123. Anamorphism ● Constructs a structure from a value ● Co- part of catamorphism
  124. 124. Anamorphism ● Constructs a structure from a value ● Co- part of catamorphism ● Instead of using Algebra[F[_], A] we will use Coalgebra[F[_], A]
  125. 125. Anamorphism ● Constructs a structure from a value ● Co- part of catamorphism ● Instead of using Algebra[F[_], A] we will use Coalgebra[F[_], A] Example: given Int, construct expression called divisors that ● is multiplication of series of 2s & one odd value ● once evaluated will return initial Int e.g 28 = 2 * 2 * 7
  126. 126. type Coalgebra[F[_], A] = A => F[A]
  127. 127. type Coalgebra[F[_], A] = A => F[A] val divisors: Coalgebra[Exp, Int] = { case n if(n % 2 == 0 && n != 2) => Multiply(2, n / 2) case n => IntValue(n) }
  128. 128. type Coalgebra[F[_], A] = A => F[A] val divisors: Coalgebra[Exp, Int] = { case n if(n % 2 == 0 && n != 2) => Multiply(2, n / 2) case n => IntValue(n) } > 12.ana[Fix, Exp](divisors)
  129. 129. type Coalgebra[F[_], A] = A => F[A] val divisors: Coalgebra[Exp, Int] = { case n if(n % 2 == 0 && n != 2) => Multiply(2, n / 2) case n => IntValue(n) } > 12.ana[Fix, Exp](divisors) Fix(Multiply(Fix(IntValue(2)),Fix(Multiply(Fix(IntValue(2)),Fix(Multiply(Fix(IntVal ue(2)),Fix(IntValue(7))))))))
  130. 130. Hylomorphism
  131. 131. Hylomorphism ● Constructs and then deconstructs a structure from a value
  132. 132. Hylomorphism ● Constructs and then deconstructs a structure from a value ● Anamorphism followed by catamorphism
  133. 133. Hylomorphism ● Constructs and then deconstructs a structure from a value ● Anamorphism followed by catamorphism ● Difference: evaluated in a single pass
  134. 134. Hylomorphism ● Constructs and then deconstructs a structure from a value ● Anamorphism followed by catamorphism ● Difference: evaluated in a single pass value hylo value ana cata structure
  135. 135. Hylomorphism ● Constructs and then deconstructs a structure from a value ● Anamorphism followed by catamorphism ● Difference: evaluated in a single pass value hylo value ana cata structure
  136. 136. val divisors: Coalgebra[Exp, Int] = { … } // Double => Exp[Double] val evaluate: Algebra[Exp, Double] = { … } // Exp[Double] => Double
  137. 137. val divisors: Coalgebra[Exp, Int] = { … } // Double => Exp[Double] val evaluate: Algebra[Exp, Double] = { … } // Exp[Double] => Double describe("divisors") { it("once evaluated will give initial value") { forAll(positiveInt) { n => n.ana(divisiors).cata(evaluate) shouldEqual(n) } }
  138. 138. val divisors: Coalgebra[Exp, Int] = { … } // Double => Exp[Double] val evaluate: Algebra[Exp, Double] = { … } // Exp[Double] => Double describe("divisors") { it("once evaluated will give initial value") { forAll(positiveInt) { n => n.hylo(evaluate, divisors) shouldEqual(n) } }
  139. 139. What else?
  140. 140. To sum it up ● Recursion is hard, but it is ubiquitous ● Explicit recursion is tedious & error-prone ● Recursion schemas ○ set of composable combinators ○ well defined in both academia & industry ● Fix point data types ● You don’t have to do FP to take advantage of recursion schemes ● You can be famous! Build stuff!
  141. 141. References [NATO68] - http://homepages.cs.ncl.ac.uk/brian.randell/NATO/nato1968.PDF [MTEU16] - https://www.infoq.com/presentations/engineer-practices-techniques [BdM97] - R. Bird and O. de Moor. Algebra of Programming. Series in Computer Science. Prentice-Hall International, 1997. C.A.R. Hoare, series editor. [MFP91] - http://eprints.eemcs.utwente.nl/7281/01/db-utwente-40501F46.pdf [STOW14] - http://blog.sumtypeofway.com/an-introduction-to-recursion-schemes/
  142. 142. Pawel Szulc
  143. 143. Pawel Szulc @rabbitonweb
  144. 144. Pawel Szulc @rabbitonweb paul.szulc@gmail.com
  145. 145. Pawel Szulc @rabbitonweb paul.szulc@gmail.com http://rabbitonweb.com

×