Going bananas with recursion schemes for fixed point data types

Pawel Szulc
Pawel SzulcScala Developer at BLStream
“Going bananas with
recursion schemes for
fixed point data types”
Pawel Szulc
email: paul.szulc@gmail.com
twitter: @rabbitonweb
github: https://github.com/rabbitonweb/
Software
Engineering
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]
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]
Recursion
“Recursion is where Functional Programming hits
the bottom”
- Greg Pfeil
Recursion Schemes
“Functional Programming with Bananas, Lenses,
Envelopes and Barbed Wire” by Erik Meijer Maarten,
Maarten Fokkinga and Ross Paterson [MFP91]
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
Real world application
https://github.com/quasar-analytics/quasar
https://github.com/slamdata/matryoshka
Recursive Structures are common
Recursive Structures are common
● Simplest examples
○ List:
■ Cons(a, List)
■ Nil
○ Binary Tree
■ Node(a, Tree, Tree)
■ Leaf(a)
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
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
Expressions!
Our example
102
+ 20.5 * 14.5
Expressions!
Sum (
Square( IntValue(10) )
Multiply( DecValue(20.5),
DecValue(14.5) ),
)
Our example
102
+ 20.5 * 14.5
Expressions!
Sum (
Square( IntValue(10) )
Multiply( DecValue(20.5),
DecValue(14.5) ),
)
Our example
102
+ 20.5 * 14.5
Expressions!
Sum (
Square( IntValue(10) )
Multiply( DecValue(20.5),
DecValue(14.5) ),
)
Our example
102
+ 20.5 * 14.5
Expressions!
Sum (
Square( IntValue(10) )
Multiply( DecValue(20.5),
DecValue(14.5) ),
)
Our example
102
+ 20.5 * 14.5
Expressions!
Sum (
Square( IntValue(10) )
Multiply( DecValue(20.5),
DecValue(14.5) ),
)
Our example
102
+ 20.5 * 14.5
Expressions!
Sum (
Square( IntValue(10) )
Multiply( DecValue(20.5),
DecValue(14.5) ),
Our example
102
+ 20.5 * 14.5
Expressions!
Sum (
Square( IntValue(10) )
Multiply( DecValue(20.5),
DecValue(14.5) ),
)
Our example
102
+ 20.5 * 14.5
Expressions!
Square (
Sum (
Square( IntValue(10) )
Multiply( DecValue(20.5),
DecValue(14.5) ),
)
)
Our example
(102
+ 20.5 * 14.5)2
Expressions!
Our example
(102
+ 20.5 * 14.5)2
Square
Sum
Square
10
Multiply
10 10
data Exp = IntVal Int |
DecVal Double |
Sum Exp Exp |
Multiply Exp Exp |
Divide Exp Exp |
Square Exp
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
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
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 =
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)
}
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)})"
}
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))
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))
}
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))
}
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))
}
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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
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]
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))
)
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))
)
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]
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]
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))
)
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))
)
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))
)
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))
)
)
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))
)
)
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))
)
)
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))
)
)
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))
)
)
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))
)
)
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))
)
)
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))
)
)
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)
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
Introducing:
fix point data
types!
Fix
Going bananas with recursion schemes for fixed point data types
case class Fix[F[_]](unFix: F[Fix[F]])
case class Fix[F[_]](unFix: F[Fix[F]])
val exp1: Exp[Exp[Unit]] =
Sum[Exp[Unit]](
IntValue[Unit](10),
IntValue[Unit](5)
)
case class Fix[F[_]](unFix: F[Fix[F]])
val exp1: Exp[Exp[Unit]] =
Sum[Exp[Unit]](
Fix(IntValue[Unit](10)),
Fix(IntValue[Unit](5))
)
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))
)
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))
)
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))
))
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))
))
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))
)
)
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)))
)
)
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)))
)
)
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)))
)
)
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)))
))
)
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)))
))
))
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)))
))
))
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)))
))
))
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))
))
))
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))
))
))
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))
))
))
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)
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)
Need something
that will
traverse the
structure…
Catamorphism
greek κατα -“downwards” as in “catastrophe”
Going bananas with recursion schemes for fixed point data types
Missing Ingredients
1. Functor
2. Our Function
a. a thing that is actually doing stuff
Functor 101
Functor 101
trait Functor[F[_]] {
def map[A, B](fa: F[A])(f: A => B): F[B]
}
Functor 101
trait Functor[F[_]] {
def map[A, B](fa: F[A])(f: A => B): F[B]
}
def foo[A[_], T](a: A[T])
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)
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] = ???
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] = ???
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)
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)
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)
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] =
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)
}
}
Missing Ingredients
1. Functor
2. Our Function
Missing Ingredients
1. Functor
2. Our Function
Missing Ingredients
1. Functor
2. F-Algebra
F-algebra
type Algebra[F[_], A] = F[A] => A
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
}
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)"
}
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 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))
))
))
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
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 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))
))
))
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))
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: 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)
}
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 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))
))
))
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))))))
ZOO of
morphisims
anamorphism & hylomorphism
Anamorphism
● Constructs a structure from a value
Anamorphism
● Constructs a structure from a value
● Co- part of catamorphism
Anamorphism
● Constructs a structure from a value
● Co- part of catamorphism
● Instead of using Algebra[F[_], A] we will use Coalgebra[F[_], A]
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
type Coalgebra[F[_], A] = A => F[A]
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)
}
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)
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))))))))
Hylomorphism
Hylomorphism
● Constructs and then deconstructs a structure from a value
Hylomorphism
● Constructs and then deconstructs a structure from a value
● Anamorphism followed by catamorphism
Hylomorphism
● Constructs and then deconstructs a structure from a value
● Anamorphism followed by catamorphism
● Difference: evaluated in a single pass
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
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
val divisors: Coalgebra[Exp, Int] = { … } // Double => Exp[Double]
val evaluate: Algebra[Exp, Double] = { … } // Exp[Double] => Double
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)
}
}
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)
}
}
What else?
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!
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/
Pawel Szulc
Pawel Szulc
@rabbitonweb
Pawel Szulc
@rabbitonweb
paul.szulc@gmail.com
Pawel Szulc
@rabbitonweb
paul.szulc@gmail.com
http://rabbitonweb.com
1 of 147

