Grade 8 TX Obj 2: Patterns, relationships, and algebraic thinking.
Algebraic Data Types and Origami Patterns
-
Upload
vasil-remeniuk -
Category
Technology
-
view
4.360 -
download
1
Transcript of Algebraic Data Types and Origami Patterns
![Page 1: Algebraic Data Types and Origami Patterns](https://reader035.fdocuments.in/reader035/viewer/2022081403/5550f5fbb4c90572478b462a/html5/thumbnails/1.jpg)
ORIGAMI patterns with Algebraic Data Types
@remeniuk
![Page 2: Algebraic Data Types and Origami Patterns](https://reader035.fdocuments.in/reader035/viewer/2022081403/5550f5fbb4c90572478b462a/html5/thumbnails/2.jpg)
What is “algebra”?
1. A set of elements 2.Some operations that map
elements to elements
![Page 3: Algebraic Data Types and Origami Patterns](https://reader035.fdocuments.in/reader035/viewer/2022081403/5550f5fbb4c90572478b462a/html5/thumbnails/3.jpg)
List
1. Elements: “list” and “list element”
2.Operations: Nil and ::(cons)
![Page 4: Algebraic Data Types and Origami Patterns](https://reader035.fdocuments.in/reader035/viewer/2022081403/5550f5fbb4c90572478b462a/html5/thumbnails/4.jpg)
In programming languages, algebraic data types are defined with the set of constructors that wrap other types
![Page 5: Algebraic Data Types and Origami Patterns](https://reader035.fdocuments.in/reader035/viewer/2022081403/5550f5fbb4c90572478b462a/html5/thumbnails/5.jpg)
Haskell offers a very expressive syntax for defining Algebraic Data Types.
data Boolean = True | False
Here's how Boolean can be implemented:
![Page 6: Algebraic Data Types and Origami Patterns](https://reader035.fdocuments.in/reader035/viewer/2022081403/5550f5fbb4c90572478b462a/html5/thumbnails/6.jpg)
data Boolean = True | False
This is a closed data type - once you've declared the constructors, you no longer can add more dynamically
True and False are data type constructors
![Page 7: Algebraic Data Types and Origami Patterns](https://reader035.fdocuments.in/reader035/viewer/2022081403/5550f5fbb4c90572478b462a/html5/thumbnails/7.jpg)
In Scala, algebraic data type declaration
is a bit more verbose...
![Page 8: Algebraic Data Types and Origami Patterns](https://reader035.fdocuments.in/reader035/viewer/2022081403/5550f5fbb4c90572478b462a/html5/thumbnails/8.jpg)
sealed trait Boolean case object True extends Boolean case object False extends Boolean
*sealed closes the data type!
![Page 9: Algebraic Data Types and Origami Patterns](https://reader035.fdocuments.in/reader035/viewer/2022081403/5550f5fbb4c90572478b462a/html5/thumbnails/9.jpg)
Scala vs Haskell
Simple extensibility via inheritence - open data types
Syntactic clarity >
![Page 10: Algebraic Data Types and Origami Patterns](https://reader035.fdocuments.in/reader035/viewer/2022081403/5550f5fbb4c90572478b462a/html5/thumbnails/10.jpg)
Regular algebraic data types
• Unit type
• Sum type: data Boolean = True | False
• Singleton type : data X a = X a
Combination of sum and singleton : Either a b = Left a | Right b
• Product type: data List a = Nil|a :: List a
(combination of unit, sum and product)
• Recursive type
![Page 11: Algebraic Data Types and Origami Patterns](https://reader035.fdocuments.in/reader035/viewer/2022081403/5550f5fbb4c90572478b462a/html5/thumbnails/11.jpg)
data ListI = NilI | ConsI Integer ListI
List of Integers in Haskell:
![Page 12: Algebraic Data Types and Origami Patterns](https://reader035.fdocuments.in/reader035/viewer/2022081403/5550f5fbb4c90572478b462a/html5/thumbnails/12.jpg)
data ListI = NilI | ConsI Integer ListI
Usage:
let list = ConsI 3 (ConsI 2 (ConsI 1 NilI))
![Page 13: Algebraic Data Types and Origami Patterns](https://reader035.fdocuments.in/reader035/viewer/2022081403/5550f5fbb4c90572478b462a/html5/thumbnails/13.jpg)
Not much more complex in Scala...
trait ListI case object NilI extends ListI case class ConsI(head: Int, tail: ListI) extends ListI
![Page 14: Algebraic Data Types and Origami Patterns](https://reader035.fdocuments.in/reader035/viewer/2022081403/5550f5fbb4c90572478b462a/html5/thumbnails/14.jpg)
...especially, with some convenience methods...
trait ListI { def ::(value: Int) = ConsI(value, this) } case object NilI extends ListI case class ConsI(value: Int, list: ListI) extends ListI
![Page 15: Algebraic Data Types and Origami Patterns](https://reader035.fdocuments.in/reader035/viewer/2022081403/5550f5fbb4c90572478b462a/html5/thumbnails/15.jpg)
...and here we are:
val list = 3 :: 2 :: 1 :: NilI
![Page 16: Algebraic Data Types and Origami Patterns](https://reader035.fdocuments.in/reader035/viewer/2022081403/5550f5fbb4c90572478b462a/html5/thumbnails/16.jpg)
Lets make our data types
more useful
![Page 17: Algebraic Data Types and Origami Patterns](https://reader035.fdocuments.in/reader035/viewer/2022081403/5550f5fbb4c90572478b462a/html5/thumbnails/17.jpg)
...making them parametrically polymorphic
trait ListI { def ::(value: Int) = ConsI(value, this) } case object NilI extends ListI case class ConsI(value: Int, list: ListI) extends ListI
BEFORE:
![Page 18: Algebraic Data Types and Origami Patterns](https://reader035.fdocuments.in/reader035/viewer/2022081403/5550f5fbb4c90572478b462a/html5/thumbnails/18.jpg)
...making them parametrically polymorphic
sealed trait ListG[+A] { def ::[B >: A](value: B) = ConsG[B](value, this) } case object NilG extends ListG[Nothing] case class ConsG[A](head: A, tail: ListG[A]) extends ListG[A]
AFTER:
![Page 19: Algebraic Data Types and Origami Patterns](https://reader035.fdocuments.in/reader035/viewer/2022081403/5550f5fbb4c90572478b462a/html5/thumbnails/19.jpg)
Defining a simple, product algebraic type for binary tree is a no-brainer:
sealed trait BTreeG[+A] case class Tip[A](value: A) extends BTreeG[A]
case class Bin[A](left: BTreeG[A], right: BTreeG[A]) extends BTreeG[A]
![Page 20: Algebraic Data Types and Origami Patterns](https://reader035.fdocuments.in/reader035/viewer/2022081403/5550f5fbb4c90572478b462a/html5/thumbnails/20.jpg)
ListG and BTreeG are Generalized Algebraic Data Types
And the programming approach itself is called Generic
Programming
![Page 21: Algebraic Data Types and Origami Patterns](https://reader035.fdocuments.in/reader035/viewer/2022081403/5550f5fbb4c90572478b462a/html5/thumbnails/21.jpg)
Let's say, we want to find a sum of all the elements in the ListG and BTreeG, now...
![Page 22: Algebraic Data Types and Origami Patterns](https://reader035.fdocuments.in/reader035/viewer/2022081403/5550f5fbb4c90572478b462a/html5/thumbnails/22.jpg)
Let's say, we want to find a sum of all the elements in the ListG and BTreeG, now...
fold
![Page 23: Algebraic Data Types and Origami Patterns](https://reader035.fdocuments.in/reader035/viewer/2022081403/5550f5fbb4c90572478b462a/html5/thumbnails/23.jpg)
def foldL[B](n: B)(f: (B, A) => B) (list: ListG[A]): B = list match { case NilG => n case ConsG(head, tail) => f(foldL(n)(f)(tail), head) } }
foldL[Int, Int](0)(_ + _)(list)
![Page 24: Algebraic Data Types and Origami Patterns](https://reader035.fdocuments.in/reader035/viewer/2022081403/5550f5fbb4c90572478b462a/html5/thumbnails/24.jpg)
def foldT[B](f: A => B)(g: (B, B) => B) (tree: BTreeG[A]): B = tree match { case Tip(value) => f(value) case Bin(left, right) => g(foldT(f)(g)(tree),foldT(f)(g)(tree)) }
foldT[Int, Int](0)(x => x)(_ + _)(tree)
![Page 25: Algebraic Data Types and Origami Patterns](https://reader035.fdocuments.in/reader035/viewer/2022081403/5550f5fbb4c90572478b462a/html5/thumbnails/25.jpg)
Obviously, foldL and foldT have very much in common.
![Page 26: Algebraic Data Types and Origami Patterns](https://reader035.fdocuments.in/reader035/viewer/2022081403/5550f5fbb4c90572478b462a/html5/thumbnails/26.jpg)
Obviously, foldL and foldT have very much in common.
In fact, the biggest difference is in
the shape of the data
![Page 27: Algebraic Data Types and Origami Patterns](https://reader035.fdocuments.in/reader035/viewer/2022081403/5550f5fbb4c90572478b462a/html5/thumbnails/27.jpg)
That would be great, if we could abstract away from data type...
![Page 28: Algebraic Data Types and Origami Patterns](https://reader035.fdocuments.in/reader035/viewer/2022081403/5550f5fbb4c90572478b462a/html5/thumbnails/28.jpg)
That would be great, if we could abstract away from data type...
With Datatype Generic programming we can!
![Page 29: Algebraic Data Types and Origami Patterns](https://reader035.fdocuments.in/reader035/viewer/2022081403/5550f5fbb4c90572478b462a/html5/thumbnails/29.jpg)
Requirements:
• Fix data type (recursive data type) • Datatype-specific instance of
Bifunctor
![Page 30: Algebraic Data Types and Origami Patterns](https://reader035.fdocuments.in/reader035/viewer/2022081403/5550f5fbb4c90572478b462a/html5/thumbnails/30.jpg)
1. Fix type
Fix [F [_, _], A]
Higher-kinded shape (pair, list, tree,...)
Type parameter of the shape
![Page 31: Algebraic Data Types and Origami Patterns](https://reader035.fdocuments.in/reader035/viewer/2022081403/5550f5fbb4c90572478b462a/html5/thumbnails/31.jpg)
Let's create an instance of Fix for List shape
trait ListF[+A, +B] case object NilF extends ListF[Nothing, Nothing] case class ConsF[A, B](head: A, tail: B) extends ListF[A, B]
type List[A] = Fix[ListF, A]
![Page 32: Algebraic Data Types and Origami Patterns](https://reader035.fdocuments.in/reader035/viewer/2022081403/5550f5fbb4c90572478b462a/html5/thumbnails/32.jpg)
2. Datatype-specific instance of Bifunctor
trait Bifunctor[F[_, _]] { def bimap[A, B, C, D](k: F[A, B], f: A => C, g: B => D): F[C, D] }
Defines mapping for the shape
![Page 33: Algebraic Data Types and Origami Patterns](https://reader035.fdocuments.in/reader035/viewer/2022081403/5550f5fbb4c90572478b462a/html5/thumbnails/33.jpg)
Bifunctor instance for ListF
implicit val listFBifunctor = new Bifunctor[ListF]{ def bimap[A, B, C, D](k: ListF[A,B], f: A => C, g: B => D): ListF[C,D] = k match { case NilF => NilF case ConsF(head, tail) => ConsF(f(head), g(tail)) } }
![Page 34: Algebraic Data Types and Origami Patterns](https://reader035.fdocuments.in/reader035/viewer/2022081403/5550f5fbb4c90572478b462a/html5/thumbnails/34.jpg)
It turns out, that a wide number of other generic operations on data types can be expressed via bimap!
![Page 35: Algebraic Data Types and Origami Patterns](https://reader035.fdocuments.in/reader035/viewer/2022081403/5550f5fbb4c90572478b462a/html5/thumbnails/35.jpg)
def map[A, B, F [_, _]](f : A => B)(t : Fix [F, A]) (implicit ft : Bifunctor [F]) : Fix [F, B] def fold[A, B, F [_, _]](f : F[A, B] => B)(t : Fix[F,A]) (implicit ft : Bifunctor [F]) : B def unfold [A, B, F [_, _]] (f : B => F[A, B]) (b : B) (implicit ft : Bifunctor [F]) : Fix[F, A] def hylo [A, B, C, F [_, _]] (f : B => F[A, B]) (g : F[A, C] => C)(b: B) (implicit ft : Bifunctor [F]) : C def build [A, F [_, _]] (f : {def apply[B]: (F [A, B] => B) => B}): Fix[F, A]
See http://goo.gl/I4OBx
![Page 36: Algebraic Data Types and Origami Patterns](https://reader035.fdocuments.in/reader035/viewer/2022081403/5550f5fbb4c90572478b462a/html5/thumbnails/36.jpg)
This approach is called
Origami patterns • Origami patterns can be applied to generic
data types!
• Include the following GoF patterns o Composite (algebraic data type itself) o Iterator (map) o Visitor (fold / hylo) o Builder (build / unfold)
![Page 37: Algebraic Data Types and Origami Patterns](https://reader035.fdocuments.in/reader035/viewer/2022081403/5550f5fbb4c90572478b462a/html5/thumbnails/37.jpg)
Those operations are called
Origami patterns • The patterns can be applied to generic data
types!
• Include the following GoF patterns o Composite (algebraic data type itself) o Iterator (map) o Visitor (fold) o Builder (build / unfold / hylo)
30 loc
vs 250 loc in pure Java
![Page 38: Algebraic Data Types and Origami Patterns](https://reader035.fdocuments.in/reader035/viewer/2022081403/5550f5fbb4c90572478b462a/html5/thumbnails/38.jpg)
Live demo! http://goo.gl/ysv5Y
![Page 39: Algebraic Data Types and Origami Patterns](https://reader035.fdocuments.in/reader035/viewer/2022081403/5550f5fbb4c90572478b462a/html5/thumbnails/39.jpg)
Thanks for watching!