SlideShare une entreprise Scribd logo
1  sur  8
Télécharger pour lire hors ligne
CHEAT-SHEET
Folding
#4
∶
/ 
𝒂𝟎 ∶
/ 
𝒂𝟏 ∶
/ 
𝒂𝟐 ∶
/ 
𝒂𝟑
𝒇
/ 
𝒂𝟎 𝒇
/ 
𝒂𝟏 𝒇
/ 
𝒂𝟐 𝒇
/ 
𝒂𝟑 𝒆
@philip_schwarz
slides by https://fpilluminated.com/
We want to write function 𝒅𝒆𝒄𝒊𝒎𝒂𝒍, which given the digits of an integer number
[𝑑0, 𝑑1, … , 𝑑𝑛]
computes the integer value of the number
-
&'(
)
𝑑𝑘 ∗ 10)*&
Thanks to the universal property of fold, if we are able to define 𝒅𝒆𝒄𝒊𝒎𝒂𝒍 so that its equations match those on the left hand side of the
following equivalence, then we are also able to implement 𝒅𝒆𝒄𝒊𝒎𝒂𝒍 using a right fold
i.e. given 𝑓𝑜𝑙𝑑𝑟
𝑓𝑜𝑙𝑑𝑟 :: 𝛼 → 𝛽 → 𝛽 → 𝛽 → 𝛼 → 𝛽
𝑓𝑜𝑙𝑑𝑟 𝑓 𝑣 = 𝑣
𝑓𝑜𝑙𝑑𝑟 𝑓 𝑣 𝑥 ∶ 𝑥𝑠 = 𝑓 𝑥 𝑓𝑜𝑙𝑑𝑟 𝑓 𝑣 𝑥𝑠
we can reimplement 𝒅𝒆𝒄𝒊𝒎𝒂𝒍 like this:
𝒅𝒆𝒄𝒊𝒎𝒂𝒍 = 𝑓𝑜𝑙𝑑𝑟 𝑓 𝑣
The universal property of 𝒇𝒐𝒍𝒅
𝒈 = 𝒗 ⟺ 𝒈 = 𝒇𝒐𝒍𝒅 𝒇 𝒗 𝒈 :: 𝛼 → 𝛽
𝒈 𝑥 ∶ 𝑥𝑠 = 𝒇 𝑥 𝒈 𝑥𝑠 𝒗 :: 𝛽
𝒇 :: 𝛼 → 𝛽 → 𝛽
scala> decimal(List(1,2,3,4))
val res0: Int = 1234
haskell> decimal [1,2,3,4]
1234
𝑑0 ∗ 103 + 𝑑1 ∗ 102 + 𝑑2 ∗ 101 + 𝑑3 ∗ 100 = 1 ∗ 1000 + 2 ∗ 100 + 3 ∗ 10 + 4 ∗ 1 = 1234
Notice that 𝒇 has two parameters: the head of the list, and the result of recursively calling 𝒈 with the tail of the list
𝒈 𝑥 ∶ 𝑥𝑠 = 𝒇 𝑥 𝒈 𝑥𝑠
In order to define our 𝒅𝒆𝒄𝒊𝒎𝒂𝒍 function however, the two parameters of 𝒇 are not sufficient. When 𝒅𝒆𝒄𝒊𝒎𝒂𝒍 is passed [𝑑𝑘, … , 𝑑𝑛], 𝒇 is
passed digit 𝑑𝑘, so 𝒇 needs 𝑛 and 𝑘 in order to compute 10)*&
, but 𝑛 − 𝑘 is the number of elements in [𝑑𝑘, … , 𝑑𝑛] minus one, so by nesting
the definition of 𝒇 inside that of 𝒅𝒆𝒄𝒊𝒎𝒂𝒍, we can avoid explicitly adding a third parameter to 𝒇 :
We nested 𝒇 inside 𝒅𝒆𝒄𝒊𝒎𝒂𝒍, so that the equations of 𝒅𝒆𝒄𝒊𝒎𝒂𝒍 match (almost) those of 𝒈. They don’t match perfectly, in that the 𝒇 nested
inside 𝒅𝒆𝒄𝒊𝒎𝒂𝒍 depends on 𝒅𝒆𝒄𝒊𝒎𝒂𝒍’s list parameter, whereas the 𝒇 nested inside 𝒈 does not depend on 𝒈’s list parameter. Are we still able
to redefine 𝒅𝒆𝒄𝒊𝒎𝒂𝒍 using 𝑓𝑜𝑙𝑑𝑟? If the match had been perfect, we would be able to define 𝒅𝒆𝒄𝒊𝒎𝒂𝒍 = 𝑓𝑜𝑙𝑑𝑟 𝑓 0 (with 𝒗 = 0), but
because 𝒇 needs to know the value of 𝑛 − 𝑘, we can’t just pass 𝒇 to 𝑓𝑜𝑙𝑑𝑟, and use 0 as the initial accumulator. Instead, we need to use (0, 0)
as the accumulator (the second 0 being the initial value of 𝑛 − 𝑘, when 𝑘 = 𝑛), and pass to 𝑓𝑜𝑙𝑑𝑟 a helper function ℎ that manages 𝑛 − 𝑘
and that wraps 𝒇, so that the latter has access to 𝑛 − 𝑘.
def h(d: Int, acc: (Int,Int)): (Int,Int) = acc match { case (ds, e) =>
def f(d: Int, ds: Int): Int =
d * Math.pow(10, e).toInt + ds
(f(d, ds), e + 1)
}
def decimal(ds: List[Int]): Int =
ds.foldRight((0,0))(h).head
h :: Int -> (Int,Int) -> (Int,Int)
h d (ds, e) = (f d ds, e + 1) where
f :: Int -> Int -> Int
f d ds = d * (10 ^ e) + ds
decimal :: [Int] -> Int
decimal ds = fst (foldr h (0,0) ds)
def decimal(digits: List[Int]): Int =
val e = digits.length-1
def f(d: Int, ds: Int): Int =
d * Math.pow(10, e).toInt + ds
digits match
case Nil => 0
case d +: ds => f(d, decimal(ds))
decimal :: [Int] -> Int
decimal [] = 0
decimal (d:ds) = f d (decimal ds) where
e = length ds
f :: Int -> Int -> Int
f d ds = d * (10 ^ e) + ds
The unnecessary complexity
of the 𝒅𝒆𝒄𝒊𝒎𝒂𝒍 functions
on this slide is purely due to
them being defined in terms
of 𝒇 . See next slide for
simpler refactored versions
in which 𝒇 is inlined.
def f(d: Int, acc: (Int,Int)): (Int,Int) = acc match
case (ds, e) => (d * Math.pow(10, e).toInt + ds, e + 1)
def decimal(ds: List[Int]): Int =
ds.foldRight((0,0))(f).head
f :: Int -> (Int,Int) -> (Int,Int)
f d (ds, e) = (d * (10 ^ e) + ds, e + 1)
decimal :: [Int] -> Int
decimal ds = fst (foldr f (0,0) ds)
def decimal(digits: List[Int]): Int = digits match
case Nil => 0
case d +: ds => d * Math.pow(10, ds.length).toInt + decimal(ds)
decimal :: [Int] -> Int
decimal [] = 0
decimal (d:ds) = d*(10^(length ds))+(decimal ds)
Same 𝒅𝒆𝒄𝒊𝒎𝒂𝒍 functions as on the previous slide, but refactored as follows:
1. inlined 𝒇 in all four functions
2. inlined e in the first two functions
3. renamed 𝒉 to 𝒇 in the last two functions
Not every function on lists can be defined as an instance of 𝑓𝑜𝑙𝑑𝑟. For example, zip cannot be so defined. Even for those that
can, an alternative definition may be more efficient. To illustrate, suppose we want a function decimal that takes a list of digits
and returns the corresponding decimal number; thus
𝑑𝑒𝑐𝑖𝑚𝑎𝑙 [𝑥0, 𝑥1, … , 𝑥n] = ∑!"#
$
𝑥𝑘10($&!)
It is assumed that the most significant digit comes first in the list. One way to compute decimal efficiently is by a process of
multiplying each digit by ten and adding in the following digit. For example
𝑑𝑒𝑐𝑖𝑚𝑎𝑙 𝑥0, 𝑥1, 𝑥2 = 10 × 10 × 10 × 0 + 𝑥0 + 𝑥1 + 𝑥2
This decomposition of a sum of powers is known as Horner’s rule.
Suppose we define ⊕ by 𝑛 ⊕ 𝑥 = 10 × 𝑛 + 𝑥. Then we can rephrase the above equation as
𝑑𝑒𝑐𝑖𝑚𝑎𝑙 𝑥0, 𝑥1, 𝑥2 = (0 ⊕ 𝑥0) ⊕ 𝑥1 ⊕ 𝑥2
This is almost like an instance of 𝑓𝑜𝑙𝑑𝑟, except that the grouping is the other way round, and the starting value appears on the
left, not on the right. In fact the computation is dual: instead of processing from right to left, the computation processes from
left to right.
This example motivates the introduction of a second fold operator called 𝑓𝑜𝑙𝑑𝑙 (pronounced ‘fold left’). Informally:
𝑓𝑜𝑙𝑑𝑙 ⊕ 𝑒 𝑥0, 𝑥1, … , 𝑥𝑛 − 1 = … ((𝑒 ⊕ 𝑥0) ⊕ 𝑥1) … ⊕ 𝑥𝑛 − 1
The parentheses group from the left, which is the reason for the name. The full definition of 𝑓𝑜𝑙𝑑𝑙 is
𝑓𝑜𝑙𝑑𝑙 ∷ 𝛽 → 𝛼 → 𝛽 → 𝛽 → 𝛼 → 𝛽
𝑓𝑜𝑙𝑑𝑙 𝑓 𝑒 = 𝑒
𝑓𝑜𝑙𝑑𝑙 𝑓 𝑒 𝑥: 𝑥𝑠 = 𝑓𝑜𝑙𝑑𝑙 𝑓 𝑓 𝑒 𝑥 𝑥𝑠
Richard Bird
The definition of 𝒅𝒆𝒄𝒊𝒎𝒂𝒍 using a right fold is inefficient because it computes ∑!"#
$
𝑑𝑘 ∗ 10$&!
by computing 10$&!
for each 𝑘.
If we look back at our initial recursive definition of 𝒅𝒆𝒄𝒊𝒎𝒂𝒍, we see that it splits its list parameter into a head and a tail.
If we get 𝒅𝒆𝒄𝒊𝒎𝒂𝒍 to split the list into init and last, we can make it more efficient by using Horner’s rule:
We can then improve on that by going back to splitting the list into a head and a tail, and making 𝒅𝒆𝒄𝒊𝒎𝒂𝒍 tail recursive:
And finally, we can improve on that by defining 𝒅𝒆𝒄𝒊𝒎𝒂𝒍 using a left fold:
(⊕) :: Int -> Int -> Int
n ⊕ d = 10 * n + d
decimal :: [Int] -> Int
decimal [] = 0
decimal (d:ds) = d*(10^(length ds)) + (decimal ds)
def decimal(digits: List[Int]): Int = digits match
case Nil => 0
case d +: ds => d * Math.pow(10, ds.length).toInt + decimal(ds)
extension (n: Int)
def ⊕(d Int): Int = 10 * n + d
decimal :: [Int] -> Int -> Int
decimal [] acc = acc
decimal (d:ds) acc = decimal ds (acc ⊕d)
def decimal(ds: List[Int], acc: Int=0): Int = digits match
case Nil => acc
case d +: ds => decimal(ds, acc ⊕ d)
decimal :: [Int] -> Int
decimal = foldl (⊕) 0
decimal :: [Int] -> Int
decimal [] = 0
decimal ds = (decimal (init ds)) ⊕ (last ds)
def decimal(digits: List[Int]): Int = digits match
case Nil => 0
case ds :+ d => decimal(ds) ⊕ d
def decimal(ds: List[Int]): Int =
ds.foldLeft(0)(_⊕_)
Recap
In the case of the 𝒅𝒆𝒄𝒊𝒎𝒂𝒍 function, defining it using a left fold is simple and mathematically more efficient
whereas defining it using a right fold is more complex and mathematically less efficient
def decimal(ds: List[Int]): Int =
ds.foldRight((0,0))(f).head
def f(d: Int, acc: (Int,Int)): (Int,Int) = acc match
case (ds, e) => (d * Math.pow(10, e).toInt + ds, e + 1)
decimal :: [Int] -> Int
decimal ds = fst (foldr f (0,0) ds)
f :: Int -> (Int,Int) -> (Int,Int)
f d (ds, e) = (d * (10 ^ e) + ds, e + 1)
decimal :: [Int] -> Int
decimal = foldl (⊕) 0
(⊕) :: Int -> Int -> Int
n ⊕ d = 10 * n + d
def decimal(ds: List[Int]): Int =
ds.foldLeft(0)(_⊕_)
extension (n: Int)
def ⊕(d Int): Int = 10 * n + d
𝒅𝒆𝒄𝒊𝒎𝒂𝒍 1,2,3,4 = 𝑑0 ∗ 103 + (𝑑1 ∗ 102 + (𝑑2 ∗ 101 + (𝑑3 ∗ 100 + 0))) = 1 ∗ 1000 + (2 ∗ 100 + (3 ∗ 10 + (4 ∗ 1 + 0))) = 1234
𝒅𝒆𝒄𝒊𝒎𝒂𝒍 1,2,3,4 = 10 ∗ 10 ∗ 10 ∗ 10 ∗ 0 + 𝑑0 + 𝑑1 + 𝑑2 + 𝑑3 = 10 ∗ (10 ∗ 10 ∗ 10 ∗ 0 + 1 + 2 + 3) + 4 = 1234
https://fpilluminated.com/
inspired
by