Recommended

Recursion schemes in Scala by
Recursion schemes in ScalaRecursion schemes in Scala
Recursion schemes in ScalaArthur Kushka
1.6K views33 slides
“Going bananas with recursion schemes for fixed point data types” by
“Going bananas with recursion schemes for fixed point data types”“Going bananas with recursion schemes for fixed point data types”
“Going bananas with recursion schemes for fixed point data types”Pawel Szulc
1.4K views170 slides
Introduction to Scala by
Introduction to ScalaIntroduction to Scala
Introduction to ScalaAleksandar Prokopec
1.6K views107 slides
ScalaBlitz by
ScalaBlitzScalaBlitz
ScalaBlitzAleksandar Prokopec
2.3K views100 slides
ScalaMeter 2014 by
ScalaMeter 2014ScalaMeter 2014
ScalaMeter 2014Aleksandar Prokopec
2.3K views77 slides
Pybelsberg — Constraint-based Programming in Python by
Pybelsberg — Constraint-based Programming in PythonPybelsberg — Constraint-based Programming in Python
Pybelsberg — Constraint-based Programming in PythonChristoph Matthies
760 views51 slides

More Related Content

What's hot

20170509 rand db_lesugent by
20170509 rand db_lesugent20170509 rand db_lesugent
20170509 rand db_lesugentProf. Wim Van Criekinge
1.2K views19 slides
Declarative Thinking, Declarative Practice by
Declarative Thinking, Declarative PracticeDeclarative Thinking, Declarative Practice
Declarative Thinking, Declarative PracticeKevlin Henney
2K views115 slides
Scala Parallel Collections by
Scala Parallel CollectionsScala Parallel Collections
Scala Parallel CollectionsAleksandar Prokopec
2.4K views140 slides
Rcommands-for those who interested in R. by
Rcommands-for those who interested in R.Rcommands-for those who interested in R.
Rcommands-for those who interested in R.Dr. Volkan OBAN
135 views7 slides
FYP Final Presentation by
FYP Final PresentationFYP Final Presentation
FYP Final PresentationJason Yeo Jie Shun
655 views78 slides
R reference card by
R reference cardR reference card
R reference cardHesher Shih
945 views4 slides

