SlideShare a Scribd company logo
1 of 14
Download to read offline
Based on definitions from
Left and Right Folds
Comparison of a mathematical definition
and a programmatic one
Polyglot FP for Fun and Profit - Haskell and Scala
@philip_schwarz
slides by https://www.slideshare.net/pjschwarz
Sergei Winitzki
sergei-winitzki-11a6431
Richard Bird
http://www.cs.ox.ac.uk/people/richard.bird/
𝑓𝑜𝑙𝑑𝑙 ∷ đ›œ → đ›Œ → đ›œ → đ›œ → đ›Œ → đ›œ
𝑓𝑜𝑙𝑑𝑙 𝑓 𝑒 = 𝑒
𝑓𝑜𝑙𝑑𝑙 𝑓 𝑒 đ‘„ ∶ đ‘„đ‘  = 𝑓𝑜𝑙𝑑𝑙 𝑓 𝑓 𝑒 đ‘„ đ‘„đ‘ 
𝑓𝑜𝑙𝑑𝑟 ∷ đ›Œ → đ›œ → đ›œ → đ›œ → đ›Œ → đ›œ
𝑓𝑜𝑙𝑑𝑟 𝑓 𝑒 = 𝑒
𝑓𝑜𝑙𝑑𝑟 𝑓 𝑒 đ‘„ ∶ đ‘„đ‘  = 𝑓 đ‘„ 𝑓𝑜𝑙𝑑𝑟 𝑓 𝑒 đ‘„đ‘ 
If I have to write down the definitions of a left
fold and a right fold for lists, here is what I write
While both definitions are recursive, the left fold is tail recursive, whereas the right fold isn’t.
Although I am very familiar with the above definitions, and view them as doing a good job of
explaining the two folds, I am always interested in alternative ways of explaining things, and so
I have been looking at Sergei Winitzki’s mathematical definitions of left and right folds, in his
upcoming book: The Science of Functional Programming (SOFP).
Sergei’s definitions of the folds are in the top two rows of the following table
Sergei Winitzki
Richard Bird
@philip_schwarz
test1 = TestCase (assertEqual "foldl(+) 0 []" 0 (foldl (+) 0 []))
test2 = TestCase (assertEqual "foldl(+) 0 [1,2,3,4]" 10 (foldl (+) 0 [1,2,3,4]))
test3 = TestCase (assertEqual "foldr (+) 0 []" 0 (foldr (+) 0 []))
test4 = TestCase (assertEqual "foldr (+) 0 [1,2,3,4]" 10 (foldr (+) 0 [1,2,3,4]))
Left folds and right folds do not necessarily produce the same
results. According to the first duality theorem of folding, one case
in which the results are the same, is when we fold using the unit
and associative operation of a monoid.
First duality theorem. Suppose ⊕ is associative with unit 𝑒. Then
𝑓𝑜𝑙𝑑𝑟 ⊕ 𝑒 đ‘„đ‘  = 𝑓𝑜𝑙𝑑𝑙 ⊕ 𝑒 đ‘„đ‘ 
For all finite lists đ‘„đ‘ .
test5 = TestCase (assertEqual "foldl(-) 0 []" 0 (foldl (+) 0 []))
test6 = TestCase (assertEqual "foldl(-) 0 [1,2,3,4]" (- 10) (foldl (-) 0 [1,2,3,4]))
test7 = TestCase (assertEqual "foldr (-) 0 []" 0 (foldr (-) 0 []))
test8 = TestCase (assertEqual "foldr (-) 0 [1,2,3,4]" (- 2) (foldr (-) 0 [1,2,3,4]))
Folding integers left and right using the (Int,+,0) monoid, for example, produces the same results.
But folding integers left and right using subtraction and zero, does not produce the same results, and in
fact (Int,-,0) is not a monoid, because subtraction is not associative.
𝑓 = 𝑏; 𝑓 đ‘„ â§ș 𝑠 = 𝑔(đ‘„, 𝑓(𝑠))
𝑓 = 𝑏; 𝑓 𝑠 â§ș [đ‘„] = 𝑔(𝑓 𝑠 , đ‘„)
To avoid any confusion (the definitions use the same function name 𝑓), and to
align with the definitions on the right, let’s modify Sergei’s definitions by doing
some simple renaming.
Here are Sergei’s mathematical definitions again, on the right (the â§ș operator
is list concatenation). Notice how neither definition is tail recursive. That is
deliberate.
As Sergei explained to me: “I'd like to avoid putting tail recursion into a
mathematical formula, because tail recursion is just a detail of how we
implement this function” and “The fact that foldLeft is tail recursive for List is
an implementation detail that is specific to the List type. It will be different for
other sequence types. I do not want to put the implementation details into the
formulas.”
𝑓 → 𝑓𝑜𝑙𝑑𝑙 𝑔 → 𝑓 𝑏 → 𝑒
𝑓𝑜𝑙𝑑𝑟 = 𝑒; 𝑓𝑜𝑙𝑑𝑟 đ‘„ â§ș 𝑠 = 𝑓(đ‘„, 𝑓𝑜𝑙𝑑𝑟(𝑠))
𝑓𝑜𝑙𝑑𝑙 = 𝑒; 𝑓𝑜𝑙𝑑𝑙 𝑠 â§ș [đ‘„] = 𝑓(𝑓𝑜𝑙𝑑𝑙 𝑠 , đ‘„)
𝑓 → 𝑓𝑜𝑙𝑑𝑟 𝑔 → 𝑓 𝑏 → 𝑒
𝑓𝑜𝑙𝑑𝑙 ∷ đ›œ → đ›Œ → đ›œ → đ›œ → đ›Œ → đ›œ
𝑓𝑜𝑙𝑑𝑙 𝑓 𝑒 = 𝑒
𝑓𝑜𝑙𝑑𝑙 𝑓 𝑒 đ‘„ ∶ đ‘„đ‘  = 𝑓𝑜𝑙𝑑𝑙 𝑓 𝑓 𝑒 đ‘„ đ‘„đ‘ 
𝑓𝑜𝑙𝑑𝑟 ∷ đ›Œ → đ›œ → đ›œ → đ›œ → đ›Œ → đ›œ
𝑓𝑜𝑙𝑑𝑟 𝑓 𝑒 = 𝑒
𝑓𝑜𝑙𝑑𝑟 𝑓 𝑒 đ‘„ ∶ đ‘„đ‘  = 𝑓 đ‘„ 𝑓𝑜𝑙𝑑𝑟 𝑓 𝑒 đ‘„đ‘ 
𝑓 = 𝑏; 𝑓 đ‘„ â§ș 𝑠 = 𝑔(đ‘„, 𝑓(𝑠))
𝑓 = 𝑏; 𝑓 𝑠 â§ș [đ‘„] = 𝑔(𝑓 𝑠 , đ‘„)
𝑓𝑜𝑙𝑑𝑟 𝑓 𝑒 [ ] = 𝑒
𝑓𝑜𝑙𝑑𝑟 𝑓 𝑒 đ‘„ â§ș 𝑠 = 𝑓 đ‘„ (𝑓𝑜𝑙𝑑𝑟 𝑓 𝑒 𝑠)
𝑓𝑜𝑙𝑑𝑙 𝑓 𝑒 = 𝑒
𝑓𝑜𝑙𝑑𝑙 𝑓 𝑒 𝑠 â§ș [đ‘„] = 𝑓 𝑓𝑜𝑙𝑑𝑙 𝑓 𝑒 𝑠 đ‘„
𝑓𝑜𝑙𝑑𝑙 :: (𝑏 → 𝑎 → 𝑏) → 𝑏 →[𝑎] → 𝑏
𝑓𝑜𝑙𝑑𝑙 𝑓 𝑒 = 𝑒
𝑓𝑜𝑙𝑑𝑙 𝑓 𝑒 𝑎𝑠 = 𝑓 𝑓𝑜𝑙𝑑𝑙 𝑓 𝑒 (𝑖𝑛𝑖𝑡 𝑎𝑠) (𝑙𝑎𝑠𝑡 𝑎𝑠)
𝑓𝑜𝑙𝑑𝑟 :: (𝑎 → 𝑏 → 𝑏) → 𝑏 →[𝑎] → 𝑏
𝑓𝑜𝑙𝑑𝑟 𝑓 𝑒 = 𝑒
𝑓𝑜𝑙𝑑𝑟 𝑓 𝑒 𝑎𝑠 = 𝑓 ℎ𝑒𝑎𝑑 𝑎𝑠 𝑓𝑜𝑙𝑑𝑟 𝑓 𝑒 (𝑡𝑎𝑖𝑙 𝑎𝑠)
𝑓𝑜𝑙𝑑𝑙 :: (𝑏 → 𝑎 → 𝑏) → 𝑏 →[𝑎] → 𝑏
𝑓𝑜𝑙𝑑𝑙 𝑓 𝑒 = 𝑒
𝑓𝑜𝑙𝑑𝑙 𝑓 𝑒 𝑎𝑠 = 𝑓 𝑏 𝑎
đ‘€â„Žđ‘’đ‘Ÿđ‘’ 𝑎 = 𝑙𝑎𝑠𝑡 𝑎𝑠
𝑏 = 𝑓𝑜𝑙𝑑𝑙 𝑓 𝑒 (𝑖𝑛𝑖𝑡 𝑎𝑠)
𝑓𝑜𝑙𝑑𝑟 :: (𝑎 → 𝑏 → 𝑏) → 𝑏 →[𝑎] → 𝑏
𝑓𝑜𝑙𝑑𝑟 𝑓 𝑒 = 𝑒
𝑓𝑜𝑙𝑑𝑟 𝑓 𝑒 𝑎𝑠 = 𝑓 𝑎 𝑏
đ‘€â„Žđ‘’đ‘Ÿđ‘’ 𝑎 = ℎ𝑒𝑎𝑑 𝑎𝑠
𝑏 = 𝑓𝑜𝑙𝑑𝑟 𝑓 𝑒 (𝑡𝑎𝑖𝑙 𝑎𝑠)
𝑓𝑜𝑙𝑑𝑟 = 𝑒; 𝑓𝑜𝑙𝑑𝑟 đ‘„ â§ș 𝑠 = 𝑓(đ‘„, 𝑓𝑜𝑙𝑑𝑟(𝑠))
𝑓𝑜𝑙𝑑𝑙 = 𝑒; 𝑓𝑜𝑙𝑑𝑙 𝑠 â§ș [đ‘„] = 𝑓(𝑓𝑜𝑙𝑑𝑙 𝑠 , đ‘„)
To help us understand the above two definitions, let’s first express them in Haskell,
pretending that we are able to use 𝑠 â§ș [đ‘„] and đ‘„ â§ș 𝑠 in a pattern match.
Now let’s replace 𝑠 â§ș [đ‘„] and đ‘„ â§ș 𝑠 with as, and get the functions to extract
the 𝑠 and the đ‘„ using the ℎ𝑒𝑎𝑑, 𝑡𝑎𝑖𝑙, 𝑙𝑎𝑠𝑡 and 𝑖𝑛𝑖𝑡. Let’s also add type signatures
And now let’s make it more obvious that what each fold is doing is taking an 𝑎 from the list,
folding the rest of the list into a 𝑏, and then returning the result of calling 𝑓 with 𝑎 and 𝑏.
𝑓𝑜𝑙𝑑𝑙 :: (𝑏 → 𝑎 → 𝑏) → 𝑏 →[𝑎] → 𝑏
𝑓𝑜𝑙𝑑𝑙 𝑓 𝑒 = 𝑒
𝑓𝑜𝑙𝑑𝑙 𝑓 𝑒 𝑎𝑠 = 𝑓 𝑏 𝑎
đ‘€â„Žđ‘’đ‘Ÿđ‘’ 𝑎 = 𝑙𝑎𝑠𝑡 𝑎𝑠
𝑏 = 𝑓𝑜𝑙𝑑𝑙 𝑓 𝑒 (𝑖𝑛𝑖𝑡 𝑎𝑠)
𝑓𝑜𝑙𝑑𝑟 :: (𝑎 → 𝑏 → 𝑏) → 𝑏 →[𝑎] → 𝑏
𝑓𝑜𝑙𝑑𝑟 𝑓 𝑒 = 𝑒
𝑓𝑜𝑙𝑑𝑟 𝑓 𝑒 𝑎𝑠 = 𝑓 𝑎 𝑏
đ‘€â„Žđ‘’đ‘Ÿđ‘’ 𝑎 = ℎ𝑒𝑎𝑑 𝑎𝑠
𝑏 = 𝑓𝑜𝑙𝑑𝑟 𝑓 𝑒 (𝑡𝑎𝑖𝑙 𝑎𝑠)
Since the above two functions are very similar, let’s extract their common logic into a fold function. Let’s call the function
that is used to extract an element from the list 𝑡𝑎𝑘𝑒, and the function that is used to extract the rest of the list 𝑟𝑒𝑠𝑡.
𝑓𝑜𝑙𝑑 ::	(𝑏 → 𝑎 → 𝑏)	→ ([𝑎]	→ 𝑎)	→ ([𝑎]	→ [𝑎])	→ 𝑏 → [𝑎]	→ 𝑏
𝑓𝑜𝑙𝑑 𝑓 𝑡𝑎𝑘𝑒 𝑟𝑒𝑠𝑡 𝑒 = 𝑒
𝑓𝑜𝑙𝑑 𝑓 𝑡𝑎𝑘𝑒 𝑟𝑒𝑠𝑡 𝑒 𝑎𝑠 = 𝑓 𝑏 𝑎
đ‘€â„Žđ‘’đ‘Ÿđ‘’ 𝑎 = 𝑡𝑎𝑘𝑒 𝑎𝑠
𝑏 = 𝑓𝑜𝑙𝑑 𝑓 𝑡𝑎𝑘𝑒 𝑟𝑒𝑠𝑡 𝑒 (𝑟𝑒𝑠𝑡 𝑎𝑠)
We can now define left and right
folds in terms of 𝑓𝑜𝑙𝑑.
𝑓𝑜𝑙𝑑𝑙 :: (𝑏 → 𝑎 → 𝑏) → 𝑏 →[𝑎] → 𝑏
𝑓𝑜𝑙𝑑𝑙 𝑓 = 𝑓𝑜𝑙𝑑 𝑓 𝑙𝑎𝑠𝑡 𝑖𝑛𝑖𝑡
𝑓𝑜𝑙𝑑𝑟 :: (𝑎 → 𝑏 → 𝑏) → 𝑏 →[𝑎] → 𝑏
𝑓𝑜𝑙𝑑𝑟 𝑓 = 𝑓𝑜𝑙𝑑 𝑓𝑙𝑖𝑝 𝑓 ℎ𝑒𝑎𝑑 𝑡𝑎𝑖𝑙
𝑓𝑙𝑖𝑝 ::	(𝑎 → 𝑏 → 𝑐)	→ 𝑏 → 𝑎 → 𝑐
𝑓𝑙𝑖𝑝 𝑓 đ‘„ 𝑩 =	𝑓 𝑩 đ‘„
The slightly perplexing thing is that while a left fold applies 𝑓 to list elements starting with the ℎ𝑒𝑎𝑑 of the list and
proceeding from left to right, the above 𝑓𝑜𝑙𝑑𝑙 function achieves that by navigating through list elements from right to left.
Third duality theorem. For all finite lists đ‘„đ‘ ,
𝑓𝑜𝑙𝑑𝑟 𝑓 𝑒 đ‘„đ‘  = 𝑓𝑜𝑙𝑑𝑙 𝑓𝑙𝑖𝑝 𝑓 𝑒 (𝑟𝑒𝑣𝑒𝑟𝑠𝑒 đ‘„đ‘ )
𝒘𝒉𝒆𝒓𝒆 𝑓𝑙𝑖𝑝 𝑓 đ‘„ 𝑩 = 𝑓 𝑩 đ‘„
The fact that we can define 𝑓𝑜𝑙𝑑𝑙 and 𝑓𝑜𝑙𝑑𝑟 in terms of 𝑓𝑜𝑙𝑑, as we
do above, seems related to the third duality theorem of folding.
Instead of our 𝑓𝑜𝑙𝑑𝑙 function being passed the reverse of the list
passed to 𝑓𝑜𝑙𝑑𝑟, it processes the list with 𝑙𝑎𝑠𝑡 and 𝑖𝑛𝑖𝑡, rather than
with ℎ𝑒𝑎𝑑 and 𝑡𝑎𝑖𝑙.
@philip_schwarz
To summarise what we did to help understand SOFP’s mathematical definitions of left and right fold: we
turned them into code and expressed them in terms of a common function 𝑓𝑜𝑙𝑑 that uses a 𝑡𝑎𝑘𝑒 function
to extract an element from the list being folded, and a 𝑟𝑒𝑠𝑡 function to extract the rest of the list.
𝑓𝑜𝑙𝑑 ::	(𝑏 → 𝑎 → 𝑏)	→ ([𝑎]	→ 𝑎)	→ ([𝑎]	→ [𝑎])	→ 𝑏 → [𝑎]	→ 𝑏
𝑓𝑜𝑙𝑑 𝑓 𝑡𝑎𝑘𝑒 𝑟𝑒𝑠𝑡 𝑒 = 𝑒
𝑓𝑜𝑙𝑑 𝑓 𝑡𝑎𝑘𝑒 𝑟𝑒𝑠𝑡 𝑒 𝑎𝑠 = 𝑓 𝑏 𝑎
đ‘€â„Žđ‘’đ‘Ÿđ‘’ 𝑎 = 𝑡𝑎𝑘𝑒 𝑎𝑠
𝑏 = 𝑓𝑜𝑙𝑑 𝑓 𝑡𝑎𝑘𝑒 𝑟𝑒𝑠𝑡 𝑒 (𝑟𝑒𝑠𝑡 𝑎𝑠)
𝑓𝑜𝑙𝑑𝑙 :: (𝑏 → 𝑎 → 𝑏) → 𝑏 →[𝑎] → 𝑏
𝑓𝑜𝑙𝑑𝑙 𝑓 = 𝑓𝑜𝑙𝑑 𝑓 𝑙𝑎𝑠𝑡 𝑖𝑛𝑖𝑡
𝑓𝑜𝑙𝑑𝑟 :: (𝑎 → 𝑏 → 𝑏) → 𝑏 →[𝑎] → 𝑏
𝑓𝑜𝑙𝑑𝑟 𝑓 = 𝑓𝑜𝑙𝑑 𝑓𝑙𝑖𝑝 𝑓 ℎ𝑒𝑎𝑑 𝑡𝑎𝑖𝑙
𝑓𝑜𝑙𝑑𝑟 = 𝑒; 𝑓𝑜𝑙𝑑𝑟 đ‘„ â§ș 𝑠 = 𝑓(đ‘„, 𝑓𝑜𝑙𝑑𝑟(𝑠))
𝑓𝑜𝑙𝑑𝑙 = 𝑒; 𝑓𝑜𝑙𝑑𝑙 𝑠 â§ș [đ‘„] = 𝑓(𝑓𝑜𝑙𝑑𝑙 𝑠 , đ‘„)
𝑓𝑜𝑙𝑑𝑟 = 𝑒; 𝑓𝑜𝑙𝑑𝑟 𝑎𝑠 = 𝑓(ℎ𝑒𝑎𝑑(𝑎𝑠), 𝑓𝑜𝑙𝑑𝑟(𝑡𝑎𝑖𝑙(𝑎𝑠)))
𝑓𝑜𝑙𝑑𝑙 = 𝑒; 𝑓𝑜𝑙𝑑𝑙 𝑎𝑠 = 𝑓(𝑓𝑜𝑙𝑑𝑙 𝑖𝑛𝑖𝑡(𝑎𝑠) , 𝑙𝑎𝑠𝑡(𝑎𝑠))
Let’s feed one aspect of the above back into Sergei’s definitions. Let’s temporarily rewrite them by
replacing 𝑠 â§ș [đ‘„] and đ‘„ â§ș 𝑠 with as, and getting the definitions to extract the 𝑠 and the đ‘„ using the
functions ℎ𝑒𝑎𝑑, 𝑡𝑎𝑖𝑙, 𝑙𝑎𝑠𝑡 and 𝑖𝑛𝑖𝑡.
Notice how the flipping of 𝑓 done by the 𝑓𝑜𝑙𝑑𝑟 function above, is reflected, in the 𝑓𝑜𝑙𝑑𝑟 function below,
in the fact that its 𝑓 takes an 𝑎 and a 𝑏, rather than a 𝑏 and an 𝑎.
Another thing we can do to understand SOFP’s definitions of left and right folds, is to see how they work
when applied to a sample list, e.g. [đ‘„0, đ‘„1, đ‘„2, đ‘„3], when we run them manually.
In the next slide we first do this for the following definitions
𝑓𝑜𝑙𝑑𝑙 = 𝑒; 𝑓𝑜𝑙𝑑𝑙 𝑠 â§ș [đ‘„] = 𝑓(𝑓𝑜𝑙𝑑𝑙 𝑠 , đ‘„) 𝑓𝑜𝑙𝑑𝑟 = 𝑒; 𝑓𝑜𝑙𝑑𝑟 đ‘„ â§ș 𝑠 = 𝑓(đ‘„, 𝑓𝑜𝑙𝑑𝑟(𝑠))
𝑓𝑜𝑙𝑑𝑙 ∷ đ›œ → đ›Œ → đ›œ → đ›œ → đ›Œ → đ›œ
𝑓𝑜𝑙𝑑𝑙 𝑓 𝑒 = 𝑒
𝑓𝑜𝑙𝑑𝑙 𝑓 𝑒 đ‘„ ∶ đ‘„đ‘  = 𝑓𝑜𝑙𝑑𝑙 𝑓 𝑓 𝑒 đ‘„ đ‘„đ‘ 
𝑓𝑜𝑙𝑑𝑟 ∷ đ›Œ → đ›œ → đ›œ → đ›œ → đ›Œ → đ›œ
𝑓𝑜𝑙𝑑𝑟 𝑓 𝑒 = 𝑒
𝑓𝑜𝑙𝑑𝑟 𝑓 𝑒 đ‘„ ∶ đ‘„đ‘  = 𝑓 đ‘„ 𝑓𝑜𝑙𝑑𝑟 𝑓 𝑒 đ‘„đ‘ 
In the slide after that, we do it for SOFP’s definitions.
∶
/ 
đ‘„0 ∶
/ 
đ‘„1 ∶
/ 
đ‘„2 ∶
/ 
đ‘„3
𝑓
/ 
𝑓 đ‘„3
/ 
𝑓 đ‘„2
/ 
𝑓 đ‘„1
/ 
𝑒 đ‘„0
𝑓
/ 
đ‘„0 𝑓
/ 
đ‘„1 𝑓
/ 
đ‘„2 𝑓
/ 
đ‘„3 𝑒
đ‘„0: (đ‘„1: đ‘„2: đ‘„3: )
𝑓 𝑓 𝑓 𝑓 𝑒 đ‘„0 đ‘„1 đ‘„2 đ‘„3
var 𝑎𝑐𝑐 = 𝑒
foreach(đ‘„ in đ‘„s)
𝑎𝑐𝑐 = 𝑓(𝑎𝑐𝑐, đ‘„)
return 𝑎𝑐𝑐
𝑓𝑜𝑙𝑑𝑟 𝑓 𝑒 đ‘„đ‘ 
𝑓𝑜𝑙𝑑𝑙 𝑓 𝑒 đ‘„đ‘ 
đ‘„đ‘  = [đ‘„0, đ‘„1, đ‘„2, đ‘„3]
𝑓𝑜𝑙𝑑𝑟 ∷ đ›Œ → đ›œ → đ›œ → đ›œ → đ›Œ → đ›œ
𝑓𝑜𝑙𝑑𝑟 𝑓 𝑒 = 𝑒
𝑓𝑜𝑙𝑑𝑟 𝑓 𝑒 đ‘„: đ‘„đ‘  = 𝑓 đ‘„ 𝑓𝑜𝑙𝑑𝑟 𝑓 𝑒 đ‘„đ‘ 
𝑓𝑜𝑙𝑑𝑙 ∷ đ›œ → đ›Œ → đ›œ → đ›œ → đ›Œ → đ›œ
𝑓𝑜𝑙𝑑𝑙 𝑓 𝑒 = 𝑒
𝑓𝑜𝑙𝑑𝑙 𝑓 𝑒 đ‘„: đ‘„đ‘  = 𝑓𝑜𝑙𝑑𝑙 𝑓 𝑓 𝑒 đ‘„ đ‘„đ‘ 
𝑟𝑒𝑝𝑙𝑎𝑐𝑒:
∶ đ‘€đ‘–đ‘Ąâ„Ž 𝑓
đ‘€đ‘–đ‘Ąâ„Ž 𝑒
𝑓𝑜𝑙𝑑𝑟 𝑓 𝑒 [đ‘„0, đ‘„1, đ‘„2, đ‘„3]
𝑓 đ‘„0 𝑓𝑜𝑙𝑑𝑟 𝑓 𝑒 [đ‘„1, đ‘„2, đ‘„3]
𝑓 đ‘„0 (𝑓 đ‘„1 (𝑓𝑜𝑙𝑑𝑟 𝑓 𝑒 [đ‘„2, đ‘„3]))
𝑓 đ‘„0 (𝑓 đ‘„1 (𝑓 đ‘„2 (𝑓𝑜𝑙𝑑𝑟 𝑓 𝑒 [đ‘„3])))
𝑓 đ‘„0 (𝑓 đ‘„1 (𝑓 đ‘„2 (𝑓 đ‘„3 (𝑓𝑜𝑙𝑑𝑟 𝑓 𝑒 [ ]))))
𝑓 đ‘„0 (𝑓 đ‘„1 (𝑓 đ‘„2 (𝑓 đ‘„3 𝑒)))
𝑓 đ‘„0 (𝑓 đ‘„1 (𝑓 đ‘„2 (𝑓 đ‘„3 𝑒)))
𝑓𝑜𝑙𝑑𝑙 𝑓 𝑒 [đ‘„0, đ‘„1, đ‘„2, đ‘„3]
𝑓𝑜𝑙𝑑𝑙 𝑓 𝑓 𝑒 đ‘„0 [đ‘„1, đ‘„2, đ‘„3]
𝑓𝑜𝑙𝑑𝑙 𝑓 𝑓 𝑓 𝑒 đ‘„0 đ‘„1 [đ‘„2, đ‘„3]
𝑓𝑜𝑙𝑑𝑙 𝑓 𝑓 𝑓 𝑓 𝑒 đ‘„0 đ‘„1 đ‘„2 [đ‘„3]
𝑓𝑜𝑙𝑑𝑙 𝑓 𝑓 𝑓 𝑓 𝑓 𝑒 đ‘„0 đ‘„1 đ‘„2 đ‘„3 [ ]
𝑓 𝑓 𝑓 𝑓 𝑒 đ‘„0 đ‘„1 đ‘„2 đ‘„3
∶
/ 
đ‘„0 ∶
/ 
đ‘„1 ∶
/ 
đ‘„2 ∶
/ 
đ‘„3
𝑓
/ 
𝑓 đ‘„3
/ 
𝑓 đ‘„2
/ 
𝑓 đ‘„1
/ 
𝑒 đ‘„0
𝑓
/ 
đ‘„0 𝑓
/ 
đ‘„1 𝑓
/ 
đ‘„2 𝑓
/ 
đ‘„3 𝑒
đ‘„0: (đ‘„1: đ‘„2: đ‘„3: )
𝑓(𝑓 𝑓 𝑓 𝑒, đ‘„0 , đ‘„1 , đ‘„2 , đ‘„3)
𝑓𝑜𝑙𝑑𝑟 đ‘„đ‘ 
𝑓𝑜𝑙𝑑𝑙 đ‘„đ‘ 
đ‘„đ‘  = [đ‘„0, đ‘„1, đ‘„2, đ‘„3]
𝑓(đ‘„0, 𝑓(đ‘„1, 𝑓(đ‘„2, 𝑓(đ‘„3, 𝑒))))
𝑓𝑜𝑙𝑑𝑙 = 𝑒; 𝑓𝑜𝑙𝑑𝑙 𝑠 â§ș [đ‘„] = 𝑓(𝑓𝑜𝑙𝑑𝑙 𝑠 , đ‘„)
𝑓𝑜𝑙𝑑𝑟 = 𝑒; 𝑓𝑜𝑙𝑑𝑟 đ‘„ â§ș 𝑠 = 𝑓(đ‘„, 𝑓𝑜𝑙𝑑𝑟(𝑠))
𝑓𝑜𝑙𝑑𝑙 đ‘„0, đ‘„1, đ‘„2, đ‘„3 ,
𝑓 𝑓𝑜𝑙𝑑𝑙 đ‘„0, đ‘„1, đ‘„2 , đ‘„3
𝑓(𝑓(𝑓𝑜𝑙𝑑𝑙 [đ‘„0, đ‘„1] , đ‘„2), đ‘„3)
𝑓 𝑓 𝑓 𝑓𝑜𝑙𝑑𝑙 đ‘„0 , đ‘„1 , đ‘„2 , đ‘„3
𝑓 𝑓 𝑓 𝑓 𝑓𝑜𝑙𝑑𝑙 [ ] , đ‘„0 , đ‘„1 , đ‘„2 , đ‘„3
𝑓 𝑓 𝑓 𝑓 𝑒, đ‘„0 , đ‘„1 , đ‘„2 , đ‘„3
𝑓𝑜𝑙𝑑𝑟([đ‘„0, đ‘„1, đ‘„2, đ‘„3])
𝑓(đ‘„0, 𝑓𝑜𝑙𝑑𝑟([đ‘„1, đ‘„2, đ‘„3]))
𝑓(đ‘„0, 𝑓(đ‘„1, 𝑓𝑜𝑙𝑑𝑟([đ‘„2, đ‘„3])))
𝑓(đ‘„0, 𝑓(đ‘„1, 𝑓(đ‘„2, 𝑓𝑜𝑙𝑑𝑟([đ‘„3]))))
𝑓(đ‘„0, 𝑓(đ‘„1, 𝑓(đ‘„2, 𝑓(đ‘„3, 𝑓𝑜𝑙𝑑𝑟([])))))
𝑓(đ‘„0, 𝑓(đ‘„1, 𝑓(đ‘„2, 𝑓(đ‘„3, 𝑒))))
𝑓𝑜𝑙𝑑𝑙 ∷ đ›œ → đ›Œ → đ›œ → đ›œ → đ›Œ → đ›œ
𝑓𝑜𝑙𝑑𝑙 𝑓 𝑒 = 𝑒
𝑓𝑜𝑙𝑑𝑙 𝑓 𝑒 đ‘„: đ‘„đ‘  = 𝑓𝑜𝑙𝑑𝑙 𝑓 𝑓 𝑒 đ‘„ đ‘„đ‘ 
𝑓𝑜𝑙𝑑𝑙 = 𝑒; 𝑓𝑜𝑙𝑑𝑙 𝑠 â§ș [đ‘„] = 𝑓(𝑓𝑜𝑙𝑑𝑙 𝑠 , đ‘„)
∶
/ 
đ‘„0 ∶
/ 
đ‘„1 ∶
/ 
đ‘„2 ∶
/ 
đ‘„3
đ‘„0: (đ‘„1: đ‘„2: đ‘„3: )
đ‘„đ‘  = [đ‘„0, đ‘„1, đ‘„2, đ‘„3]
𝑓
/ 
𝑓 đ‘„3
/ 
𝑓 đ‘„2
/ 
𝑓 đ‘„1
/ 
𝑒 đ‘„0
𝑓𝑜𝑙𝑑𝑙 𝑓 𝑒 [đ‘„0, đ‘„1, đ‘„2, đ‘„3]
𝑓𝑜𝑙𝑑𝑙 𝑓 𝑓 𝑒 đ‘„0 [đ‘„1, đ‘„2, đ‘„3]
𝑓𝑜𝑙𝑑𝑙 𝑓 𝑓 𝑓 𝑒 đ‘„0 đ‘„1 [đ‘„2, đ‘„3]
𝑓𝑜𝑙𝑑𝑙 𝑓 𝑓 𝑓 𝑓 𝑒 đ‘„0 đ‘„1 đ‘„2 [đ‘„3]
𝑓𝑜𝑙𝑑𝑙 𝑓 𝑓 𝑓 𝑓 𝑓 𝑒 đ‘„0 đ‘„1 đ‘„2 đ‘„3 [ ]
𝑓 𝑓 𝑓 𝑓 𝑒 đ‘„0 đ‘„1 đ‘„2 đ‘„3
𝑓𝑜𝑙𝑑𝑙 đ‘„0, đ‘„1, đ‘„2, đ‘„3 ,
𝑓 𝑓𝑜𝑙𝑑𝑙 đ‘„0, đ‘„1, đ‘„2 , đ‘„3
𝑓(𝑓(𝑓𝑜𝑙𝑑𝑙 [đ‘„0, đ‘„1] , đ‘„2), đ‘„3)
𝑓 𝑓 𝑓 𝑓𝑜𝑙𝑑𝑙 đ‘„0 , đ‘„1 , đ‘„2 , đ‘„3
𝑓 𝑓 𝑓 𝑓 𝑓𝑜𝑙𝑑𝑙 [ ] , đ‘„0 , đ‘„1 , đ‘„2 , đ‘„3
𝑓 𝑓 𝑓 𝑓 𝑒, đ‘„0 , đ‘„1 , đ‘„2 , đ‘„3
Now let’s compare the results for both
definitions of 𝑓𝑜𝑙𝑑𝑙. The results are the same.
@philip_schwarz
𝑓
/ 
đ‘„0 𝑓
/ 
đ‘„1 𝑓
/ 
đ‘„2 𝑓
/ 
đ‘„3 𝑒
𝑓𝑜𝑙𝑑𝑟 ∷ đ›Œ → đ›œ → đ›œ → đ›œ → đ›Œ → đ›œ
𝑓𝑜𝑙𝑑𝑟 𝑓 𝑒 = 𝑒
𝑓𝑜𝑙𝑑𝑟 𝑓 𝑒 đ‘„: đ‘„đ‘  = 𝑓 đ‘„ 𝑓𝑜𝑙𝑑𝑟 𝑓 𝑒 đ‘„đ‘ 
𝑓𝑜𝑙𝑑𝑟 𝑓 𝑒 [đ‘„0, đ‘„1, đ‘„2, đ‘„3]
𝑓 đ‘„0 𝑓𝑜𝑙𝑑𝑟 𝑓 𝑒 [đ‘„1, đ‘„2, đ‘„3]
𝑓 đ‘„0 (𝑓 đ‘„1 (𝑓𝑜𝑙𝑑𝑟 𝑓 𝑒 [đ‘„2, đ‘„3]))
𝑓 đ‘„0 (𝑓 đ‘„1 (𝑓 đ‘„2 (𝑓𝑜𝑙𝑑𝑟 𝑓 𝑒 [đ‘„3])))
𝑓 đ‘„0 (𝑓 đ‘„1 (𝑓 đ‘„2 (𝑓 đ‘„3 (𝑓𝑜𝑙𝑑𝑟 𝑓 𝑒 [ ]))))
𝑓 đ‘„0 (𝑓 đ‘„1 (𝑓 đ‘„2 (𝑓 đ‘„3 𝑒)))
𝑓𝑜𝑙𝑑𝑟 = 𝑒; 𝑓𝑜𝑙𝑑𝑟 đ‘„ â§ș 𝑠 = 𝑓(đ‘„, 𝑓𝑜𝑙𝑑𝑟(𝑠))
𝑓𝑜𝑙𝑑𝑟([đ‘„0, đ‘„1, đ‘„2, đ‘„3])
𝑓(đ‘„0, 𝑓𝑜𝑙𝑑𝑟([đ‘„1, đ‘„2, đ‘„3]))
𝑓(đ‘„0, 𝑓(đ‘„1, 𝑓𝑜𝑙𝑑𝑟([đ‘„2, đ‘„3])))
𝑓(đ‘„0, 𝑓(đ‘„1, 𝑓(đ‘„2, 𝑓𝑜𝑙𝑑𝑟([đ‘„3]))))
𝑓(đ‘„0, 𝑓(đ‘„1, 𝑓(đ‘„2, 𝑓(đ‘„3, 𝑓𝑜𝑙𝑑𝑟([])))))
𝑓(đ‘„0, 𝑓(đ‘„1, 𝑓(đ‘„2, 𝑓(đ‘„3, 𝑒))))
∶
/ 
đ‘„0 ∶
/ 
đ‘„1 ∶
/ 
đ‘„2 ∶
/ 
đ‘„3
đ‘„0: (đ‘„1: đ‘„2: đ‘„3: )
đ‘„đ‘  = [đ‘„0, đ‘„1, đ‘„2, đ‘„3]
And now let’s compare the results for both
definitions of 𝑓𝑜𝑙𝑑𝑟. Again, the results are the same.
The way 𝑓𝑜𝑙𝑑𝑟 applies 𝑓 to đ‘„, 𝑩, z is by associating to the right.
The way 𝑓𝑜𝑙𝑑𝑙 does it is by associating to the right.
Thinking of 𝑓 as an infix operator can help to grasp this.
𝑓𝑜𝑙𝑑𝑟 𝑓(đ‘„, 𝑓(𝑩, 𝑧)) đ‘„ ⊕ 𝑩 ⊕ 𝑧
𝑓𝑜𝑙𝑑𝑙 𝑓 𝑓 đ‘„, 𝑩 , 𝑧 (đ‘„ ⊕ 𝑩) ⊕ 𝑧
𝑓𝑜𝑙𝑑𝑟 ⊕ 𝑒 đ‘„, 𝑩, z = đ‘„ ⊕ (𝑩 ⊕ 𝑧 ⊕ 𝑒 )
𝑓𝑜𝑙𝑑𝑟 (+) 0 [1,2,3] = 1 + (2 + (3 + 0)) = 6
𝑓𝑜𝑙𝑑𝑙 (+) 0 [1,2,3] = ((0 + 1) + 2) + 3 = 6
𝑓𝑜𝑙𝑑𝑟 − 0 1,2,3 = 1 − (2 − (3 − 0)) = 2
𝑓𝑜𝑙𝑑𝑙 − 0 1,2,3 = ((0 − 1) − 2) − 3 = −6
⊕
/ 
đ‘„ ⊕
/ 
𝑩 ⊕
/ 
𝑧 𝑒
⊕
/ 
⊕ 𝑧
/ 
⊕ 𝑩
/ 
𝑒 đ‘„
𝑓𝑜𝑙𝑑𝑙 ⊕ 𝑒 đ‘„, 𝑩, 𝑧 = ((𝑒 ⊕ đ‘„) ⊕ 𝑩) ⊕ 𝑧
Addition is associative, so associating to the left and to the right yields the
same result. But subtraction isn’t associative, so associating to the left yields
a result that is different to the one yielded when associating to the right.
We have seen that Sergei’s definitions of left and right folds make perfect sense.
Not only are they simple and succinct, they are also free of implementation details like tail recursion.
That’s all. I hope you found this slide deck useful.
By the way, in case you are interested, see below for a whole series of slide decks dedicated to folding.