Contenu connexe

Similaire à Folding Cheat Sheet #4 - fourth in a series

Teeing Up Python - Code Golf
Teeing Up Python - Code GolfTeeing Up Python - Code Golf
Teeing Up Python - Code GolfYelp Engineering
 
Lecture 01 reals number system
Lecture 01 reals number systemLecture 01 reals number system
Lecture 01 reals number systemHazel Joy Chong
 
Python 04-ifelse-return-input-strings.pptx
Python 04-ifelse-return-input-strings.pptxPython 04-ifelse-return-input-strings.pptx
Python 04-ifelse-return-input-strings.pptxTseChris
 
Complex function
Complex functionComplex function
Complex functionShrey Patel
 
23UCACC11 Python Programming (MTNC) (BCA)
23UCACC11 Python Programming (MTNC) (BCA)23UCACC11 Python Programming (MTNC) (BCA)
23UCACC11 Python Programming (MTNC) (BCA)ssuser7f90ae
 
Lists.pptx
Lists.pptxLists.pptx
Lists.pptxYagna15
 
Scala. Introduction to FP. Monads
Scala. Introduction to FP. MonadsScala. Introduction to FP. Monads
Scala. Introduction to FP. MonadsKirill Kozlov
 
iRODS Rule Language Cheat Sheet
iRODS Rule Language Cheat SheetiRODS Rule Language Cheat Sheet
iRODS Rule Language Cheat SheetSamuel Lampa
 