What's hot(16)

Declarative Thinking, Declarative Practice by Kevlin Henney
Declarative Thinking, Declarative PracticeDeclarative Thinking, Declarative Practice
Declarative Thinking, Declarative Practice
Kevlin Henney2K views
Rcommands-for those who interested in R. by Dr. Volkan OBAN
Rcommands-for those who interested in R.Rcommands-for those who interested in R.
Rcommands-for those who interested in R.
Dr. Volkan OBAN135 views
R reference card by Hesher Shih
R reference cardR reference card
R reference card
Hesher Shih945 views
Gentlest Introduction to Tensorflow - Part 3 by Khor SoonHin
Gentlest Introduction to Tensorflow - Part 3Gentlest Introduction to Tensorflow - Part 3
Gentlest Introduction to Tensorflow - Part 3
Khor SoonHin4.8K views
Gentlest Introduction to Tensorflow - Part 2 by Khor SoonHin
Gentlest Introduction to Tensorflow - Part 2Gentlest Introduction to Tensorflow - Part 2
Gentlest Introduction to Tensorflow - Part 2
Khor SoonHin2.8K views
Python легко и просто. Красиво решаем повседневные задачи by Maxim Kulsha
Python легко и просто. Красиво решаем повседневные задачиPython легко и просто. Красиво решаем повседневные задачи
Python легко и просто. Красиво решаем повседневные задачи
Maxim Kulsha1.3K views
Programming in lua STRING AND ARRAY by vikram mahendra
Programming in lua STRING AND ARRAYProgramming in lua STRING AND ARRAY
Programming in lua STRING AND ARRAY
vikram mahendra254 views
TensorFlow in Practice by indico data
TensorFlow in PracticeTensorFlow in Practice
TensorFlow in Practice
indico data5.4K views
R short-refcard by conline
R short-refcardR short-refcard
R short-refcard
conline321 views
Lucio Floretta - TensorFlow and Deep Learning without a PhD - Codemotion Mila... by Codemotion
Lucio Floretta - TensorFlow and Deep Learning without a PhD - Codemotion Mila...Lucio Floretta - TensorFlow and Deep Learning without a PhD - Codemotion Mila...
Lucio Floretta - TensorFlow and Deep Learning without a PhD - Codemotion Mila...
Codemotion829 views
Google Go For Ruby Hackers by Eleanor McHugh
Google Go For Ruby HackersGoogle Go For Ruby Hackers
Google Go For Ruby Hackers
Eleanor McHugh2.3K views
Gentlest Introduction to Tensorflow by Khor SoonHin
Gentlest Introduction to TensorflowGentlest Introduction to Tensorflow
Gentlest Introduction to Tensorflow
Khor SoonHin5.9K views

Similar to Going bananas with recursion schemes for fixed point data types