More Related Content

What's hot

What's hot (20)

Kleisli Composition
Kleisli CompositionKleisli Composition
Kleisli Composition
 
Monoids - Part 1 - with examples using Scalaz and Cats
Monoids - Part 1 - with examples using Scalaz and CatsMonoids - Part 1 - with examples using Scalaz and Cats
Monoids - Part 1 - with examples using Scalaz and Cats
 
The Functional Programming Triad of Map, Filter and Fold
The Functional Programming Triad of Map, Filter and FoldThe Functional Programming Triad of Map, Filter and Fold
The Functional Programming Triad of Map, Filter and Fold
 
ZIO Queue
ZIO QueueZIO Queue
ZIO Queue
 
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...
 
Ad hoc Polymorphism using Type Classes and Cats
Ad hoc Polymorphism using Type Classes and CatsAd hoc Polymorphism using Type Classes and Cats
Ad hoc Polymorphism using Type Classes and Cats
 
Functional Core and Imperative Shell - Game of Life Example - Haskell and Scala
Functional Core and Imperative Shell - Game of Life Example - Haskell and ScalaFunctional Core and Imperative Shell - Game of Life Example - Haskell and Scala
Functional Core and Imperative Shell - Game of Life Example - Haskell and Scala
 
Functional Domain Modeling - The ZIO 2 Way
Functional Domain Modeling - The ZIO 2 WayFunctional Domain Modeling - The ZIO 2 Way
Functional Domain Modeling - The ZIO 2 Way
 
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...
 
