Recursion schemes in Scala
-
Upload
arthur-kushka -
Category
Engineering
-
view
207 -
download
4
Transcript of Recursion schemes in Scala
![Page 1: Recursion schemes in Scala](https://reader034.fdocuments.us/reader034/viewer/2022042507/587332391a28ab596c8b6d43/html5/thumbnails/1.jpg)
Recursionschemesin Scalaand also fixed point data types
![Page 2: Recursion schemes in Scala](https://reader034.fdocuments.us/reader034/viewer/2022042507/587332391a28ab596c8b6d43/html5/thumbnails/2.jpg)
Today we will speak about freakyfunctional stuff, enjoy :)Arthur Kushka // @Arhelmus
Yo
![Page 3: Recursion schemes in Scala](https://reader034.fdocuments.us/reader034/viewer/2022042507/587332391a28ab596c8b6d43/html5/thumbnails/3.jpg)
a method for structuring programs mainlyas sequences of possibly nested functionprocedure calls.
programmingFunctional
((x: Array[Byte]) => x) .andThen(encodeBase64) .andThen(name => s"Hello $name") .andThen(println)
![Page 4: Recursion schemes in Scala](https://reader034.fdocuments.us/reader034/viewer/2022042507/587332391a28ab596c8b6d43/html5/thumbnails/4.jpg)
everywhere!
Recursive schemasLists and treesFilesystemsDatabases
list match { // Cons(1, Cons(2, Cons(3, Nil))) case 1 :: 2 :: 3 :: Nil => case Nil => }
![Page 5: Recursion schemes in Scala](https://reader034.fdocuments.us/reader034/viewer/2022042507/587332391a28ab596c8b6d43/html5/thumbnails/5.jpg)
Example01
![Page 6: Recursion schemes in Scala](https://reader034.fdocuments.us/reader034/viewer/2022042507/587332391a28ab596c8b6d43/html5/thumbnails/6.jpg)
SumMultiplyDivideSquare
Math equasionevaluation
![Page 7: Recursion schemes in Scala](https://reader034.fdocuments.us/reader034/viewer/2022042507/587332391a28ab596c8b6d43/html5/thumbnails/7.jpg)
Lets define our DSL
sealed trait Expcase class IntValue(value: Int) extends Expcase class DecValue(value: Double) extends Exp
case class Sum(exp1: Exp, exp2: Exp) extends Expcase class Multiply(exp1: Exp, exp2: Exp) extends Expcase class Divide(exp1: Exp, exp2: Exp) extends Expcase class Square(exp: Exp) extends Exp
![Page 8: Recursion schemes in Scala](https://reader034.fdocuments.us/reader034/viewer/2022042507/587332391a28ab596c8b6d43/html5/thumbnails/8.jpg)
Exampleequation
Sum( Square( IntValue(4) ), Multiply( DecValue(3.3), IntValue(4) ) )
4^2 + 3.3 * 4
![Page 9: Recursion schemes in Scala](https://reader034.fdocuments.us/reader034/viewer/2022042507/587332391a28ab596c8b6d43/html5/thumbnails/9.jpg)
val evaluate: Exp => Double = { case DecValue(value) => value case IntValue(value) => value.toDouble case Sum(exp1, exp2) => evaluate(exp1) + evaluate(exp2) case Multiply(exp1, exp2) => evaluate(exp1) * evaluate(exp2) case Divide(exp1, exp2) => evaluate(exp1) / evaluate(exp2) case Square(exp) => val v = evaluate(exp) v * v }
![Page 10: Recursion schemes in Scala](https://reader034.fdocuments.us/reader034/viewer/2022042507/587332391a28ab596c8b6d43/html5/thumbnails/10.jpg)
val stringify: Exp => String = { case DecValue(value) => value.toString case IntValue(value) => value.toString case Sum(exp1, exp2) => s"${stringify(exp1)} + ${stringify(exp2)}" case Square(exp) => s"${stringify(exp)} ^ 2" case Multiply(exp1, exp2) => s"${stringify(exp1)} * ${stringify(exp2)}" case Divide(exp1, exp2) => s"${stringify(exp1)} / ${stringify(exp2)}" }
![Page 11: Recursion schemes in Scala](https://reader034.fdocuments.us/reader034/viewer/2022042507/587332391a28ab596c8b6d43/html5/thumbnails/11.jpg)
It will work!
but...
evaluate(expression) // prints 29.2stringify(expression) // prints 4 ^ 2 + 3.3 * 4
![Page 12: Recursion schemes in Scala](https://reader034.fdocuments.us/reader034/viewer/2022042507/587332391a28ab596c8b6d43/html5/thumbnails/12.jpg)
There are a lot ofmess
case Sum(exp1: Exp, exp2: Exp) => evaluate(exp1) + evaluate(exp2)
And not only...
![Page 13: Recursion schemes in Scala](https://reader034.fdocuments.us/reader034/viewer/2022042507/587332391a28ab596c8b6d43/html5/thumbnails/13.jpg)
Problem of partialinterpretation
val optimize: Exp => Exp = { case Multiply(exp1, exp2) if exp1 == exp2 => Square(optimize(exp1)) case other => ???}
Lets improve
![Page 14: Recursion schemes in Scala](https://reader034.fdocuments.us/reader034/viewer/2022042507/587332391a28ab596c8b6d43/html5/thumbnails/14.jpg)
going toresulttypes02
![Page 15: Recursion schemes in Scala](https://reader034.fdocuments.us/reader034/viewer/2022042507/587332391a28ab596c8b6d43/html5/thumbnails/15.jpg)
Generalize it
sealed trait Exp[T]case class IntValue[T](value: Int) extends Exp[T]case class DecValue[T](value: Double) extends Exp[T]
case class Sum[T](exp1: T, exp2: T) extends Exp[T]case class Multiply[T](exp1: T, exp2: T) extends Exp[T]case class Divide[T](exp1: T, exp2: T) extends Exp[T]case class Square[T](exp: T) extends Exp[T]
![Page 16: Recursion schemes in Scala](https://reader034.fdocuments.us/reader034/viewer/2022042507/587332391a28ab596c8b6d43/html5/thumbnails/16.jpg)
val expression: Exp[Exp[Exp[Unit]]] =Sum[Exp[Exp[Unit]]]( Square[Exp[Unit]]( IntValue[Unit](4) ), Multiply[Exp[Unit]]( DecValue[Unit](3.3), IntValue[Unit](4) ) )
Nesting types issue
![Page 17: Recursion schemes in Scala](https://reader034.fdocuments.us/reader034/viewer/2022042507/587332391a28ab596c8b6d43/html5/thumbnails/17.jpg)
its like a hiding of part that doesn't matter
fixed point types
![Page 18: Recursion schemes in Scala](https://reader034.fdocuments.us/reader034/viewer/2022042507/587332391a28ab596c8b6d43/html5/thumbnails/18.jpg)
F[_] is a generic type with a hole, afterwrapping of Exp with that we will haveFix[Exp] type.
let's addtypehack
case class Fix[F[_]](unFix: F[Fix[F]])
![Page 19: Recursion schemes in Scala](https://reader034.fdocuments.us/reader034/viewer/2022042507/587332391a28ab596c8b6d43/html5/thumbnails/19.jpg)
val expression: Fix[Exp] = Fix(Sum( Fix(Square( Fix(IntValue(4)) )), Fix(Multiply( Fix(DecValue(3.3)), Fix(IntValue(4)) )) ))
Hacked code
![Page 20: Recursion schemes in Scala](https://reader034.fdocuments.us/reader034/viewer/2022042507/587332391a28ab596c8b6d43/html5/thumbnails/20.jpg)
case class Square[T](exp: T) extends Exp[T]object Square { def apply(fixExp: Exp[Fix[Exp]]) = Fix[Exp](fixExp)}
val expression: Fix[Exp] = Square( Square( Square( IntValue(4) )))
Let's do it cleaner
![Page 21: Recursion schemes in Scala](https://reader034.fdocuments.us/reader034/viewer/2022042507/587332391a28ab596c8b6d43/html5/thumbnails/21.jpg)
time to traverseour structure03
![Page 22: Recursion schemes in Scala](https://reader034.fdocuments.us/reader034/viewer/2022042507/587332391a28ab596c8b6d43/html5/thumbnails/22.jpg)
def map[F[_], A, B](fa: F[A])(f: A=>B): F[B]
Functor 911
![Page 23: Recursion schemes in Scala](https://reader034.fdocuments.us/reader034/viewer/2022042507/587332391a28ab596c8b6d43/html5/thumbnails/23.jpg)
Scalaz example
case class Container[T](data: T)
implicit val functor = new Functor[Container] { override def map[A, B](fa: Container[A]) (f: A => B): Container[B] = Container(f(fa.data)) }
functor.map(Container(1))(_.toString) // "1"
For cats you will have same code
![Page 24: Recursion schemes in Scala](https://reader034.fdocuments.us/reader034/viewer/2022042507/587332391a28ab596c8b6d43/html5/thumbnails/24.jpg)
implicit val functor = new Functor[Exp] {
override def map[A, B](fa: Exp[A])(f: A => B): Exp[B] =
fa match {
case IntValue(v) => IntValue(v)
case DecValue(v) => DecValue(v)
case Sum(v1, v2) => Sum(f(v1), f(v2))
case Multiply(v1, v2) => Multiply(f(v1), f(v2))
case Divide(v1, v2) => Divide(f(v1), f(v2))
case Square(v) => Square(f(v))
}
}
![Page 25: Recursion schemes in Scala](https://reader034.fdocuments.us/reader034/viewer/2022042507/587332391a28ab596c8b6d43/html5/thumbnails/25.jpg)
catamorphismanamorphismhylomorphism04
![Page 26: Recursion schemes in Scala](https://reader034.fdocuments.us/reader034/viewer/2022042507/587332391a28ab596c8b6d43/html5/thumbnails/26.jpg)
“Functional Programming with Bananas,Lenses, Envelopes and Barbed Wire”, byErik Meijer
generalized folding operation
catamorphism
![Page 27: Recursion schemes in Scala](https://reader034.fdocuments.us/reader034/viewer/2022042507/587332391a28ab596c8b6d43/html5/thumbnails/27.jpg)
Lets defineAlgebratype Algebra[F[_], A] = F[A] => Aval evaluate: Algebra[Exp, Double] = { case IntValue(v) => v.toDouble case DecValue(v) => v case Sum(v1, v2) => v1 + v2 case Multiply(v1, v2) => v1 * v2 case Divide(v1, v2) => v1 / v2 case Square(v) => Math.sqrt(v) }
![Page 28: Recursion schemes in Scala](https://reader034.fdocuments.us/reader034/viewer/2022042507/587332391a28ab596c8b6d43/html5/thumbnails/28.jpg)
So as a result
val expression: Fix[Exp] = Sum( Multiply(IntValue(4), IntValue(4)), Multiply(DecValue(3.3), IntValue(4)) )
import matryoshka.implicits._expression.cata(evaluate) // 29.2
![Page 29: Recursion schemes in Scala](https://reader034.fdocuments.us/reader034/viewer/2022042507/587332391a28ab596c8b6d43/html5/thumbnails/29.jpg)
do you remember about partial interpretation?
Extra profit
val optimize: Algebra[Exp, Fix[Exp]] = { case Multiply(Fix(exp), Fix(exp2)) if exp == exp2 => Fix(Square(exp)) case other => Fix[Exp](other) }
import matryoshka.implicits._expression.cata(optimize).cata(stringify) // 4 ^ 2 + 3.3 * 4
![Page 30: Recursion schemes in Scala](https://reader034.fdocuments.us/reader034/viewer/2022042507/587332391a28ab596c8b6d43/html5/thumbnails/30.jpg)
val evaluate: Exp => Double = { case DecValue(value) => value case IntValue(value) => value.toDouble case Sum(exp1, exp2) => evaluate(exp1) + evaluate(exp2) case Multiply(exp1, exp2) => evaluate(exp1) * evaluate(exp2) case Divide(exp1, exp2) => evaluate(exp1) / evaluate(exp2) case Square(exp) => val v = evaluate(exp) v * v }
type Algebra[F[_], A]val evaluate: Algebra[Exp, Double] = { case IntValue(v) => v.toDouble case DecValue(v) => v case Sum(v1, v2) => v1 + v2 case Multiply(v1, v2) => v1 * v2 case Divide(v1, v2) => v1 / v2 case Square(v) => Math.sqrt(v) }
![Page 31: Recursion schemes in Scala](https://reader034.fdocuments.us/reader034/viewer/2022042507/587332391a28ab596c8b6d43/html5/thumbnails/31.jpg)
catamorphism: F[_] => A anamorphism: A => F[_] hylomorphism: F[_] => A => F[_]
Just good toknow
![Page 32: Recursion schemes in Scala](https://reader034.fdocuments.us/reader034/viewer/2022042507/587332391a28ab596c8b6d43/html5/thumbnails/32.jpg)
Fixed point types is perfect to createDSLsRecursion schemas is composableAll you need to use that stuff, youalready know from Scala
Summary
![Page 33: Recursion schemes in Scala](https://reader034.fdocuments.us/reader034/viewer/2022042507/587332391a28ab596c8b6d43/html5/thumbnails/33.jpg)
thank you.any questions?