Scala - where objects and functions meet by
Scala - where objects and functions meetScala - where objects and functions meet
Scala - where objects and functions meetMario Fusco
1.8K views32 slides
In class we saw how to evaluate an expression given a map from identi.pdf by
In class we saw how to evaluate an expression given a map from identi.pdfIn class we saw how to evaluate an expression given a map from identi.pdf
In class we saw how to evaluate an expression given a map from identi.pdfsonicleaner
3 views1 slide
Compiler Construction | Lecture 5 | Transformation by Term Rewriting by
Compiler Construction | Lecture 5 | Transformation by Term RewritingCompiler Construction | Lecture 5 | Transformation by Term Rewriting
Compiler Construction | Lecture 5 | Transformation by Term RewritingEelco Visser
448 views175 slides
SDC - Einführung in Scala by
SDC - Einführung in ScalaSDC - Einführung in Scala
SDC - Einführung in ScalaChristian Baranowski
1.2K views73 slides
Declare Your Language: Transformation by Strategic Term Rewriting by
Declare Your Language: Transformation by Strategic Term RewritingDeclare Your Language: Transformation by Strategic Term Rewriting
Declare Your Language: Transformation by Strategic Term RewritingEelco Visser
602 views173 slides
Term Rewriting by
Term RewritingTerm Rewriting
Term RewritingEelco Visser
924 views142 slides

Similar to Going bananas with recursion schemes for fixed point data types(20)

Scala - where objects and functions meet by Mario Fusco
Scala - where objects and functions meetScala - where objects and functions meet
Scala - where objects and functions meet
Mario Fusco1.8K views
In class we saw how to evaluate an expression given a map from identi.pdf by sonicleaner
In class we saw how to evaluate an expression given a map from identi.pdfIn class we saw how to evaluate an expression given a map from identi.pdf
In class we saw how to evaluate an expression given a map from identi.pdf
sonicleaner3 views
Compiler Construction | Lecture 5 | Transformation by Term Rewriting by Eelco Visser
Compiler Construction | Lecture 5 | Transformation by Term RewritingCompiler Construction | Lecture 5 | Transformation by Term Rewriting
Compiler Construction | Lecture 5 | Transformation by Term Rewriting
Eelco Visser448 views
Declare Your Language: Transformation by Strategic Term Rewriting by Eelco Visser
Declare Your Language: Transformation by Strategic Term RewritingDeclare Your Language: Transformation by Strategic Term Rewriting
Declare Your Language: Transformation by Strategic Term Rewriting
Eelco Visser602 views
Monadologie by league
MonadologieMonadologie
Monadologie
league3.6K views
ecoop-slides.pdf by AndongFAN
ecoop-slides.pdfecoop-slides.pdf
ecoop-slides.pdf
AndongFAN185 views
Go Programming Language (Golang) by Ishin Vin
Go Programming Language (Golang)Go Programming Language (Golang)
Go Programming Language (Golang)
Ishin Vin775 views
The Functional Programming Triad of Folding, Scanning and Iteration - a first... by Philip Schwarz
The Functional Programming Triad of Folding, Scanning and Iteration - a first...The Functional Programming Triad of Folding, Scanning and Iteration - a first...
The Functional Programming Triad of Folding, Scanning and Iteration - a first...
Philip Schwarz105 views
Go: It's Not Just For Google by Eleanor McHugh
Go: It's Not Just For GoogleGo: It's Not Just For Google
Go: It's Not Just For Google
Eleanor McHugh1.5K views
The Functional Programming Triad of Folding, Scanning and Iteration - a first... by Philip Schwarz
The Functional Programming Triad of Folding, Scanning and Iteration - a first...The Functional Programming Triad of Folding, Scanning and Iteration - a first...
The Functional Programming Triad of Folding, Scanning and Iteration - a first...
Philip Schwarz971 views
ハイブリッド言語Scalaを使う by bpstudy
ハイブリッド言語Scalaを使うハイブリッド言語Scalaを使う
ハイブリッド言語Scalaを使う
bpstudy1.7K views
Need help programming this assignment in OCaml- 1) Copy-paste the fol (1).pdf by aarifi9988
Need help programming this assignment in OCaml-  1) Copy-paste the fol (1).pdfNeed help programming this assignment in OCaml-  1) Copy-paste the fol (1).pdf
Need help programming this assignment in OCaml- 1) Copy-paste the fol (1).pdf
aarifi99884 views
Scope Graphs: A fresh look at name binding in programming languages by Eelco Visser
Scope Graphs: A fresh look at name binding in programming languagesScope Graphs: A fresh look at name binding in programming languages
Scope Graphs: A fresh look at name binding in programming languages
Eelco Visser779 views
Futzing with actors (etc.) by league
Futzing with actors (etc.)Futzing with actors (etc.)
Futzing with actors (etc.)
league937 views