Refactoring: A First Example - Martin Fowler’s First Example of Refactoring, ...
Refactoring: A First Example - Martin Fowler’s First Example of Refactoring, ...Refactoring: A First Example - Martin Fowler’s First Example of Refactoring, ...
Refactoring: A First Example - Martin Fowler’s First Example of Refactoring, ...
 
Scala 3 by Example - Algebraic Data Types for Domain Driven Design - Part 1
Scala 3 by Example - Algebraic Data Types for Domain Driven Design - Part 1Scala 3 by Example - Algebraic Data Types for Domain Driven Design - Part 1
Scala 3 by Example - Algebraic Data Types for Domain Driven Design - Part 1
 
Exploring ZIO Prelude: The game changer for typeclasses in Scala
Exploring ZIO Prelude: The game changer for typeclasses in ScalaExploring ZIO Prelude: The game changer for typeclasses in Scala
Exploring ZIO Prelude: The game changer for typeclasses in Scala
 
non-strict functions, bottom and scala by-name parameters
non-strict functions, bottom and scala by-name parametersnon-strict functions, bottom and scala by-name parameters
non-strict functions, bottom and scala by-name parameters
 
‘go-to’ general-purpose sequential collections - from Java To Scala
‘go-to’ general-purpose sequential collections -from Java To Scala‘go-to’ general-purpose sequential collections -from Java To Scala
‘go-to’ general-purpose sequential collections - from Java To Scala
 
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...
 