Understanding the "Chain Rule" for Derivatives by Deriving Your Own Version
Understanding the "Chain Rule" for Derivatives by Deriving Your Own VersionUnderstanding the "Chain Rule" for Derivatives by Deriving Your Own Version
Understanding the "Chain Rule" for Derivatives by Deriving Your Own VersionJames Smith
 
Introduction to Functional Programming with Scala
Introduction to Functional Programming with ScalaIntroduction to Functional Programming with Scala
Introduction to Functional Programming with ScalaDaniel Cukier
 
functions
 functions  functions
functions Gaditek
 

Similaire à Folding Cheat Sheet #4 - fourth in a series (20)

Array
ArrayArray
Array
 
Teeing Up Python - Code Golf
Teeing Up Python - Code GolfTeeing Up Python - Code Golf
Teeing Up Python - Code Golf
 
Lecture 01 reals number system
Lecture 01 reals number systemLecture 01 reals number system
Lecture 01 reals number system
 
Python 04-ifelse-return-input-strings.pptx
Python 04-ifelse-return-input-strings.pptxPython 04-ifelse-return-input-strings.pptx
Python 04-ifelse-return-input-strings.pptx
 
Frp2016 3
Frp2016 3Frp2016 3
Frp2016 3
 
Complex function
Complex functionComplex function
Complex function
 
Maths number system
Maths   number systemMaths   number system
Maths number system
 
Map, Reduce and Filter in Swift
Map, Reduce and Filter in SwiftMap, Reduce and Filter in Swift
Map, Reduce and Filter in Swift
 
23UCACC11 Python Programming (MTNC) (BCA)
23UCACC11 Python Programming (MTNC) (BCA)23UCACC11 Python Programming (MTNC) (BCA)
23UCACC11 Python Programming (MTNC) (BCA)
 
Lists.pptx
Lists.pptxLists.pptx
Lists.pptx
 
Scala. Introduction to FP. Monads
Scala. Introduction to FP. MonadsScala. Introduction to FP. Monads
Scala. Introduction to FP. Monads
 
Python Lecture 11
Python Lecture 11Python Lecture 11
Python Lecture 11
 