More from Pawel Szulc

Getting acquainted with Lens by
Getting acquainted with LensGetting acquainted with Lens
Getting acquainted with LensPawel Szulc
629 views226 slides
Impossibility by
ImpossibilityImpossibility
ImpossibilityPawel Szulc
474 views113 slides
Maintainable Software Architecture in Haskell (with Polysemy) by
Maintainable Software Architecture in Haskell (with Polysemy)Maintainable Software Architecture in Haskell (with Polysemy)
Maintainable Software Architecture in Haskell (with Polysemy)Pawel Szulc
526 views285 slides
Painless Haskell by
Painless HaskellPainless Haskell
Painless HaskellPawel Szulc
2.4K views226 slides
Trip with monads by
Trip with monadsTrip with monads
Trip with monadsPawel Szulc
1.9K views140 slides
Trip with monads by
Trip with monadsTrip with monads
Trip with monadsPawel Szulc
1K views137 slides

More from Pawel Szulc(20)

Getting acquainted with Lens by Pawel Szulc
Getting acquainted with LensGetting acquainted with Lens
Getting acquainted with Lens
Pawel Szulc629 views
Maintainable Software Architecture in Haskell (with Polysemy) by Pawel Szulc
Maintainable Software Architecture in Haskell (with Polysemy)Maintainable Software Architecture in Haskell (with Polysemy)
Maintainable Software Architecture in Haskell (with Polysemy)
Pawel Szulc526 views
Painless Haskell by Pawel Szulc
Painless HaskellPainless Haskell
Painless Haskell
Pawel Szulc2.4K views
Trip with monads by Pawel Szulc
Trip with monadsTrip with monads
Trip with monads
Pawel Szulc1.9K views
Illogical engineers by Pawel Szulc
Illogical engineersIllogical engineers
Illogical engineers
Pawel Szulc257 views
RChain - Understanding Distributed Calculi by Pawel Szulc
RChain - Understanding Distributed CalculiRChain - Understanding Distributed Calculi
RChain - Understanding Distributed Calculi
Pawel Szulc421 views
Illogical engineers by Pawel Szulc
Illogical engineersIllogical engineers
Illogical engineers
Pawel Szulc1.2K views
Understanding distributed calculi in Haskell by Pawel Szulc
Understanding distributed calculi in HaskellUnderstanding distributed calculi in Haskell
Understanding distributed calculi in Haskell
Pawel Szulc866 views
Software engineering the genesis by Pawel Szulc
Software engineering  the genesisSoftware engineering  the genesis
Software engineering the genesis
Pawel Szulc377 views
Make your programs Free by Pawel Szulc
Make your programs FreeMake your programs Free
Make your programs Free
Pawel Szulc3.9K views
Writing your own RDD for fun and profit by Pawel Szulc
Writing your own RDD for fun and profitWriting your own RDD for fun and profit
Writing your own RDD for fun and profit
Pawel Szulc774 views
The cats toolbox a quick tour of some basic typeclasses by Pawel Szulc
The cats toolbox  a quick tour of some basic typeclassesThe cats toolbox  a quick tour of some basic typeclasses
The cats toolbox a quick tour of some basic typeclasses
Pawel Szulc397 views
Introduction to type classes by Pawel Szulc
Introduction to type classesIntroduction to type classes
Introduction to type classes
Pawel Szulc642 views
Functional Programming & Event Sourcing - a pair made in heaven by Pawel Szulc
Functional Programming & Event Sourcing - a pair made in heavenFunctional Programming & Event Sourcing - a pair made in heaven
Functional Programming & Event Sourcing - a pair made in heaven
Pawel Szulc2.1K views
Apache spark workshop by Pawel Szulc
Apache spark workshopApache spark workshop
Apache spark workshop
Pawel Szulc977 views
Introduction to type classes in 30 min by Pawel Szulc
Introduction to type classes in 30 minIntroduction to type classes in 30 min
Introduction to type classes in 30 min
Pawel Szulc1.8K views
Real world gobbledygook by Pawel Szulc
Real world gobbledygookReal world gobbledygook
Real world gobbledygook
Pawel Szulc814 views
Apache spark when things go wrong by Pawel Szulc
Apache spark   when things go wrongApache spark   when things go wrong
Apache spark when things go wrong
Pawel Szulc929 views