Sierpinski Triangle - Polyglot FP for Fun and Profit - Haskell and Scala
Sierpinski Triangle - Polyglot FP for Fun and Profit - Haskell and ScalaSierpinski Triangle - Polyglot FP for Fun and Profit - Haskell and Scala
Sierpinski Triangle - Polyglot FP for Fun and Profit - Haskell and Scala
 
Sequence and Traverse - Part 1
Sequence and Traverse - Part 1Sequence and Traverse - Part 1
Sequence and Traverse - Part 1
 
The Uniform Access Principle
The Uniform Access PrincipleThe Uniform Access Principle
The Uniform Access Principle
 
Scala 3 by Example - Algebraic Data Types for Domain Driven Design - Part 2
Scala 3 by Example - Algebraic Data Types for Domain Driven Design - Part 2Scala 3 by Example - Algebraic Data Types for Domain Driven Design - Part 2
Scala 3 by Example - Algebraic Data Types for Domain Driven Design - Part 2
 
Functional Patterns in Domain Modeling
Functional Patterns in Domain ModelingFunctional Patterns in Domain Modeling
Functional Patterns in Domain Modeling
 

Similar to Left and Right Folds - Comparison of a mathematical definition and a programmatic one - Polyglot FP for Fun and Profit - Haskell and Scala

Semana 24 funciones iv ĂĄlgebra uni ccesa007
Semana 24 funciones iv ĂĄlgebra uni ccesa007Semana 24 funciones iv ĂĄlgebra uni ccesa007
Semana 24 funciones iv ĂĄlgebra uni ccesa007
Demetrio Ccesa Rayme
 
Relativity
RelativityRelativity
Relativity
edgardoangeles1
 

