Slide 1

Slide 1 text

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/

Slide 2

Slide 2 text

π‘“π‘œπ‘™π‘‘π‘™ ∷ 𝛽 β†’ 𝛼 β†’ 𝛽 β†’ 𝛽 β†’ 𝛼 β†’ 𝛽 π‘“π‘œπ‘™π‘‘π‘™ 𝑓 𝑒 = 𝑒 π‘“π‘œπ‘™π‘‘π‘™ 𝑓 𝑒 π‘₯ ∢ π‘₯𝑠 = π‘“π‘œπ‘™π‘‘π‘™ 𝑓 𝑓 𝑒 π‘₯ π‘₯𝑠 π‘“π‘œπ‘™π‘‘π‘Ÿ ∷ 𝛼 β†’ 𝛽 β†’ 𝛽 β†’ 𝛽 β†’ 𝛼 β†’ 𝛽 π‘“π‘œπ‘™π‘‘π‘Ÿ 𝑓 𝑒 = 𝑒 π‘“π‘œπ‘™π‘‘π‘Ÿ 𝑓 𝑒 π‘₯ ∢ π‘₯𝑠 = 𝑓 π‘₯ π‘“π‘œπ‘™π‘‘π‘Ÿ 𝑓 𝑒 π‘₯𝑠 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

Slide 3

Slide 3 text

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.

Slide 4

Slide 4 text

𝑓 = 𝑏; 𝑓 π‘₯ β§Ί 𝑠 = 𝑔(π‘₯, 𝑓(𝑠)) 𝑓 = 𝑏; 𝑓 𝑠 β§Ί [π‘₯] = 𝑔(𝑓 𝑠 , π‘₯) 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.” 𝑓 β†’ π‘“π‘œπ‘™π‘‘π‘™ 𝑔 β†’ 𝑓 𝑏 β†’ 𝑒 π‘“π‘œπ‘™π‘‘π‘Ÿ = 𝑒; π‘“π‘œπ‘™π‘‘π‘Ÿ π‘₯ β§Ί 𝑠 = 𝑓(π‘₯, π‘“π‘œπ‘™π‘‘π‘Ÿ(𝑠)) π‘“π‘œπ‘™π‘‘π‘™ = 𝑒; π‘“π‘œπ‘™π‘‘π‘™ 𝑠 β§Ί [π‘₯] = 𝑓(π‘“π‘œπ‘™π‘‘π‘™ 𝑠 , π‘₯) 𝑓 β†’ π‘“π‘œπ‘™π‘‘π‘Ÿ 𝑔 β†’ 𝑓 𝑏 β†’ 𝑒 π‘“π‘œπ‘™π‘‘π‘™ ∷ 𝛽 β†’ 𝛼 β†’ 𝛽 β†’ 𝛽 β†’ 𝛼 β†’ 𝛽 π‘“π‘œπ‘™π‘‘π‘™ 𝑓 𝑒 = 𝑒 π‘“π‘œπ‘™π‘‘π‘™ 𝑓 𝑒 π‘₯ ∢ π‘₯𝑠 = π‘“π‘œπ‘™π‘‘π‘™ 𝑓 𝑓 𝑒 π‘₯ π‘₯𝑠 π‘“π‘œπ‘™π‘‘π‘Ÿ ∷ 𝛼 β†’ 𝛽 β†’ 𝛽 β†’ 𝛽 β†’ 𝛼 β†’ 𝛽 π‘“π‘œπ‘™π‘‘π‘Ÿ 𝑓 𝑒 = 𝑒 π‘“π‘œπ‘™π‘‘π‘Ÿ 𝑓 𝑒 π‘₯ ∢ π‘₯𝑠 = 𝑓 π‘₯ π‘“π‘œπ‘™π‘‘π‘Ÿ 𝑓 𝑒 π‘₯𝑠 𝑓 = 𝑏; 𝑓 π‘₯ β§Ί 𝑠 = 𝑔(π‘₯, 𝑓(𝑠)) 𝑓 = 𝑏; 𝑓 𝑠 β§Ί [π‘₯] = 𝑔(𝑓 𝑠 , π‘₯)