Recently uploaded

How to build dyanmic dashboards and ensure they always work by
How to build dyanmic dashboards and ensure they always workHow to build dyanmic dashboards and ensure they always work
How to build dyanmic dashboards and ensure they always workWiiisdom
16 views13 slides
Introduction to Git Source Control by
Introduction to Git Source ControlIntroduction to Git Source Control
Introduction to Git Source ControlJohn Valentino
8 views18 slides
Ports-and-Adapters Architecture for Embedded HMI by
Ports-and-Adapters Architecture for Embedded HMIPorts-and-Adapters Architecture for Embedded HMI
Ports-and-Adapters Architecture for Embedded HMIBurkhard Stubert
35 views19 slides
ADDO_2022_CICID_Tom_Halpin.pdf by
ADDO_2022_CICID_Tom_Halpin.pdfADDO_2022_CICID_Tom_Halpin.pdf
ADDO_2022_CICID_Tom_Halpin.pdfTomHalpin9
6 views33 slides
predicting-m3-devopsconMunich-2023.pptx by
predicting-m3-devopsconMunich-2023.pptxpredicting-m3-devopsconMunich-2023.pptx
predicting-m3-devopsconMunich-2023.pptxTier1 app
10 views24 slides
aATP - New Correlation Confirmation Feature.pptx by
aATP - New Correlation Confirmation Feature.pptxaATP - New Correlation Confirmation Feature.pptx
aATP - New Correlation Confirmation Feature.pptxEsatEsenek1
222 views6 slides

Recently uploaded(20)