Monad Fact #4
Monad Fact #4Monad Fact #4
Monad Fact #4
 
Ch8b
Ch8bCh8b
Ch8b
 
Scala by Luc Duponcheel
Scala by Luc DuponcheelScala by Luc Duponcheel
Scala by Luc Duponcheel
 
7. basics
7. basics7. basics
7. basics
 
iRODS Rule Language Cheat Sheet
iRODS Rule Language Cheat SheetiRODS Rule Language Cheat Sheet
iRODS Rule Language Cheat Sheet
 
Understanding the "Chain Rule" for Derivatives by Deriving Your Own Version
Understanding the "Chain Rule" for Derivatives by Deriving Your Own VersionUnderstanding the "Chain Rule" for Derivatives by Deriving Your Own Version
Understanding the "Chain Rule" for Derivatives by Deriving Your Own Version
 
Introduction to Functional Programming with Scala
Introduction to Functional Programming with ScalaIntroduction to Functional Programming with Scala
Introduction to Functional Programming with Scala
 
functions
 functions  functions
functions
 

Plus de Philip Schwarz

Folding Cheat Sheet #3 - third in a series
Folding Cheat Sheet #3 - third in a seriesFolding Cheat Sheet #3 - third in a series
Folding Cheat Sheet #3 - third in a seriesPhilip Schwarz
 
Folding Cheat Sheet #2 - second in a series
Folding Cheat Sheet #2 - second in a seriesFolding Cheat Sheet #2 - second in a series
Folding Cheat Sheet #2 - second in a seriesPhilip Schwarz
 
Folding Cheat Sheet #1 - first in a series
Folding Cheat Sheet #1 - first in a seriesFolding Cheat Sheet #1 - first in a series
Folding Cheat Sheet #1 - first in a seriesPhilip Schwarz
 
Scala Left Fold Parallelisation - Three Approaches
Scala Left Fold Parallelisation- Three ApproachesScala Left Fold Parallelisation- Three Approaches
Scala Left Fold Parallelisation - Three ApproachesPhilip Schwarz
 
Tagless Final Encoding - Algebras and Interpreters and also Programs
Tagless Final Encoding - Algebras and Interpreters and also ProgramsTagless Final Encoding - Algebras and Interpreters and also Programs
Tagless Final Encoding - Algebras and Interpreters and also ProgramsPhilip Schwarz
 
Fusing Transformations of Strict Scala Collections with Views
Fusing Transformations of Strict Scala Collections with ViewsFusing Transformations of Strict Scala Collections with Views
Fusing Transformations of Strict Scala Collections with ViewsPhilip Schwarz
 
A sighting of traverse_ function in Practical FP in Scala
A sighting of traverse_ function in Practical FP in ScalaA sighting of traverse_ function in Practical FP in Scala
A sighting of traverse_ function in Practical FP in ScalaPhilip Schwarz
 
A sighting of traverseFilter and foldMap in Practical FP in Scala
A sighting of traverseFilter and foldMap in Practical FP in ScalaA sighting of traverseFilter and foldMap in Practical FP in Scala
A sighting of traverseFilter and foldMap in Practical FP in ScalaPhilip Schwarz
 
A sighting of sequence function in Practical FP in Scala
A sighting of sequence function in Practical FP in ScalaA sighting of sequence function in Practical FP in Scala
A sighting of sequence function in Practical FP in ScalaPhilip Schwarz
 
N-Queens Combinatorial Puzzle meets Cats
N-Queens Combinatorial Puzzle meets CatsN-Queens Combinatorial Puzzle meets Cats
N-Queens Combinatorial Puzzle meets CatsPhilip Schwarz
 
Kleisli composition, flatMap, join, map, unit - implementation and interrelat...
Kleisli composition, flatMap, join, map, unit - implementation and interrelat...Kleisli composition, flatMap, join, map, unit - implementation and interrelat...
Kleisli composition, flatMap, join, map, unit - implementation and interrelat...Philip Schwarz
 
The aggregate function - from sequential and parallel folds to parallel aggre...
The aggregate function - from sequential and parallel folds to parallel aggre...The aggregate function - from sequential and parallel folds to parallel aggre...
The aggregate function - from sequential and parallel folds to parallel aggre...Philip Schwarz
 
Nat, List and Option Monoids - from scratch - Combining and Folding - an example
Nat, List and Option Monoids -from scratch -Combining and Folding -an exampleNat, List and Option Monoids -from scratch -Combining and Folding -an example
Nat, List and Option Monoids - from scratch - Combining and Folding - an examplePhilip Schwarz
 
Nat, List and Option Monoids - from scratch - Combining and Folding - an example
Nat, List and Option Monoids -from scratch -Combining and Folding -an exampleNat, List and Option Monoids -from scratch -Combining and Folding -an example
Nat, List and Option Monoids - from scratch - Combining and Folding - an examplePhilip Schwarz
 
The Sieve of Eratosthenes - Part II - Genuine versus Unfaithful Sieve - Haske...
The Sieve of Eratosthenes - Part II - Genuine versus Unfaithful Sieve - Haske...The Sieve of Eratosthenes - Part II - Genuine versus Unfaithful Sieve - Haske...
The Sieve of Eratosthenes - Part II - Genuine versus Unfaithful Sieve - Haske...Philip Schwarz
 
Sum and Product Types - The Fruit Salad & Fruit Snack Example - From F# to Ha...
Sum and Product Types -The Fruit Salad & Fruit Snack Example - From F# to Ha...Sum and Product Types -The Fruit Salad & Fruit Snack Example - From F# to Ha...
Sum and Product Types - The Fruit Salad & Fruit Snack Example - From F# to Ha...Philip Schwarz
 