Slide 5

Slide 5 text

π‘“π‘œπ‘™π‘‘π‘Ÿ 𝑓 𝑒 [ ] = 𝑒 π‘“π‘œπ‘™π‘‘π‘Ÿ 𝑓 𝑒 π‘₯ β§Ί 𝑠 = 𝑓 π‘₯ (π‘“π‘œπ‘™π‘‘π‘Ÿ 𝑓 𝑒 𝑠) π‘“π‘œπ‘™π‘‘π‘™ 𝑓 𝑒 = 𝑒 π‘“π‘œπ‘™π‘‘π‘™ 𝑓 𝑒 𝑠 β§Ί [π‘₯] = 𝑓 π‘“π‘œπ‘™π‘‘π‘™ 𝑓 𝑒 𝑠 π‘₯ π‘“π‘œπ‘™π‘‘π‘™ :: (𝑏 β†’ π‘Ž β†’ 𝑏) β†’ 𝑏 β†’[π‘Ž] β†’ 𝑏 π‘“π‘œπ‘™π‘‘π‘™ 𝑓 𝑒 = 𝑒 π‘“π‘œπ‘™π‘‘π‘™ 𝑓 𝑒 π‘Žπ‘  = 𝑓 π‘“π‘œπ‘™π‘‘π‘™ 𝑓 𝑒 (𝑖𝑛𝑖𝑑 π‘Žπ‘ ) (π‘™π‘Žπ‘ π‘‘ π‘Žπ‘ ) π‘“π‘œπ‘™π‘‘π‘Ÿ :: (π‘Ž β†’ 𝑏 β†’ 𝑏) β†’ 𝑏 β†’[π‘Ž] β†’ 𝑏 π‘“π‘œπ‘™π‘‘π‘Ÿ 𝑓 𝑒 = 𝑒 π‘“π‘œπ‘™π‘‘π‘Ÿ 𝑓 𝑒 π‘Žπ‘  = 𝑓 β„Žπ‘’π‘Žπ‘‘ π‘Žπ‘  π‘“π‘œπ‘™π‘‘π‘Ÿ 𝑓 𝑒 (π‘‘π‘Žπ‘–π‘™ π‘Žπ‘ ) π‘“π‘œπ‘™π‘‘π‘™ :: (𝑏 β†’ π‘Ž β†’ 𝑏) β†’ 𝑏 β†’[π‘Ž] β†’ 𝑏 π‘“π‘œπ‘™π‘‘π‘™ 𝑓 𝑒 = 𝑒 π‘“π‘œπ‘™π‘‘π‘™ 𝑓 𝑒 π‘Žπ‘  = 𝑓 𝑏 π‘Ž π‘€β„Žπ‘’π‘Ÿπ‘’ π‘Ž = π‘™π‘Žπ‘ π‘‘ π‘Žπ‘  𝑏 = π‘“π‘œπ‘™π‘‘π‘™ 𝑓 𝑒 (𝑖𝑛𝑖𝑑 π‘Žπ‘ ) π‘“π‘œπ‘™π‘‘π‘Ÿ :: (π‘Ž β†’ 𝑏 β†’ 𝑏) β†’ 𝑏 β†’[π‘Ž] β†’ 𝑏 π‘“π‘œπ‘™π‘‘π‘Ÿ 𝑓 𝑒 = 𝑒 π‘“π‘œπ‘™π‘‘π‘Ÿ 𝑓 𝑒 π‘Žπ‘  = 𝑓 π‘Ž 𝑏 π‘€β„Žπ‘’π‘Ÿπ‘’ π‘Ž = β„Žπ‘’π‘Žπ‘‘ π‘Žπ‘  𝑏 = π‘“π‘œπ‘™π‘‘π‘Ÿ 𝑓 𝑒 (π‘‘π‘Žπ‘–π‘™ π‘Žπ‘ ) π‘“π‘œπ‘™π‘‘π‘Ÿ = 𝑒; π‘“π‘œπ‘™π‘‘π‘Ÿ π‘₯ β§Ί 𝑠 = 𝑓(π‘₯, π‘“π‘œπ‘™π‘‘π‘Ÿ(𝑠)) π‘“π‘œπ‘™π‘‘π‘™ = 𝑒; π‘“π‘œπ‘™π‘‘π‘™ 𝑠 β§Ί [π‘₯] = 𝑓(π‘“π‘œπ‘™π‘‘π‘™ 𝑠 , π‘₯) 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 𝑏.