How to build dyanmic dashboards and ensure they always work by Wiiisdom
How to build dyanmic dashboards and ensure they always workHow to build dyanmic dashboards and ensure they always work
How to build dyanmic dashboards and ensure they always work
Wiiisdom16 views
Introduction to Git Source Control by John Valentino
Introduction to Git Source ControlIntroduction to Git Source Control
Introduction to Git Source Control
John Valentino8 views
Ports-and-Adapters Architecture for Embedded HMI by Burkhard Stubert
Ports-and-Adapters Architecture for Embedded HMIPorts-and-Adapters Architecture for Embedded HMI
Ports-and-Adapters Architecture for Embedded HMI
Burkhard Stubert35 views
ADDO_2022_CICID_Tom_Halpin.pdf by TomHalpin9
ADDO_2022_CICID_Tom_Halpin.pdfADDO_2022_CICID_Tom_Halpin.pdf
ADDO_2022_CICID_Tom_Halpin.pdf
TomHalpin96 views
predicting-m3-devopsconMunich-2023.pptx by Tier1 app
predicting-m3-devopsconMunich-2023.pptxpredicting-m3-devopsconMunich-2023.pptx
predicting-m3-devopsconMunich-2023.pptx
Tier1 app10 views
aATP - New Correlation Confirmation Feature.pptx by EsatEsenek1
aATP - New Correlation Confirmation Feature.pptxaATP - New Correlation Confirmation Feature.pptx
aATP - New Correlation Confirmation Feature.pptx
EsatEsenek1222 views
JioEngage_Presentation.pptx by admin125455
JioEngage_Presentation.pptxJioEngage_Presentation.pptx
JioEngage_Presentation.pptx
admin1254559 views
Dapr Unleashed: Accelerating Microservice Development by Miroslav Janeski
Dapr Unleashed: Accelerating Microservice DevelopmentDapr Unleashed: Accelerating Microservice Development
Dapr Unleashed: Accelerating Microservice Development
Miroslav Janeski16 views
Mobile App Development Company by Richestsoft
Mobile App Development CompanyMobile App Development Company
Mobile App Development Company
Richestsoft 5 views
Understanding HTML terminology by artembondar5
Understanding HTML terminologyUnderstanding HTML terminology
Understanding HTML terminology
artembondar58 views
predicting-m3-devopsconMunich-2023-v2.pptx by Tier1 app
predicting-m3-devopsconMunich-2023-v2.pptxpredicting-m3-devopsconMunich-2023-v2.pptx
predicting-m3-devopsconMunich-2023-v2.pptx
Tier1 app14 views
How To Make Your Plans Suck Less — Maarten Dalmijn at the 57th Hands-on Agile... by Stefan Wolpers
How To Make Your Plans Suck Less — Maarten Dalmijn at the 57th Hands-on Agile...How To Make Your Plans Suck Less — Maarten Dalmijn at the 57th Hands-on Agile...
How To Make Your Plans Suck Less — Maarten Dalmijn at the 57th Hands-on Agile...
Stefan Wolpers44 views