Algebraic Data Types for Data Oriented Programming - From Haskell and Scala t...
Algebraic Data Types forData Oriented Programming - From Haskell and Scala t...Algebraic Data Types forData Oriented Programming - From Haskell and Scala t...
Algebraic Data Types for Data Oriented Programming - From Haskell and Scala t...Philip Schwarz
 
Jordan Peterson - The pursuit of meaning and related ethical axioms
Jordan Peterson - The pursuit of meaning and related ethical axiomsJordan Peterson - The pursuit of meaning and related ethical axioms
Jordan Peterson - The pursuit of meaning and related ethical axiomsPhilip Schwarz
 
Defining filter using (a) recursion (b) folding (c) folding with S, B and I c...
Defining filter using (a) recursion (b) folding (c) folding with S, B and I c...Defining filter using (a) recursion (b) folding (c) folding with S, B and I c...
Defining filter using (a) recursion (b) folding (c) folding with S, B and I c...Philip Schwarz
 
Defining filter using (a) recursion (b) folding with S, B and I combinators (...
Defining filter using (a) recursion (b) folding with S, B and I combinators (...Defining filter using (a) recursion (b) folding with S, B and I combinators (...
Defining filter using (a) recursion (b) folding with S, B and I combinators (...Philip Schwarz
 

Plus de Philip Schwarz (20)

Folding Cheat Sheet #3 - third in a series
Folding Cheat Sheet #3 - third in a seriesFolding Cheat Sheet #3 - third in a series
Folding Cheat Sheet #3 - third in a series
 
Folding Cheat Sheet #2 - second in a series
Folding Cheat Sheet #2 - second in a seriesFolding Cheat Sheet #2 - second in a series
Folding Cheat Sheet #2 - second in a series
 
Folding Cheat Sheet #1 - first in a series
Folding Cheat Sheet #1 - first in a seriesFolding Cheat Sheet #1 - first in a series
Folding Cheat Sheet #1 - first in a series
 
Scala Left Fold Parallelisation - Three Approaches
Scala Left Fold Parallelisation- Three ApproachesScala Left Fold Parallelisation- Three Approaches
Scala Left Fold Parallelisation - Three Approaches
 
Tagless Final Encoding - Algebras and Interpreters and also Programs
Tagless Final Encoding - Algebras and Interpreters and also ProgramsTagless Final Encoding - Algebras and Interpreters and also Programs
Tagless Final Encoding - Algebras and Interpreters and also Programs
 
Fusing Transformations of Strict Scala Collections with Views
Fusing Transformations of Strict Scala Collections with ViewsFusing Transformations of Strict Scala Collections with Views
Fusing Transformations of Strict Scala Collections with Views
 
A sighting of traverse_ function in Practical FP in Scala
A sighting of traverse_ function in Practical FP in ScalaA sighting of traverse_ function in Practical FP in Scala
A sighting of traverse_ function in Practical FP in Scala
 
A sighting of traverseFilter and foldMap in Practical FP in Scala
A sighting of traverseFilter and foldMap in Practical FP in ScalaA sighting of traverseFilter and foldMap in Practical FP in Scala
A sighting of traverseFilter and foldMap in Practical FP in Scala
 
A sighting of sequence function in Practical FP in Scala
A sighting of sequence function in Practical FP in ScalaA sighting of sequence function in Practical FP in Scala
A sighting of sequence function in Practical FP in Scala
 
N-Queens Combinatorial Puzzle meets Cats
N-Queens Combinatorial Puzzle meets CatsN-Queens Combinatorial Puzzle meets Cats
N-Queens Combinatorial Puzzle meets Cats
 
Kleisli composition, flatMap, join, map, unit - implementation and interrelat...
Kleisli composition, flatMap, join, map, unit - implementation and interrelat...Kleisli composition, flatMap, join, map, unit - implementation and interrelat...
Kleisli composition, flatMap, join, map, unit - implementation and interrelat...
 
The aggregate function - from sequential and parallel folds to parallel aggre...
The aggregate function - from sequential and parallel folds to parallel aggre...The aggregate function - from sequential and parallel folds to parallel aggre...
The aggregate function - from sequential and parallel folds to parallel aggre...
 
Nat, List and Option Monoids - from scratch - Combining and Folding - an example
Nat, List and Option Monoids -from scratch -Combining and Folding -an exampleNat, List and Option Monoids -from scratch -Combining and Folding -an example
Nat, List and Option Monoids - from scratch - Combining and Folding - an example
 
Nat, List and Option Monoids - from scratch - Combining and Folding - an example
Nat, List and Option Monoids -from scratch -Combining and Folding -an exampleNat, List and Option Monoids -from scratch -Combining and Folding -an example
Nat, List and Option Monoids - from scratch - Combining and Folding - an example
 
The Sieve of Eratosthenes - Part II - Genuine versus Unfaithful Sieve - Haske...
The Sieve of Eratosthenes - Part II - Genuine versus Unfaithful Sieve - Haske...The Sieve of Eratosthenes - Part II - Genuine versus Unfaithful Sieve - Haske...
The Sieve of Eratosthenes - Part II - Genuine versus Unfaithful Sieve - Haske...
 
Sum and Product Types - The Fruit Salad & Fruit Snack Example - From F# to Ha...
Sum and Product Types -The Fruit Salad & Fruit Snack Example - From F# to Ha...Sum and Product Types -The Fruit Salad & Fruit Snack Example - From F# to Ha...
Sum and Product Types - The Fruit Salad & Fruit Snack Example - From F# to Ha...
 
Algebraic Data Types for Data Oriented Programming - From Haskell and Scala t...
Algebraic Data Types forData Oriented Programming - From Haskell and Scala t...Algebraic Data Types forData Oriented Programming - From Haskell and Scala t...
Algebraic Data Types for Data Oriented Programming - From Haskell and Scala t...
 
Jordan Peterson - The pursuit of meaning and related ethical axioms
Jordan Peterson - The pursuit of meaning and related ethical axiomsJordan Peterson - The pursuit of meaning and related ethical axioms
Jordan Peterson - The pursuit of meaning and related ethical axioms
 
Defining filter using (a) recursion (b) folding (c) folding with S, B and I c...
Defining filter using (a) recursion (b) folding (c) folding with S, B and I c...Defining filter using (a) recursion (b) folding (c) folding with S, B and I c...
Defining filter using (a) recursion (b) folding (c) folding with S, B and I c...
 
Defining filter using (a) recursion (b) folding with S, B and I combinators (...
Defining filter using (a) recursion (b) folding with S, B and I combinators (...Defining filter using (a) recursion (b) folding with S, B and I combinators (...
Defining filter using (a) recursion (b) folding with S, B and I combinators (...
 

Dernier

Salesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantSalesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantAxelRicardoTrocheRiq
 
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfLearn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfkalichargn70th171
 
Building Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop SlideBuilding Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop SlideChristina Lin
 
Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)OPEN KNOWLEDGE GmbH
 
Hand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxHand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxbodapatigopi8531
 
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...Christina Lin
 
Introduction to Decentralized Applications (dApps)
Introduction to Decentralized Applications (dApps)Introduction to Decentralized Applications (dApps)
Introduction to Decentralized Applications (dApps)Intelisync
 
Optimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVOptimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVshikhaohhpro
 
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...ICS
 
The Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdf
The Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdfThe Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdf
The Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdfkalichargn70th171
 
What is Binary Language? Computer Number Systems
What is Binary Language?  Computer Number SystemsWhat is Binary Language?  Computer Number Systems
What is Binary Language? Computer Number SystemsJheuzeDellosa
 
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...harshavardhanraghave
 
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...MyIntelliSource, Inc.
 
Unit 1.1 Excite Part 1, class 9, cbse...
Unit 1.1 Excite Part 1, class 9, cbse...Unit 1.1 Excite Part 1, class 9, cbse...
Unit 1.1 Excite Part 1, class 9, cbse...aditisharan08
 
Project Based Learning (A.I).pptx detail explanation
Project Based Learning (A.I).pptx detail explanationProject Based Learning (A.I).pptx detail explanation
Project Based Learning (A.I).pptx detail explanationkaushalgiri8080
 
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed DataAlluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed DataAlluxio, Inc.
 
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...gurkirankumar98700
 
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer DataAdobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer DataBradBedford3
 
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...soniya singh
 

Dernier (20)

Salesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantSalesforce Certified Field Service Consultant
Salesforce Certified Field Service Consultant
 
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfLearn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
 
Building Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop SlideBuilding Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
 
Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)
 
Hand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxHand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptx
 
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
 
Introduction to Decentralized Applications (dApps)
Introduction to Decentralized Applications (dApps)Introduction to Decentralized Applications (dApps)
Introduction to Decentralized Applications (dApps)
 
Exploring iOS App Development: Simplifying the Process
Exploring iOS App Development: Simplifying the ProcessExploring iOS App Development: Simplifying the Process
Exploring iOS App Development: Simplifying the Process
 
Optimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVOptimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTV
 
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
 
The Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdf
The Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdfThe Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdf
The Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdf
 
What is Binary Language? Computer Number Systems
What is Binary Language?  Computer Number SystemsWhat is Binary Language?  Computer Number Systems
What is Binary Language? Computer Number Systems
 
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
 
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
 
Unit 1.1 Excite Part 1, class 9, cbse...
Unit 1.1 Excite Part 1, class 9, cbse...Unit 1.1 Excite Part 1, class 9, cbse...
Unit 1.1 Excite Part 1, class 9, cbse...
 
Project Based Learning (A.I).pptx detail explanation
Project Based Learning (A.I).pptx detail explanationProject Based Learning (A.I).pptx detail explanation
Project Based Learning (A.I).pptx detail explanation
 
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed DataAlluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
 
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
 
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer DataAdobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
 
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
 

Folding Cheat Sheet #4 - fourth in a series

  • 1. CHEAT-SHEET Folding #4 ∶ / 𝒂𝟎 ∶ / 𝒂𝟏 ∶ / 𝒂𝟐 ∶ / 𝒂𝟑 𝒇 / 𝒂𝟎 𝒇 / 𝒂𝟏 𝒇 / 𝒂𝟐 𝒇 / 𝒂𝟑 𝒆 @philip_schwarz slides by https://fpilluminated.com/
  • 2. We want to write function 𝒅𝒆𝒄𝒊𝒎𝒂𝒍, which given the digits of an integer number [𝑑0, 𝑑1, … , 𝑑𝑛] computes the integer value of the number - &'( ) 𝑑𝑘 ∗ 10)*& Thanks to the universal property of fold, if we are able to define 𝒅𝒆𝒄𝒊𝒎𝒂𝒍 so that its equations match those on the left hand side of the following equivalence, then we are also able to implement 𝒅𝒆𝒄𝒊𝒎𝒂𝒍 using a right fold i.e. given 𝑓𝑜𝑙𝑑𝑟 𝑓𝑜𝑙𝑑𝑟 :: 𝛼 → 𝛽 → 𝛽 → 𝛽 → 𝛼 → 𝛽 𝑓𝑜𝑙𝑑𝑟 𝑓 𝑣 = 𝑣 𝑓𝑜𝑙𝑑𝑟 𝑓 𝑣 𝑥 ∶ 𝑥𝑠 = 𝑓 𝑥 𝑓𝑜𝑙𝑑𝑟 𝑓 𝑣 𝑥𝑠 we can reimplement 𝒅𝒆𝒄𝒊𝒎𝒂𝒍 like this: 𝒅𝒆𝒄𝒊𝒎𝒂𝒍 = 𝑓𝑜𝑙𝑑𝑟 𝑓 𝑣 The universal property of 𝒇𝒐𝒍𝒅 𝒈 = 𝒗 ⟺ 𝒈 = 𝒇𝒐𝒍𝒅 𝒇 𝒗 𝒈 :: 𝛼 → 𝛽 𝒈 𝑥 ∶ 𝑥𝑠 = 𝒇 𝑥 𝒈 𝑥𝑠 𝒗 :: 𝛽 𝒇 :: 𝛼 → 𝛽 → 𝛽 scala> decimal(List(1,2,3,4)) val res0: Int = 1234 haskell> decimal [1,2,3,4] 1234 𝑑0 ∗ 103 + 𝑑1 ∗ 102 + 𝑑2 ∗ 101 + 𝑑3 ∗ 100 = 1 ∗ 1000 + 2 ∗ 100 + 3 ∗ 10 + 4 ∗ 1 = 1234
  • 3. Notice that 𝒇 has two parameters: the head of the list, and the result of recursively calling 𝒈 with the tail of the list 𝒈 𝑥 ∶ 𝑥𝑠 = 𝒇 𝑥 𝒈 𝑥𝑠 In order to define our 𝒅𝒆𝒄𝒊𝒎𝒂𝒍 function however, the two parameters of 𝒇 are not sufficient. When 𝒅𝒆𝒄𝒊𝒎𝒂𝒍 is passed [𝑑𝑘, … , 𝑑𝑛], 𝒇 is passed digit 𝑑𝑘, so 𝒇 needs 𝑛 and 𝑘 in order to compute 10)*& , but 𝑛 − 𝑘 is the number of elements in [𝑑𝑘, … , 𝑑𝑛] minus one, so by nesting the definition of 𝒇 inside that of 𝒅𝒆𝒄𝒊𝒎𝒂𝒍, we can avoid explicitly adding a third parameter to 𝒇 : We nested 𝒇 inside 𝒅𝒆𝒄𝒊𝒎𝒂𝒍, so that the equations of 𝒅𝒆𝒄𝒊𝒎𝒂𝒍 match (almost) those of 𝒈. They don’t match perfectly, in that the 𝒇 nested inside 𝒅𝒆𝒄𝒊𝒎𝒂𝒍 depends on 𝒅𝒆𝒄𝒊𝒎𝒂𝒍’s list parameter, whereas the 𝒇 nested inside 𝒈 does not depend on 𝒈’s list parameter. Are we still able to redefine 𝒅𝒆𝒄𝒊𝒎𝒂𝒍 using 𝑓𝑜𝑙𝑑𝑟? If the match had been perfect, we would be able to define 𝒅𝒆𝒄𝒊𝒎𝒂𝒍 = 𝑓𝑜𝑙𝑑𝑟 𝑓 0 (with 𝒗 = 0), but because 𝒇 needs to know the value of 𝑛 − 𝑘, we can’t just pass 𝒇 to 𝑓𝑜𝑙𝑑𝑟, and use 0 as the initial accumulator. Instead, we need to use (0, 0) as the accumulator (the second 0 being the initial value of 𝑛 − 𝑘, when 𝑘 = 𝑛), and pass to 𝑓𝑜𝑙𝑑𝑟 a helper function ℎ that manages 𝑛 − 𝑘 and that wraps 𝒇, so that the latter has access to 𝑛 − 𝑘. def h(d: Int, acc: (Int,Int)): (Int,Int) = acc match { case (ds, e) => def f(d: Int, ds: Int): Int = d * Math.pow(10, e).toInt + ds (f(d, ds), e + 1) } def decimal(ds: List[Int]): Int = ds.foldRight((0,0))(h).head h :: Int -> (Int,Int) -> (Int,Int) h d (ds, e) = (f d ds, e + 1) where f :: Int -> Int -> Int f d ds = d * (10 ^ e) + ds decimal :: [Int] -> Int decimal ds = fst (foldr h (0,0) ds) def decimal(digits: List[Int]): Int = val e = digits.length-1 def f(d: Int, ds: Int): Int = d * Math.pow(10, e).toInt + ds digits match case Nil => 0 case d +: ds => f(d, decimal(ds)) decimal :: [Int] -> Int decimal [] = 0 decimal (d:ds) = f d (decimal ds) where e = length ds f :: Int -> Int -> Int f d ds = d * (10 ^ e) + ds The unnecessary complexity of the 𝒅𝒆𝒄𝒊𝒎𝒂𝒍 functions on this slide is purely due to them being defined in terms of 𝒇 . See next slide for simpler refactored versions in which 𝒇 is inlined.
  • 4. def f(d: Int, acc: (Int,Int)): (Int,Int) = acc match case (ds, e) => (d * Math.pow(10, e).toInt + ds, e + 1) def decimal(ds: List[Int]): Int = ds.foldRight((0,0))(f).head f :: Int -> (Int,Int) -> (Int,Int) f d (ds, e) = (d * (10 ^ e) + ds, e + 1) decimal :: [Int] -> Int decimal ds = fst (foldr f (0,0) ds) def decimal(digits: List[Int]): Int = digits match case Nil => 0 case d +: ds => d * Math.pow(10, ds.length).toInt + decimal(ds) decimal :: [Int] -> Int decimal [] = 0 decimal (d:ds) = d*(10^(length ds))+(decimal ds) Same 𝒅𝒆𝒄𝒊𝒎𝒂𝒍 functions as on the previous slide, but refactored as follows: 1. inlined 𝒇 in all four functions 2. inlined e in the first two functions 3. renamed 𝒉 to 𝒇 in the last two functions
  • 5. Not every function on lists can be defined as an instance of 𝑓𝑜𝑙𝑑𝑟. For example, zip cannot be so defined. Even for those that can, an alternative definition may be more efficient. To illustrate, suppose we want a function decimal that takes a list of digits and returns the corresponding decimal number; thus 𝑑𝑒𝑐𝑖𝑚𝑎𝑙 [𝑥0, 𝑥1, … , 𝑥n] = ∑!"# $ 𝑥𝑘10($&!) It is assumed that the most significant digit comes first in the list. One way to compute decimal efficiently is by a process of multiplying each digit by ten and adding in the following digit. For example 𝑑𝑒𝑐𝑖𝑚𝑎𝑙 𝑥0, 𝑥1, 𝑥2 = 10 × 10 × 10 × 0 + 𝑥0 + 𝑥1 + 𝑥2 This decomposition of a sum of powers is known as Horner’s rule. Suppose we define ⊕ by 𝑛 ⊕ 𝑥 = 10 × 𝑛 + 𝑥. Then we can rephrase the above equation as 𝑑𝑒𝑐𝑖𝑚𝑎𝑙 𝑥0, 𝑥1, 𝑥2 = (0 ⊕ 𝑥0) ⊕ 𝑥1 ⊕ 𝑥2 This is almost like an instance of 𝑓𝑜𝑙𝑑𝑟, except that the grouping is the other way round, and the starting value appears on the left, not on the right. In fact the computation is dual: instead of processing from right to left, the computation processes from left to right. This example motivates the introduction of a second fold operator called 𝑓𝑜𝑙𝑑𝑙 (pronounced ‘fold left’). Informally: 𝑓𝑜𝑙𝑑𝑙 ⊕ 𝑒 𝑥0, 𝑥1, … , 𝑥𝑛 − 1 = … ((𝑒 ⊕ 𝑥0) ⊕ 𝑥1) … ⊕ 𝑥𝑛 − 1 The parentheses group from the left, which is the reason for the name. The full definition of 𝑓𝑜𝑙𝑑𝑙 is 𝑓𝑜𝑙𝑑𝑙 ∷ 𝛽 → 𝛼 → 𝛽 → 𝛽 → 𝛼 → 𝛽 𝑓𝑜𝑙𝑑𝑙 𝑓 𝑒 = 𝑒 𝑓𝑜𝑙𝑑𝑙 𝑓 𝑒 𝑥: 𝑥𝑠 = 𝑓𝑜𝑙𝑑𝑙 𝑓 𝑓 𝑒 𝑥 𝑥𝑠 Richard Bird The definition of 𝒅𝒆𝒄𝒊𝒎𝒂𝒍 using a right fold is inefficient because it computes ∑!"# $ 𝑑𝑘 ∗ 10$&! by computing 10$&! for each 𝑘.
  • 6. If we look back at our initial recursive definition of 𝒅𝒆𝒄𝒊𝒎𝒂𝒍, we see that it splits its list parameter into a head and a tail. If we get 𝒅𝒆𝒄𝒊𝒎𝒂𝒍 to split the list into init and last, we can make it more efficient by using Horner’s rule: We can then improve on that by going back to splitting the list into a head and a tail, and making 𝒅𝒆𝒄𝒊𝒎𝒂𝒍 tail recursive: And finally, we can improve on that by defining 𝒅𝒆𝒄𝒊𝒎𝒂𝒍 using a left fold: (⊕) :: Int -> Int -> Int n ⊕ d = 10 * n + d decimal :: [Int] -> Int decimal [] = 0 decimal (d:ds) = d*(10^(length ds)) + (decimal ds) def decimal(digits: List[Int]): Int = digits match case Nil => 0 case d +: ds => d * Math.pow(10, ds.length).toInt + decimal(ds) extension (n: Int) def ⊕(d Int): Int = 10 * n + d decimal :: [Int] -> Int -> Int decimal [] acc = acc decimal (d:ds) acc = decimal ds (acc ⊕d) def decimal(ds: List[Int], acc: Int=0): Int = digits match case Nil => acc case d +: ds => decimal(ds, acc ⊕ d) decimal :: [Int] -> Int decimal = foldl (⊕) 0 decimal :: [Int] -> Int decimal [] = 0 decimal ds = (decimal (init ds)) ⊕ (last ds) def decimal(digits: List[Int]): Int = digits match case Nil => 0 case ds :+ d => decimal(ds) ⊕ d def decimal(ds: List[Int]): Int = ds.foldLeft(0)(_⊕_)
  • 7. Recap In the case of the 𝒅𝒆𝒄𝒊𝒎𝒂𝒍 function, defining it using a left fold is simple and mathematically more efficient whereas defining it using a right fold is more complex and mathematically less efficient def decimal(ds: List[Int]): Int = ds.foldRight((0,0))(f).head def f(d: Int, acc: (Int,Int)): (Int,Int) = acc match case (ds, e) => (d * Math.pow(10, e).toInt + ds, e + 1) decimal :: [Int] -> Int decimal ds = fst (foldr f (0,0) ds) f :: Int -> (Int,Int) -> (Int,Int) f d (ds, e) = (d * (10 ^ e) + ds, e + 1) decimal :: [Int] -> Int decimal = foldl (⊕) 0 (⊕) :: Int -> Int -> Int n ⊕ d = 10 * n + d def decimal(ds: List[Int]): Int = ds.foldLeft(0)(_⊕_) extension (n: Int) def ⊕(d Int): Int = 10 * n + d 𝒅𝒆𝒄𝒊𝒎𝒂𝒍 1,2,3,4 = 𝑑0 ∗ 103 + (𝑑1 ∗ 102 + (𝑑2 ∗ 101 + (𝑑3 ∗ 100 + 0))) = 1 ∗ 1000 + (2 ∗ 100 + (3 ∗ 10 + (4 ∗ 1 + 0))) = 1234 𝒅𝒆𝒄𝒊𝒎𝒂𝒍 1,2,3,4 = 10 ∗ 10 ∗ 10 ∗ 10 ∗ 0 + 𝑑0 + 𝑑1 + 𝑑2 + 𝑑3 = 10 ∗ (10 ∗ 10 ∗ 10 ∗ 0 + 1 + 2 + 3) + 4 = 1234