Similar to Left and Right Folds - Comparison of a mathematical definition and a programmatic one - Polyglot FP for Fun and Profit - Haskell and Scala (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
 
Dual Spaces of Generalized Cesaro Sequence Space and Related Matrix Mapping
Dual Spaces of Generalized Cesaro Sequence Space and Related Matrix MappingDual Spaces of Generalized Cesaro Sequence Space and Related Matrix Mapping
Dual Spaces of Generalized Cesaro Sequence Space and Related Matrix Mapping
 
Differential Geometry for Machine Learning
Differential Geometry for Machine LearningDifferential Geometry for Machine Learning
Differential Geometry for Machine Learning
 
Basic calculus (ii) recap
Basic calculus (ii) recapBasic calculus (ii) recap
Basic calculus (ii) recap
 
Semana 24 funciones iv ĂĄlgebra uni ccesa007
Semana 24 funciones iv ĂĄlgebra uni ccesa007Semana 24 funciones iv ĂĄlgebra uni ccesa007
Semana 24 funciones iv ĂĄlgebra uni ccesa007
 
On ranges and null spaces of a special type of operator named 𝝀 − 𝒋𝒆𝒄𝒕𝒊𝒐𝒏. – ...
On ranges and null spaces of a special type of operator named 𝝀 − 𝒋𝒆𝒄𝒕𝒊𝒐𝒏. – ...On ranges and null spaces of a special type of operator named 𝝀 − 𝒋𝒆𝒄𝒕𝒊𝒐𝒏. – ...
On ranges and null spaces of a special type of operator named 𝝀 − 𝒋𝒆𝒄𝒕𝒊𝒐𝒏. – ...
 
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 #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
 
E0561719
E0561719E0561719
E0561719
 
Teoria Numérica (Palestra 01)
Teoria Numérica (Palestra 01)Teoria Numérica (Palestra 01)
Teoria Numérica (Palestra 01)
 
PRODUCT RULES
PRODUCT RULESPRODUCT RULES
PRODUCT RULES
 
Matrix Transformations on Some Difference Sequence Spaces
Matrix Transformations on Some Difference Sequence SpacesMatrix Transformations on Some Difference Sequence Spaces
Matrix Transformations on Some Difference Sequence Spaces
 
Recurrence relation of Bessel's and Legendre's function
Recurrence relation of Bessel's and Legendre's functionRecurrence relation of Bessel's and Legendre's function
Recurrence relation of Bessel's and Legendre's function
 
3 capitulo-iii-matriz-asociada-sem-14-t-l-d
3 capitulo-iii-matriz-asociada-sem-14-t-l-d3 capitulo-iii-matriz-asociada-sem-14-t-l-d
3 capitulo-iii-matriz-asociada-sem-14-t-l-d
 
Further Results On The Basis Of Cauchy’s Proper Bound for the Zeros of Entire...
Further Results On The Basis Of Cauchy’s Proper Bound for the Zeros of Entire...Further Results On The Basis Of Cauchy’s Proper Bound for the Zeros of Entire...
Further Results On The Basis Of Cauchy’s Proper Bound for the Zeros of Entire...
 
Generalized Laplace - Mellin Integral Transformation
Generalized Laplace - Mellin Integral TransformationGeneralized Laplace - Mellin Integral Transformation
Generalized Laplace - Mellin Integral Transformation
 
Relativity
RelativityRelativity
Relativity
 
Change variablethm
Change variablethmChange variablethm
Change variablethm
 
AJMS_480_23.pdf
AJMS_480_23.pdfAJMS_480_23.pdf
AJMS_480_23.pdf
 
MT102 ЛДĐșц 4
MT102 ЛДĐșц 4MT102 ЛДĐșц 4
MT102 ЛДĐșц 4
 

More from Philip Schwarz

N-Queens Combinatorial Puzzle meets Cats
N-Queens Combinatorial Puzzle meets CatsN-Queens Combinatorial Puzzle meets Cats
N-Queens Combinatorial Puzzle meets Cats
Philip Schwarz
 

More from Philip Schwarz (20)

Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
Direct Style Effect Systems -The Print[A] Example- A Comprehension AidDirect Style Effect Systems -The Print[A] Example- A Comprehension Aid
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
 
Folding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth in a seriesFolding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth 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
 
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...
 
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...
 
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 (...
 
The Sieve of Eratosthenes - Part 1 - with minor corrections
The Sieve of Eratosthenes - Part 1 - with minor correctionsThe Sieve of Eratosthenes - Part 1 - with minor corrections
The Sieve of Eratosthenes - Part 1 - with minor corrections
 
The Sieve of Eratosthenes - Part 1
The Sieve of Eratosthenes - Part 1The Sieve of Eratosthenes - Part 1
The Sieve of Eratosthenes - Part 1
 
Computer Graphics in Java and Scala - Part 1b
Computer Graphics in Java and Scala - Part 1bComputer Graphics in Java and Scala - Part 1b
Computer Graphics in Java and Scala - Part 1b
 
The Expression Problem - Part 2
The Expression Problem - Part 2The Expression Problem - Part 2
The Expression Problem - Part 2
 

Recently uploaded

JustNaik Solution Deck (stage bus sector)
JustNaik Solution Deck (stage bus sector)JustNaik Solution Deck (stage bus sector)
JustNaik Solution Deck (stage bus sector)
Max Lee
 
Microsoft 365 Copilot; An AI tool changing the world of work _PDF.pdf
Microsoft 365 Copilot; An AI tool changing the world of work _PDF.pdfMicrosoft 365 Copilot; An AI tool changing the world of work _PDF.pdf
Microsoft 365 Copilot; An AI tool changing the world of work _PDF.pdf
Q-Advise
 

Recently uploaded (20)

Top Mobile App Development Companies 2024
Top Mobile App Development Companies 2024Top Mobile App Development Companies 2024
Top Mobile App Development Companies 2024
 
COMPUTER AND ITS COMPONENTS PPT.by naitik sharma Class 9th A mittal internati...
COMPUTER AND ITS COMPONENTS PPT.by naitik sharma Class 9th A mittal internati...COMPUTER AND ITS COMPONENTS PPT.by naitik sharma Class 9th A mittal internati...
COMPUTER AND ITS COMPONENTS PPT.by naitik sharma Class 9th A mittal internati...
 
AI/ML Infra Meetup | Reducing Prefill for LLM Serving in RAG
AI/ML Infra Meetup | Reducing Prefill for LLM Serving in RAGAI/ML Infra Meetup | Reducing Prefill for LLM Serving in RAG
AI/ML Infra Meetup | Reducing Prefill for LLM Serving in RAG
 
Implementing KPIs and Right Metrics for Agile Delivery Teams.pdf
Implementing KPIs and Right Metrics for Agile Delivery Teams.pdfImplementing KPIs and Right Metrics for Agile Delivery Teams.pdf
Implementing KPIs and Right Metrics for Agile Delivery Teams.pdf
 
5 Reasons Driving Warehouse Management Systems Demand
5 Reasons Driving Warehouse Management Systems Demand5 Reasons Driving Warehouse Management Systems Demand
5 Reasons Driving Warehouse Management Systems Demand
 
AI/ML Infra Meetup | Perspective on Deep Learning Framework
AI/ML Infra Meetup | Perspective on Deep Learning FrameworkAI/ML Infra Meetup | Perspective on Deep Learning Framework
AI/ML Infra Meetup | Perspective on Deep Learning Framework
 
Secure Software Ecosystem Teqnation 2024
Secure Software Ecosystem Teqnation 2024Secure Software Ecosystem Teqnation 2024
Secure Software Ecosystem Teqnation 2024
 
Agnieszka Andrzejewska - BIM School Course in KrakĂłw
Agnieszka Andrzejewska - BIM School Course in KrakĂłwAgnieszka Andrzejewska - BIM School Course in KrakĂłw
Agnieszka Andrzejewska - BIM School Course in KrakĂłw
 
Abortion ^Clinic ^%[+971588192166''] Abortion Pill Al Ain (?@?) Abortion Pill...
Abortion ^Clinic ^%[+971588192166''] Abortion Pill Al Ain (?@?) Abortion Pill...Abortion ^Clinic ^%[+971588192166''] Abortion Pill Al Ain (?@?) Abortion Pill...
Abortion ^Clinic ^%[+971588192166''] Abortion Pill Al Ain (?@?) Abortion Pill...
 
The Impact of PLM Software on Fashion Production
The Impact of PLM Software on Fashion ProductionThe Impact of PLM Software on Fashion Production
The Impact of PLM Software on Fashion Production
 
A Guideline to Zendesk to Re:amaze Data Migration
A Guideline to Zendesk to Re:amaze Data MigrationA Guideline to Zendesk to Re:amaze Data Migration
A Guideline to Zendesk to Re:amaze Data Migration
 
JustNaik Solution Deck (stage bus sector)
JustNaik Solution Deck (stage bus sector)JustNaik Solution Deck (stage bus sector)
JustNaik Solution Deck (stage bus sector)
 
Microsoft 365 Copilot; An AI tool changing the world of work _PDF.pdf
Microsoft 365 Copilot; An AI tool changing the world of work _PDF.pdfMicrosoft 365 Copilot; An AI tool changing the world of work _PDF.pdf
Microsoft 365 Copilot; An AI tool changing the world of work _PDF.pdf
 
INGKA DIGITAL: Linked Metadata by Design
INGKA DIGITAL: Linked Metadata by DesignINGKA DIGITAL: Linked Metadata by Design
INGKA DIGITAL: Linked Metadata by Design
 
how-to-download-files-safely-from-the-internet.pdf
how-to-download-files-safely-from-the-internet.pdfhow-to-download-files-safely-from-the-internet.pdf
how-to-download-files-safely-from-the-internet.pdf
 
GraphSummit Stockholm - Neo4j - Knowledge Graphs and Product Updates
GraphSummit Stockholm - Neo4j - Knowledge Graphs and Product UpdatesGraphSummit Stockholm - Neo4j - Knowledge Graphs and Product Updates
GraphSummit Stockholm - Neo4j - Knowledge Graphs and Product Updates
 
AI/ML Infra Meetup | ML explainability in Michelangelo
AI/ML Infra Meetup | ML explainability in MichelangeloAI/ML Infra Meetup | ML explainability in Michelangelo
AI/ML Infra Meetup | ML explainability in Michelangelo
 
Studiovity film pre-production and screenwriting software
Studiovity film pre-production and screenwriting softwareStudiovity film pre-production and screenwriting software
Studiovity film pre-production and screenwriting software
 
Facemoji Keyboard released its 2023 State of Emoji report, outlining the most...
Facemoji Keyboard released its 2023 State of Emoji report, outlining the most...Facemoji Keyboard released its 2023 State of Emoji report, outlining the most...
Facemoji Keyboard released its 2023 State of Emoji report, outlining the most...
 
10 Essential Software Testing Tools You Need to Know About.pdf
10 Essential Software Testing Tools You Need to Know About.pdf10 Essential Software Testing Tools You Need to Know About.pdf
10 Essential Software Testing Tools You Need to Know About.pdf
 

Left and Right Folds - Comparison of a mathematical definition and a programmatic one - Polyglot FP for Fun and Profit - Haskell and Scala

  • 1. Based on definitions from Left and Right Folds Comparison of a mathematical definition and a programmatic one Polyglot FP for Fun and Profit - Haskell and Scala @philip_schwarz slides by https://www.slideshare.net/pjschwarz Sergei Winitzki sergei-winitzki-11a6431 Richard Bird http://www.cs.ox.ac.uk/people/richard.bird/
  • 2. 𝑓𝑜𝑙𝑑𝑙 ∷ đ›œ → đ›Œ → đ›œ → đ›œ → đ›Œ → đ›œ 𝑓𝑜𝑙𝑑𝑙 𝑓 𝑒 = 𝑒 𝑓𝑜𝑙𝑑𝑙 𝑓 𝑒 đ‘„ ∶ đ‘„đ‘  = 𝑓𝑜𝑙𝑑𝑙 𝑓 𝑓 𝑒 đ‘„ đ‘„đ‘  𝑓𝑜𝑙𝑑𝑟 ∷ đ›Œ → đ›œ → đ›œ → đ›œ → đ›Œ → đ›œ 𝑓𝑜𝑙𝑑𝑟 𝑓 𝑒 = 𝑒 𝑓𝑜𝑙𝑑𝑟 𝑓 𝑒 đ‘„ ∶ đ‘„đ‘  = 𝑓 đ‘„ 𝑓𝑜𝑙𝑑𝑟 𝑓 𝑒 đ‘„đ‘  If I have to write down the definitions of a left fold and a right fold for lists, here is what I write While both definitions are recursive, the left fold is tail recursive, whereas the right fold isn’t. Although I am very familiar with the above definitions, and view them as doing a good job of explaining the two folds, I am always interested in alternative ways of explaining things, and so I have been looking at Sergei Winitzki’s mathematical definitions of left and right folds, in his upcoming book: The Science of Functional Programming (SOFP). Sergei’s definitions of the folds are in the top two rows of the following table Sergei Winitzki Richard Bird @philip_schwarz
  • 3. test1 = TestCase (assertEqual "foldl(+) 0 []" 0 (foldl (+) 0 [])) test2 = TestCase (assertEqual "foldl(+) 0 [1,2,3,4]" 10 (foldl (+) 0 [1,2,3,4])) test3 = TestCase (assertEqual "foldr (+) 0 []" 0 (foldr (+) 0 [])) test4 = TestCase (assertEqual "foldr (+) 0 [1,2,3,4]" 10 (foldr (+) 0 [1,2,3,4])) Left folds and right folds do not necessarily produce the same results. According to the first duality theorem of folding, one case in which the results are the same, is when we fold using the unit and associative operation of a monoid. First duality theorem. Suppose ⊕ is associative with unit 𝑒. Then 𝑓𝑜𝑙𝑑𝑟 ⊕ 𝑒 đ‘„đ‘  = 𝑓𝑜𝑙𝑑𝑙 ⊕ 𝑒 đ‘„đ‘  For all finite lists đ‘„đ‘ . test5 = TestCase (assertEqual "foldl(-) 0 []" 0 (foldl (+) 0 [])) test6 = TestCase (assertEqual "foldl(-) 0 [1,2,3,4]" (- 10) (foldl (-) 0 [1,2,3,4])) test7 = TestCase (assertEqual "foldr (-) 0 []" 0 (foldr (-) 0 [])) test8 = TestCase (assertEqual "foldr (-) 0 [1,2,3,4]" (- 2) (foldr (-) 0 [1,2,3,4])) Folding integers left and right using the (Int,+,0) monoid, for example, produces the same results. But folding integers left and right using subtraction and zero, does not produce the same results, and in fact (Int,-,0) is not a monoid, because subtraction is not associative.
  • 4. 𝑓 = 𝑏; 𝑓 đ‘„ â§ș 𝑠 = 𝑔(đ‘„, 𝑓(𝑠)) 𝑓 = 𝑏; 𝑓 𝑠 â§ș [đ‘„] = 𝑔(𝑓 𝑠 , đ‘„) To avoid any confusion (the definitions use the same function name 𝑓), and to align with the definitions on the right, let’s modify Sergei’s definitions by doing some simple renaming. Here are Sergei’s mathematical definitions again, on the right (the â§ș operator is list concatenation). Notice how neither definition is tail recursive. That is deliberate. As Sergei explained to me: “I'd like to avoid putting tail recursion into a mathematical formula, because tail recursion is just a detail of how we implement this function” and “The fact that foldLeft is tail recursive for List is an implementation detail that is specific to the List type. It will be different for other sequence types. I do not want to put the implementation details into the formulas.” 𝑓 → 𝑓𝑜𝑙𝑑𝑙 𝑔 → 𝑓 𝑏 → 𝑒 𝑓𝑜𝑙𝑑𝑟 = 𝑒; 𝑓𝑜𝑙𝑑𝑟 đ‘„ â§ș 𝑠 = 𝑓(đ‘„, 𝑓𝑜𝑙𝑑𝑟(𝑠)) 𝑓𝑜𝑙𝑑𝑙 = 𝑒; 𝑓𝑜𝑙𝑑𝑙 𝑠 â§ș [đ‘„] = 𝑓(𝑓𝑜𝑙𝑑𝑙 𝑠 , đ‘„) 𝑓 → 𝑓𝑜𝑙𝑑𝑟 𝑔 → 𝑓 𝑏 → 𝑒 𝑓𝑜𝑙𝑑𝑙 ∷ đ›œ → đ›Œ → đ›œ → đ›œ → đ›Œ → đ›œ 𝑓𝑜𝑙𝑑𝑙 𝑓 𝑒 = 𝑒 𝑓𝑜𝑙𝑑𝑙 𝑓 𝑒 đ‘„ ∶ đ‘„đ‘  = 𝑓𝑜𝑙𝑑𝑙 𝑓 𝑓 𝑒 đ‘„ đ‘„đ‘  𝑓𝑜𝑙𝑑𝑟 ∷ đ›Œ → đ›œ → đ›œ → đ›œ → đ›Œ → đ›œ 𝑓𝑜𝑙𝑑𝑟 𝑓 𝑒 = 𝑒 𝑓𝑜𝑙𝑑𝑟 𝑓 𝑒 đ‘„ ∶ đ‘„đ‘  = 𝑓 đ‘„ 𝑓𝑜𝑙𝑑𝑟 𝑓 𝑒 đ‘„đ‘  𝑓 = 𝑏; 𝑓 đ‘„ â§ș 𝑠 = 𝑔(đ‘„, 𝑓(𝑠)) 𝑓 = 𝑏; 𝑓 𝑠 â§ș [đ‘„] = 𝑔(𝑓 𝑠 , đ‘„)
  • 5. 𝑓𝑜𝑙𝑑𝑟 𝑓 𝑒 [ ] = 𝑒 𝑓𝑜𝑙𝑑𝑟 𝑓 𝑒 đ‘„ â§ș 𝑠 = 𝑓 đ‘„ (𝑓𝑜𝑙𝑑𝑟 𝑓 𝑒 𝑠) 𝑓𝑜𝑙𝑑𝑙 𝑓 𝑒 = 𝑒 𝑓𝑜𝑙𝑑𝑙 𝑓 𝑒 𝑠 â§ș [đ‘„] = 𝑓 𝑓𝑜𝑙𝑑𝑙 𝑓 𝑒 𝑠 đ‘„ 𝑓𝑜𝑙𝑑𝑙 :: (𝑏 → 𝑎 → 𝑏) → 𝑏 →[𝑎] → 𝑏 𝑓𝑜𝑙𝑑𝑙 𝑓 𝑒 = 𝑒 𝑓𝑜𝑙𝑑𝑙 𝑓 𝑒 𝑎𝑠 = 𝑓 𝑓𝑜𝑙𝑑𝑙 𝑓 𝑒 (𝑖𝑛𝑖𝑡 𝑎𝑠) (𝑙𝑎𝑠𝑡 𝑎𝑠) 𝑓𝑜𝑙𝑑𝑟 :: (𝑎 → 𝑏 → 𝑏) → 𝑏 →[𝑎] → 𝑏 𝑓𝑜𝑙𝑑𝑟 𝑓 𝑒 = 𝑒 𝑓𝑜𝑙𝑑𝑟 𝑓 𝑒 𝑎𝑠 = 𝑓 ℎ𝑒𝑎𝑑 𝑎𝑠 𝑓𝑜𝑙𝑑𝑟 𝑓 𝑒 (𝑡𝑎𝑖𝑙 𝑎𝑠) 𝑓𝑜𝑙𝑑𝑙 :: (𝑏 → 𝑎 → 𝑏) → 𝑏 →[𝑎] → 𝑏 𝑓𝑜𝑙𝑑𝑙 𝑓 𝑒 = 𝑒 𝑓𝑜𝑙𝑑𝑙 𝑓 𝑒 𝑎𝑠 = 𝑓 𝑏 𝑎 đ‘€â„Žđ‘’đ‘Ÿđ‘’ 𝑎 = 𝑙𝑎𝑠𝑡 𝑎𝑠 𝑏 = 𝑓𝑜𝑙𝑑𝑙 𝑓 𝑒 (𝑖𝑛𝑖𝑡 𝑎𝑠) 𝑓𝑜𝑙𝑑𝑟 :: (𝑎 → 𝑏 → 𝑏) → 𝑏 →[𝑎] → 𝑏 𝑓𝑜𝑙𝑑𝑟 𝑓 𝑒 = 𝑒 𝑓𝑜𝑙𝑑𝑟 𝑓 𝑒 𝑎𝑠 = 𝑓 𝑎 𝑏 đ‘€â„Žđ‘’đ‘Ÿđ‘’ 𝑎 = ℎ𝑒𝑎𝑑 𝑎𝑠 𝑏 = 𝑓𝑜𝑙𝑑𝑟 𝑓 𝑒 (𝑡𝑎𝑖𝑙 𝑎𝑠) 𝑓𝑜𝑙𝑑𝑟 = 𝑒; 𝑓𝑜𝑙𝑑𝑟 đ‘„ â§ș 𝑠 = 𝑓(đ‘„, 𝑓𝑜𝑙𝑑𝑟(𝑠)) 𝑓𝑜𝑙𝑑𝑙 = 𝑒; 𝑓𝑜𝑙𝑑𝑙 𝑠 â§ș [đ‘„] = 𝑓(𝑓𝑜𝑙𝑑𝑙 𝑠 , đ‘„) To help us understand the above two definitions, let’s first express them in Haskell, pretending that we are able to use 𝑠 â§ș [đ‘„] and đ‘„ â§ș 𝑠 in a pattern match. Now let’s replace 𝑠 â§ș [đ‘„] and đ‘„ â§ș 𝑠 with as, and get the functions to extract the 𝑠 and the đ‘„ using the ℎ𝑒𝑎𝑑, 𝑡𝑎𝑖𝑙, 𝑙𝑎𝑠𝑡 and 𝑖𝑛𝑖𝑡. Let’s also add type signatures And now let’s make it more obvious that what each fold is doing is taking an 𝑎 from the list, folding the rest of the list into a 𝑏, and then returning the result of calling 𝑓 with 𝑎 and 𝑏.
  • 6. 𝑓𝑜𝑙𝑑𝑙 :: (𝑏 → 𝑎 → 𝑏) → 𝑏 →[𝑎] → 𝑏 𝑓𝑜𝑙𝑑𝑙 𝑓 𝑒 = 𝑒 𝑓𝑜𝑙𝑑𝑙 𝑓 𝑒 𝑎𝑠 = 𝑓 𝑏 𝑎 đ‘€â„Žđ‘’đ‘Ÿđ‘’ 𝑎 = 𝑙𝑎𝑠𝑡 𝑎𝑠 𝑏 = 𝑓𝑜𝑙𝑑𝑙 𝑓 𝑒 (𝑖𝑛𝑖𝑡 𝑎𝑠) 𝑓𝑜𝑙𝑑𝑟 :: (𝑎 → 𝑏 → 𝑏) → 𝑏 →[𝑎] → 𝑏 𝑓𝑜𝑙𝑑𝑟 𝑓 𝑒 = 𝑒 𝑓𝑜𝑙𝑑𝑟 𝑓 𝑒 𝑎𝑠 = 𝑓 𝑎 𝑏 đ‘€â„Žđ‘’đ‘Ÿđ‘’ 𝑎 = ℎ𝑒𝑎𝑑 𝑎𝑠 𝑏 = 𝑓𝑜𝑙𝑑𝑟 𝑓 𝑒 (𝑡𝑎𝑖𝑙 𝑎𝑠) Since the above two functions are very similar, let’s extract their common logic into a fold function. Let’s call the function that is used to extract an element from the list 𝑡𝑎𝑘𝑒, and the function that is used to extract the rest of the list 𝑟𝑒𝑠𝑡. 𝑓𝑜𝑙𝑑 :: (𝑏 → 𝑎 → 𝑏) → ([𝑎] → 𝑎) → ([𝑎] → [𝑎]) → 𝑏 → [𝑎] → 𝑏 𝑓𝑜𝑙𝑑 𝑓 𝑡𝑎𝑘𝑒 𝑟𝑒𝑠𝑡 𝑒 = 𝑒 𝑓𝑜𝑙𝑑 𝑓 𝑡𝑎𝑘𝑒 𝑟𝑒𝑠𝑡 𝑒 𝑎𝑠 = 𝑓 𝑏 𝑎 đ‘€â„Žđ‘’đ‘Ÿđ‘’ 𝑎 = 𝑡𝑎𝑘𝑒 𝑎𝑠 𝑏 = 𝑓𝑜𝑙𝑑 𝑓 𝑡𝑎𝑘𝑒 𝑟𝑒𝑠𝑡 𝑒 (𝑟𝑒𝑠𝑡 𝑎𝑠) We can now define left and right folds in terms of 𝑓𝑜𝑙𝑑. 𝑓𝑜𝑙𝑑𝑙 :: (𝑏 → 𝑎 → 𝑏) → 𝑏 →[𝑎] → 𝑏 𝑓𝑜𝑙𝑑𝑙 𝑓 = 𝑓𝑜𝑙𝑑 𝑓 𝑙𝑎𝑠𝑡 𝑖𝑛𝑖𝑡 𝑓𝑜𝑙𝑑𝑟 :: (𝑎 → 𝑏 → 𝑏) → 𝑏 →[𝑎] → 𝑏 𝑓𝑜𝑙𝑑𝑟 𝑓 = 𝑓𝑜𝑙𝑑 𝑓𝑙𝑖𝑝 𝑓 ℎ𝑒𝑎𝑑 𝑡𝑎𝑖𝑙 𝑓𝑙𝑖𝑝 :: (𝑎 → 𝑏 → 𝑐) → 𝑏 → 𝑎 → 𝑐 𝑓𝑙𝑖𝑝 𝑓 đ‘„ 𝑩 = 𝑓 𝑩 đ‘„ The slightly perplexing thing is that while a left fold applies 𝑓 to list elements starting with the ℎ𝑒𝑎𝑑 of the list and proceeding from left to right, the above 𝑓𝑜𝑙𝑑𝑙 function achieves that by navigating through list elements from right to left. Third duality theorem. For all finite lists đ‘„đ‘ , 𝑓𝑜𝑙𝑑𝑟 𝑓 𝑒 đ‘„đ‘  = 𝑓𝑜𝑙𝑑𝑙 𝑓𝑙𝑖𝑝 𝑓 𝑒 (𝑟𝑒𝑣𝑒𝑟𝑠𝑒 đ‘„đ‘ ) 𝒘𝒉𝒆𝒓𝒆 𝑓𝑙𝑖𝑝 𝑓 đ‘„ 𝑩 = 𝑓 𝑩 đ‘„ The fact that we can define 𝑓𝑜𝑙𝑑𝑙 and 𝑓𝑜𝑙𝑑𝑟 in terms of 𝑓𝑜𝑙𝑑, as we do above, seems related to the third duality theorem of folding. Instead of our 𝑓𝑜𝑙𝑑𝑙 function being passed the reverse of the list passed to 𝑓𝑜𝑙𝑑𝑟, it processes the list with 𝑙𝑎𝑠𝑡 and 𝑖𝑛𝑖𝑡, rather than with ℎ𝑒𝑎𝑑 and 𝑡𝑎𝑖𝑙. @philip_schwarz
  • 7. To summarise what we did to help understand SOFP’s mathematical definitions of left and right fold: we turned them into code and expressed them in terms of a common function 𝑓𝑜𝑙𝑑 that uses a 𝑡𝑎𝑘𝑒 function to extract an element from the list being folded, and a 𝑟𝑒𝑠𝑡 function to extract the rest of the list. 𝑓𝑜𝑙𝑑 :: (𝑏 → 𝑎 → 𝑏) → ([𝑎] → 𝑎) → ([𝑎] → [𝑎]) → 𝑏 → [𝑎] → 𝑏 𝑓𝑜𝑙𝑑 𝑓 𝑡𝑎𝑘𝑒 𝑟𝑒𝑠𝑡 𝑒 = 𝑒 𝑓𝑜𝑙𝑑 𝑓 𝑡𝑎𝑘𝑒 𝑟𝑒𝑠𝑡 𝑒 𝑎𝑠 = 𝑓 𝑏 𝑎 đ‘€â„Žđ‘’đ‘Ÿđ‘’ 𝑎 = 𝑡𝑎𝑘𝑒 𝑎𝑠 𝑏 = 𝑓𝑜𝑙𝑑 𝑓 𝑡𝑎𝑘𝑒 𝑟𝑒𝑠𝑡 𝑒 (𝑟𝑒𝑠𝑡 𝑎𝑠) 𝑓𝑜𝑙𝑑𝑙 :: (𝑏 → 𝑎 → 𝑏) → 𝑏 →[𝑎] → 𝑏 𝑓𝑜𝑙𝑑𝑙 𝑓 = 𝑓𝑜𝑙𝑑 𝑓 𝑙𝑎𝑠𝑡 𝑖𝑛𝑖𝑡 𝑓𝑜𝑙𝑑𝑟 :: (𝑎 → 𝑏 → 𝑏) → 𝑏 →[𝑎] → 𝑏 𝑓𝑜𝑙𝑑𝑟 𝑓 = 𝑓𝑜𝑙𝑑 𝑓𝑙𝑖𝑝 𝑓 ℎ𝑒𝑎𝑑 𝑡𝑎𝑖𝑙 𝑓𝑜𝑙𝑑𝑟 = 𝑒; 𝑓𝑜𝑙𝑑𝑟 đ‘„ â§ș 𝑠 = 𝑓(đ‘„, 𝑓𝑜𝑙𝑑𝑟(𝑠)) 𝑓𝑜𝑙𝑑𝑙 = 𝑒; 𝑓𝑜𝑙𝑑𝑙 𝑠 â§ș [đ‘„] = 𝑓(𝑓𝑜𝑙𝑑𝑙 𝑠 , đ‘„) 𝑓𝑜𝑙𝑑𝑟 = 𝑒; 𝑓𝑜𝑙𝑑𝑟 𝑎𝑠 = 𝑓(ℎ𝑒𝑎𝑑(𝑎𝑠), 𝑓𝑜𝑙𝑑𝑟(𝑡𝑎𝑖𝑙(𝑎𝑠))) 𝑓𝑜𝑙𝑑𝑙 = 𝑒; 𝑓𝑜𝑙𝑑𝑙 𝑎𝑠 = 𝑓(𝑓𝑜𝑙𝑑𝑙 𝑖𝑛𝑖𝑡(𝑎𝑠) , 𝑙𝑎𝑠𝑡(𝑎𝑠)) Let’s feed one aspect of the above back into Sergei’s definitions. Let’s temporarily rewrite them by replacing 𝑠 â§ș [đ‘„] and đ‘„ â§ș 𝑠 with as, and getting the definitions to extract the 𝑠 and the đ‘„ using the functions ℎ𝑒𝑎𝑑, 𝑡𝑎𝑖𝑙, 𝑙𝑎𝑠𝑡 and 𝑖𝑛𝑖𝑡. Notice how the flipping of 𝑓 done by the 𝑓𝑜𝑙𝑑𝑟 function above, is reflected, in the 𝑓𝑜𝑙𝑑𝑟 function below, in the fact that its 𝑓 takes an 𝑎 and a 𝑏, rather than a 𝑏 and an 𝑎.
  • 8. Another thing we can do to understand SOFP’s definitions of left and right folds, is to see how they work when applied to a sample list, e.g. [đ‘„0, đ‘„1, đ‘„2, đ‘„3], when we run them manually. In the next slide we first do this for the following definitions 𝑓𝑜𝑙𝑑𝑙 = 𝑒; 𝑓𝑜𝑙𝑑𝑙 𝑠 â§ș [đ‘„] = 𝑓(𝑓𝑜𝑙𝑑𝑙 𝑠 , đ‘„) 𝑓𝑜𝑙𝑑𝑟 = 𝑒; 𝑓𝑜𝑙𝑑𝑟 đ‘„ â§ș 𝑠 = 𝑓(đ‘„, 𝑓𝑜𝑙𝑑𝑟(𝑠)) 𝑓𝑜𝑙𝑑𝑙 ∷ đ›œ → đ›Œ → đ›œ → đ›œ → đ›Œ → đ›œ 𝑓𝑜𝑙𝑑𝑙 𝑓 𝑒 = 𝑒 𝑓𝑜𝑙𝑑𝑙 𝑓 𝑒 đ‘„ ∶ đ‘„đ‘  = 𝑓𝑜𝑙𝑑𝑙 𝑓 𝑓 𝑒 đ‘„ đ‘„đ‘  𝑓𝑜𝑙𝑑𝑟 ∷ đ›Œ → đ›œ → đ›œ → đ›œ → đ›Œ → đ›œ 𝑓𝑜𝑙𝑑𝑟 𝑓 𝑒 = 𝑒 𝑓𝑜𝑙𝑑𝑟 𝑓 𝑒 đ‘„ ∶ đ‘„đ‘  = 𝑓 đ‘„ 𝑓𝑜𝑙𝑑𝑟 𝑓 𝑒 đ‘„đ‘  In the slide after that, we do it for SOFP’s definitions.
  • 9. ∶ / đ‘„0 ∶ / đ‘„1 ∶ / đ‘„2 ∶ / đ‘„3 𝑓 / 𝑓 đ‘„3 / 𝑓 đ‘„2 / 𝑓 đ‘„1 / 𝑒 đ‘„0 𝑓 / đ‘„0 𝑓 / đ‘„1 𝑓 / đ‘„2 𝑓 / đ‘„3 𝑒 đ‘„0: (đ‘„1: đ‘„2: đ‘„3: ) 𝑓 𝑓 𝑓 𝑓 𝑒 đ‘„0 đ‘„1 đ‘„2 đ‘„3 var 𝑎𝑐𝑐 = 𝑒 foreach(đ‘„ in đ‘„s) 𝑎𝑐𝑐 = 𝑓(𝑎𝑐𝑐, đ‘„) return 𝑎𝑐𝑐 𝑓𝑜𝑙𝑑𝑟 𝑓 𝑒 đ‘„đ‘  𝑓𝑜𝑙𝑑𝑙 𝑓 𝑒 đ‘„đ‘  đ‘„đ‘  = [đ‘„0, đ‘„1, đ‘„2, đ‘„3] 𝑓𝑜𝑙𝑑𝑟 ∷ đ›Œ → đ›œ → đ›œ → đ›œ → đ›Œ → đ›œ 𝑓𝑜𝑙𝑑𝑟 𝑓 𝑒 = 𝑒 𝑓𝑜𝑙𝑑𝑟 𝑓 𝑒 đ‘„: đ‘„đ‘  = 𝑓 đ‘„ 𝑓𝑜𝑙𝑑𝑟 𝑓 𝑒 đ‘„đ‘  𝑓𝑜𝑙𝑑𝑙 ∷ đ›œ → đ›Œ → đ›œ → đ›œ → đ›Œ → đ›œ 𝑓𝑜𝑙𝑑𝑙 𝑓 𝑒 = 𝑒 𝑓𝑜𝑙𝑑𝑙 𝑓 𝑒 đ‘„: đ‘„đ‘  = 𝑓𝑜𝑙𝑑𝑙 𝑓 𝑓 𝑒 đ‘„ đ‘„đ‘  𝑟𝑒𝑝𝑙𝑎𝑐𝑒: ∶ đ‘€đ‘–đ‘Ąâ„Ž 𝑓 đ‘€đ‘–đ‘Ąâ„Ž 𝑒 𝑓𝑜𝑙𝑑𝑟 𝑓 𝑒 [đ‘„0, đ‘„1, đ‘„2, đ‘„3] 𝑓 đ‘„0 𝑓𝑜𝑙𝑑𝑟 𝑓 𝑒 [đ‘„1, đ‘„2, đ‘„3] 𝑓 đ‘„0 (𝑓 đ‘„1 (𝑓𝑜𝑙𝑑𝑟 𝑓 𝑒 [đ‘„2, đ‘„3])) 𝑓 đ‘„0 (𝑓 đ‘„1 (𝑓 đ‘„2 (𝑓𝑜𝑙𝑑𝑟 𝑓 𝑒 [đ‘„3]))) 𝑓 đ‘„0 (𝑓 đ‘„1 (𝑓 đ‘„2 (𝑓 đ‘„3 (𝑓𝑜𝑙𝑑𝑟 𝑓 𝑒 [ ])))) 𝑓 đ‘„0 (𝑓 đ‘„1 (𝑓 đ‘„2 (𝑓 đ‘„3 𝑒))) 𝑓 đ‘„0 (𝑓 đ‘„1 (𝑓 đ‘„2 (𝑓 đ‘„3 𝑒))) 𝑓𝑜𝑙𝑑𝑙 𝑓 𝑒 [đ‘„0, đ‘„1, đ‘„2, đ‘„3] 𝑓𝑜𝑙𝑑𝑙 𝑓 𝑓 𝑒 đ‘„0 [đ‘„1, đ‘„2, đ‘„3] 𝑓𝑜𝑙𝑑𝑙 𝑓 𝑓 𝑓 𝑒 đ‘„0 đ‘„1 [đ‘„2, đ‘„3] 𝑓𝑜𝑙𝑑𝑙 𝑓 𝑓 𝑓 𝑓 𝑒 đ‘„0 đ‘„1 đ‘„2 [đ‘„3] 𝑓𝑜𝑙𝑑𝑙 𝑓 𝑓 𝑓 𝑓 𝑓 𝑒 đ‘„0 đ‘„1 đ‘„2 đ‘„3 [ ] 𝑓 𝑓 𝑓 𝑓 𝑒 đ‘„0 đ‘„1 đ‘„2 đ‘„3
  • 10. ∶ / đ‘„0 ∶ / đ‘„1 ∶ / đ‘„2 ∶ / đ‘„3 𝑓 / 𝑓 đ‘„3 / 𝑓 đ‘„2 / 𝑓 đ‘„1 / 𝑒 đ‘„0 𝑓 / đ‘„0 𝑓 / đ‘„1 𝑓 / đ‘„2 𝑓 / đ‘„3 𝑒 đ‘„0: (đ‘„1: đ‘„2: đ‘„3: ) 𝑓(𝑓 𝑓 𝑓 𝑒, đ‘„0 , đ‘„1 , đ‘„2 , đ‘„3) 𝑓𝑜𝑙𝑑𝑟 đ‘„đ‘  𝑓𝑜𝑙𝑑𝑙 đ‘„đ‘  đ‘„đ‘  = [đ‘„0, đ‘„1, đ‘„2, đ‘„3] 𝑓(đ‘„0, 𝑓(đ‘„1, 𝑓(đ‘„2, 𝑓(đ‘„3, 𝑒)))) 𝑓𝑜𝑙𝑑𝑙 = 𝑒; 𝑓𝑜𝑙𝑑𝑙 𝑠 â§ș [đ‘„] = 𝑓(𝑓𝑜𝑙𝑑𝑙 𝑠 , đ‘„) 𝑓𝑜𝑙𝑑𝑟 = 𝑒; 𝑓𝑜𝑙𝑑𝑟 đ‘„ â§ș 𝑠 = 𝑓(đ‘„, 𝑓𝑜𝑙𝑑𝑟(𝑠)) 𝑓𝑜𝑙𝑑𝑙 đ‘„0, đ‘„1, đ‘„2, đ‘„3 , 𝑓 𝑓𝑜𝑙𝑑𝑙 đ‘„0, đ‘„1, đ‘„2 , đ‘„3 𝑓(𝑓(𝑓𝑜𝑙𝑑𝑙 [đ‘„0, đ‘„1] , đ‘„2), đ‘„3) 𝑓 𝑓 𝑓 𝑓𝑜𝑙𝑑𝑙 đ‘„0 , đ‘„1 , đ‘„2 , đ‘„3 𝑓 𝑓 𝑓 𝑓 𝑓𝑜𝑙𝑑𝑙 [ ] , đ‘„0 , đ‘„1 , đ‘„2 , đ‘„3 𝑓 𝑓 𝑓 𝑓 𝑒, đ‘„0 , đ‘„1 , đ‘„2 , đ‘„3 𝑓𝑜𝑙𝑑𝑟([đ‘„0, đ‘„1, đ‘„2, đ‘„3]) 𝑓(đ‘„0, 𝑓𝑜𝑙𝑑𝑟([đ‘„1, đ‘„2, đ‘„3])) 𝑓(đ‘„0, 𝑓(đ‘„1, 𝑓𝑜𝑙𝑑𝑟([đ‘„2, đ‘„3]))) 𝑓(đ‘„0, 𝑓(đ‘„1, 𝑓(đ‘„2, 𝑓𝑜𝑙𝑑𝑟([đ‘„3])))) 𝑓(đ‘„0, 𝑓(đ‘„1, 𝑓(đ‘„2, 𝑓(đ‘„3, 𝑓𝑜𝑙𝑑𝑟([]))))) 𝑓(đ‘„0, 𝑓(đ‘„1, 𝑓(đ‘„2, 𝑓(đ‘„3, 𝑒))))
  • 11. 𝑓𝑜𝑙𝑑𝑙 ∷ đ›œ → đ›Œ → đ›œ → đ›œ → đ›Œ → đ›œ 𝑓𝑜𝑙𝑑𝑙 𝑓 𝑒 = 𝑒 𝑓𝑜𝑙𝑑𝑙 𝑓 𝑒 đ‘„: đ‘„đ‘  = 𝑓𝑜𝑙𝑑𝑙 𝑓 𝑓 𝑒 đ‘„ đ‘„đ‘  𝑓𝑜𝑙𝑑𝑙 = 𝑒; 𝑓𝑜𝑙𝑑𝑙 𝑠 â§ș [đ‘„] = 𝑓(𝑓𝑜𝑙𝑑𝑙 𝑠 , đ‘„) ∶ / đ‘„0 ∶ / đ‘„1 ∶ / đ‘„2 ∶ / đ‘„3 đ‘„0: (đ‘„1: đ‘„2: đ‘„3: ) đ‘„đ‘  = [đ‘„0, đ‘„1, đ‘„2, đ‘„3] 𝑓 / 𝑓 đ‘„3 / 𝑓 đ‘„2 / 𝑓 đ‘„1 / 𝑒 đ‘„0 𝑓𝑜𝑙𝑑𝑙 𝑓 𝑒 [đ‘„0, đ‘„1, đ‘„2, đ‘„3] 𝑓𝑜𝑙𝑑𝑙 𝑓 𝑓 𝑒 đ‘„0 [đ‘„1, đ‘„2, đ‘„3] 𝑓𝑜𝑙𝑑𝑙 𝑓 𝑓 𝑓 𝑒 đ‘„0 đ‘„1 [đ‘„2, đ‘„3] 𝑓𝑜𝑙𝑑𝑙 𝑓 𝑓 𝑓 𝑓 𝑒 đ‘„0 đ‘„1 đ‘„2 [đ‘„3] 𝑓𝑜𝑙𝑑𝑙 𝑓 𝑓 𝑓 𝑓 𝑓 𝑒 đ‘„0 đ‘„1 đ‘„2 đ‘„3 [ ] 𝑓 𝑓 𝑓 𝑓 𝑒 đ‘„0 đ‘„1 đ‘„2 đ‘„3 𝑓𝑜𝑙𝑑𝑙 đ‘„0, đ‘„1, đ‘„2, đ‘„3 , 𝑓 𝑓𝑜𝑙𝑑𝑙 đ‘„0, đ‘„1, đ‘„2 , đ‘„3 𝑓(𝑓(𝑓𝑜𝑙𝑑𝑙 [đ‘„0, đ‘„1] , đ‘„2), đ‘„3) 𝑓 𝑓 𝑓 𝑓𝑜𝑙𝑑𝑙 đ‘„0 , đ‘„1 , đ‘„2 , đ‘„3 𝑓 𝑓 𝑓 𝑓 𝑓𝑜𝑙𝑑𝑙 [ ] , đ‘„0 , đ‘„1 , đ‘„2 , đ‘„3 𝑓 𝑓 𝑓 𝑓 𝑒, đ‘„0 , đ‘„1 , đ‘„2 , đ‘„3 Now let’s compare the results for both definitions of 𝑓𝑜𝑙𝑑𝑙. The results are the same. @philip_schwarz
  • 12. 𝑓 / đ‘„0 𝑓 / đ‘„1 𝑓 / đ‘„2 𝑓 / đ‘„3 𝑒 𝑓𝑜𝑙𝑑𝑟 ∷ đ›Œ → đ›œ → đ›œ → đ›œ → đ›Œ → đ›œ 𝑓𝑜𝑙𝑑𝑟 𝑓 𝑒 = 𝑒 𝑓𝑜𝑙𝑑𝑟 𝑓 𝑒 đ‘„: đ‘„đ‘  = 𝑓 đ‘„ 𝑓𝑜𝑙𝑑𝑟 𝑓 𝑒 đ‘„đ‘  𝑓𝑜𝑙𝑑𝑟 𝑓 𝑒 [đ‘„0, đ‘„1, đ‘„2, đ‘„3] 𝑓 đ‘„0 𝑓𝑜𝑙𝑑𝑟 𝑓 𝑒 [đ‘„1, đ‘„2, đ‘„3] 𝑓 đ‘„0 (𝑓 đ‘„1 (𝑓𝑜𝑙𝑑𝑟 𝑓 𝑒 [đ‘„2, đ‘„3])) 𝑓 đ‘„0 (𝑓 đ‘„1 (𝑓 đ‘„2 (𝑓𝑜𝑙𝑑𝑟 𝑓 𝑒 [đ‘„3]))) 𝑓 đ‘„0 (𝑓 đ‘„1 (𝑓 đ‘„2 (𝑓 đ‘„3 (𝑓𝑜𝑙𝑑𝑟 𝑓 𝑒 [ ])))) 𝑓 đ‘„0 (𝑓 đ‘„1 (𝑓 đ‘„2 (𝑓 đ‘„3 𝑒))) 𝑓𝑜𝑙𝑑𝑟 = 𝑒; 𝑓𝑜𝑙𝑑𝑟 đ‘„ â§ș 𝑠 = 𝑓(đ‘„, 𝑓𝑜𝑙𝑑𝑟(𝑠)) 𝑓𝑜𝑙𝑑𝑟([đ‘„0, đ‘„1, đ‘„2, đ‘„3]) 𝑓(đ‘„0, 𝑓𝑜𝑙𝑑𝑟([đ‘„1, đ‘„2, đ‘„3])) 𝑓(đ‘„0, 𝑓(đ‘„1, 𝑓𝑜𝑙𝑑𝑟([đ‘„2, đ‘„3]))) 𝑓(đ‘„0, 𝑓(đ‘„1, 𝑓(đ‘„2, 𝑓𝑜𝑙𝑑𝑟([đ‘„3])))) 𝑓(đ‘„0, 𝑓(đ‘„1, 𝑓(đ‘„2, 𝑓(đ‘„3, 𝑓𝑜𝑙𝑑𝑟([]))))) 𝑓(đ‘„0, 𝑓(đ‘„1, 𝑓(đ‘„2, 𝑓(đ‘„3, 𝑒)))) ∶ / đ‘„0 ∶ / đ‘„1 ∶ / đ‘„2 ∶ / đ‘„3 đ‘„0: (đ‘„1: đ‘„2: đ‘„3: ) đ‘„đ‘  = [đ‘„0, đ‘„1, đ‘„2, đ‘„3] And now let’s compare the results for both definitions of 𝑓𝑜𝑙𝑑𝑟. Again, the results are the same.
  • 13. The way 𝑓𝑜𝑙𝑑𝑟 applies 𝑓 to đ‘„, 𝑩, z is by associating to the right. The way 𝑓𝑜𝑙𝑑𝑙 does it is by associating to the right. Thinking of 𝑓 as an infix operator can help to grasp this. 𝑓𝑜𝑙𝑑𝑟 𝑓(đ‘„, 𝑓(𝑩, 𝑧)) đ‘„ ⊕ 𝑩 ⊕ 𝑧 𝑓𝑜𝑙𝑑𝑙 𝑓 𝑓 đ‘„, 𝑩 , 𝑧 (đ‘„ ⊕ 𝑩) ⊕ 𝑧 𝑓𝑜𝑙𝑑𝑟 ⊕ 𝑒 đ‘„, 𝑩, z = đ‘„ ⊕ (𝑩 ⊕ 𝑧 ⊕ 𝑒 ) 𝑓𝑜𝑙𝑑𝑟 (+) 0 [1,2,3] = 1 + (2 + (3 + 0)) = 6 𝑓𝑜𝑙𝑑𝑙 (+) 0 [1,2,3] = ((0 + 1) + 2) + 3 = 6 𝑓𝑜𝑙𝑑𝑟 − 0 1,2,3 = 1 − (2 − (3 − 0)) = 2 𝑓𝑜𝑙𝑑𝑙 − 0 1,2,3 = ((0 − 1) − 2) − 3 = −6 ⊕ / đ‘„ ⊕ / 𝑩 ⊕ / 𝑧 𝑒 ⊕ / ⊕ 𝑧 / ⊕ 𝑩 / 𝑒 đ‘„ 𝑓𝑜𝑙𝑑𝑙 ⊕ 𝑒 đ‘„, 𝑩, 𝑧 = ((𝑒 ⊕ đ‘„) ⊕ 𝑩) ⊕ 𝑧 Addition is associative, so associating to the left and to the right yields the same result. But subtraction isn’t associative, so associating to the left yields a result that is different to the one yielded when associating to the right.
  • 14. We have seen that Sergei’s definitions of left and right folds make perfect sense. Not only are they simple and succinct, they are also free of implementation details like tail recursion. That’s all. I hope you found this slide deck useful. By the way, in case you are interested, see below for a whole series of slide decks dedicated to folding.