Going bananas with recursion schemes for fixed point data types

  • 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/
  • 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. 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. Recursion “Recursion is where Functional Programming hits the bottom” - Greg Pfeil
  • 6. Recursion Schemes “Functional Programming with Bananas, Lenses, Envelopes and Barbed Wire” by Erik Meijer Maarten, Maarten Fokkinga and Ross Paterson [MFP91]
  • 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
  • 10. Recursive Structures are common ● Simplest examples ○ List: ■ Cons(a, List) ■ Nil ○ Binary Tree ■ Node(a, Tree, Tree) ■ Leaf(a)
  • 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. 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
  • 14. Expressions! Sum ( Square( IntValue(10) ) Multiply( DecValue(20.5), DecValue(14.5) ), ) Our example 102 + 20.5 * 14.5
  • 15. Expressions! Sum ( Square( IntValue(10) ) Multiply( DecValue(20.5), DecValue(14.5) ), ) Our example 102 + 20.5 * 14.5
  • 16. Expressions! Sum ( Square( IntValue(10) ) Multiply( DecValue(20.5), DecValue(14.5) ), ) Our example 102 + 20.5 * 14.5
  • 17. Expressions! Sum ( Square( IntValue(10) ) Multiply( DecValue(20.5), DecValue(14.5) ), ) Our example 102 + 20.5 * 14.5
  • 18. Expressions! Sum ( Square( IntValue(10) ) Multiply( DecValue(20.5), DecValue(14.5) ), ) Our example 102 + 20.5 * 14.5
  • 19. Expressions! Sum ( Square( IntValue(10) ) Multiply( DecValue(20.5), DecValue(14.5) ), Our example 102 + 20.5 * 14.5
  • 20. Expressions! Sum ( Square( IntValue(10) ) Multiply( DecValue(20.5), DecValue(14.5) ), ) Our example 102 + 20.5 * 14.5
  • 21. Expressions! Square ( Sum ( Square( IntValue(10) ) Multiply( DecValue(20.5), DecValue(14.5) ), ) ) Our example (102 + 20.5 * 14.5)2
  • 22. Expressions! Our example (102 + 20.5 * 14.5)2 Square Sum Square 10 Multiply 10 10
  • 23. data Exp = IntVal Int | DecVal Double | Sum Exp Exp | Multiply Exp Exp | Divide Exp Exp | Square Exp
  • 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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
  • 69. Fix
  • 72. case class Fix[F[_]](unFix: F[Fix[F]]) val exp1: Exp[Exp[Unit]] = Sum[Exp[Unit]]( IntValue[Unit](10), IntValue[Unit](5) )
  • 73. case class Fix[F[_]](unFix: F[Fix[F]]) val exp1: Exp[Exp[Unit]] = Sum[Exp[Unit]]( Fix(IntValue[Unit](10)), Fix(IntValue[Unit](5)) )
  • 74. 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)) )
  • 75. 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)) )
  • 76. 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)) ))
  • 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)) ))
  • 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]]( IntValue[Unit](10), IntValue[Unit](5)) ) )
  • 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[Exp[Unit]]( Fix(IntValue[Fix[Exp]](10)), Fix(IntValue[Fix[Exp]](5))) ) )
  • 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]]]( DecValue[Exp[Unit]](5.2), Sum[Fix[Exp]]( Fix(IntValue[Fix[Exp]](10)), Fix(IntValue[Fix[Exp]](5))) ) )
  • 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)), Sum[Fix[Exp]]( Fix(IntValue[Fix[Exp]](10)), Fix(IntValue[Fix[Exp]](5))) ) )
  • 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]]] = Divide[Exp[Exp[Unit]]]( Fix(DecValue[Fix[Exp]](5.2)), Fix(Sum[Fix[Exp]]( Fix(IntValue[Fix[Exp]](10)), Fix(IntValue[Fix[Exp]](5))) )) )
  • 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: 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))) )) ))
  • 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. 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))) )) ))
  • 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. 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. 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)) )) ))
  • 89. 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)
  • 90. 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)
  • 94. Missing Ingredients 1. Functor 2. Our Function a. a thing that is actually doing stuff
  • 96. Functor 101 trait Functor[F[_]] { def map[A, B](fa: F[A])(f: A => B): F[B] }
  • 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])
  • 98. 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)
  • 99. 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] = ???
  • 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] = ???
  • 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)
  • 102. 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)
  • 103. 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)
  • 104. 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] =
  • 105. 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) } }
  • 110. 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 }
  • 111. 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)" }
  • 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 }
  • 113. 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)) )) ))
  • 114. 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
  • 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)" }
  • 116. 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)) )) ))
  • 117. 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))
  • 118. 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)) }
  • 119. 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) }
  • 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) }
  • 121. 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)) )) ))
  • 122. 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))))))
  • 124. Anamorphism ● Constructs a structure from a value
  • 125. Anamorphism ● Constructs a structure from a value ● Co- part of catamorphism
  • 126. Anamorphism ● Constructs a structure from a value ● Co- part of catamorphism ● Instead of using Algebra[F[_], A] we will use Coalgebra[F[_], A]
  • 127. 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
  • 128. type Coalgebra[F[_], A] = A => F[A]
  • 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) }
  • 130. 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)
  • 131. 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))))))))
  • 133. Hylomorphism ● Constructs and then deconstructs a structure from a value
  • 134. Hylomorphism ● Constructs and then deconstructs a structure from a value ● Anamorphism followed by catamorphism
  • 135. Hylomorphism ● Constructs and then deconstructs a structure from a value ● Anamorphism followed by catamorphism ● Difference: evaluated in a single pass
  • 136. 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
  • 137. 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
  • 138. val divisors: Coalgebra[Exp, Int] = { … } // Double => Exp[Double] val evaluate: Algebra[Exp, Double] = { … } // Exp[Double] => Double
  • 139. 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) } }
  • 140. 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) } }
  • 142. 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!
  • 143. 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/