Slide 6

Slide 6 text

π‘“π‘œπ‘™π‘‘π‘™ :: (𝑏 β†’ π‘Ž β†’ 𝑏) β†’ 𝑏 β†’[π‘Ž] β†’ 𝑏 π‘“π‘œπ‘™π‘‘π‘™ 𝑓 𝑒 = 𝑒 π‘“π‘œπ‘™π‘‘π‘™ 𝑓 𝑒 π‘Žπ‘  = 𝑓 𝑏 π‘Ž π‘€β„Žπ‘’π‘Ÿπ‘’ π‘Ž = π‘™π‘Žπ‘ π‘‘ π‘Žπ‘  𝑏 = π‘“π‘œπ‘™π‘‘π‘™ 𝑓 𝑒 (𝑖𝑛𝑖𝑑 π‘Žπ‘ ) π‘“π‘œπ‘™π‘‘π‘Ÿ :: (π‘Ž β†’ 𝑏 β†’ 𝑏) β†’ 𝑏 β†’[π‘Ž] β†’ 𝑏 π‘“π‘œπ‘™π‘‘π‘Ÿ 𝑓 𝑒 = 𝑒 π‘“π‘œπ‘™π‘‘π‘Ÿ 𝑓 𝑒 π‘Žπ‘  = 𝑓 π‘Ž 𝑏 π‘€β„Žπ‘’π‘Ÿπ‘’ π‘Ž = β„Žπ‘’π‘Žπ‘‘ π‘Žπ‘  𝑏 = π‘“π‘œπ‘™π‘‘π‘Ÿ 𝑓 𝑒 (π‘‘π‘Žπ‘–π‘™ π‘Žπ‘ ) 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

Slide 7

Slide 7 text

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 π‘Ž.

Slide 8

Slide 8 text

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.

Slide 9

Slide 9 text

∢ / \ π‘₯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

Slide 10

Slide 10 text

∢ / \ π‘₯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 , 𝑒))))

Slide 11

Slide 11 text

π‘“π‘œπ‘™π‘‘π‘™ ∷ 𝛽 β†’ 𝛼 β†’ 𝛽 β†’ 𝛽 β†’ 𝛼 β†’ 𝛽 π‘“π‘œπ‘™π‘‘π‘™ 𝑓 𝑒 = 𝑒 π‘“π‘œπ‘™π‘‘π‘™ 𝑓 𝑒 π‘₯: π‘₯𝑠 = π‘“π‘œπ‘™π‘‘π‘™ 𝑓 𝑓 𝑒 π‘₯ π‘₯𝑠 π‘“π‘œπ‘™π‘‘π‘™ = 𝑒; π‘“π‘œπ‘™π‘‘π‘™ 𝑠 β§Ί [π‘₯] = 𝑓(π‘“π‘œπ‘™π‘‘π‘™ 𝑠 , π‘₯) ∢ / \ π‘₯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

Slide 12

Slide 12 text

𝑓 / \ π‘₯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.

Slide 13

Slide 13 text

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.

Slide 14

Slide 14 text

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.