All You Need is Fold in the Key of C# Mike Harris
All You Need is Foldin the Key of C# Mike Harris
All You Need Is FOLD
All You Need Is FOLD
All you need is FOLD
FOLD
Fold is All You Need!
Tour
• Backstage
• Concert
• Farewell
Backstage
f
g
Function
f g
f(g)
Function
Fold
a1
a2
an
b
Fold
foldr :: (α → β → β) → β → ([α] → β)foldl :: (β → α→ β) → β → ([α] → β)
SeedFunc
a1
a2
an
Fold b
Given
We
Func
Seed
f anf a2f Seed a1
f anf a2f(Seed, a1)
f anf(f(Seed, a1), a2)
b
Fold
a1
a2
an
b
— Paul FeyerabendAgainst Method Chapter 16
“Fundamental conceptual change … presupposes new world-views and
new languages capable of expressing them.”
Concert
All You Need is Fold
Set List
• And
• Or
• Length
• Reverse
• Map
• Filter
• Zip
Set List
• And
• Or
• Length
• Reverse
• Map
• Filter
• Zip
And
T/F
T/F
T/F
T/F
And
and :: [Bool] → Booland = fold (∧) True
TrueAnd
f1
f2
fn
Fold f
Given
We
And
True
And
True And
public bool And( params bool[] facts){ return facts.Aggregate( true, (m, x) => m && x);}
And True
var sut = new Folder(); sut.And(false, true, false);
And
True
False True False
And
And
True
False True False
M
X
result False
And
And
False
True False
M
X
result False
And
And
False
False
M
X
result False
And
And
True
False True False
result False
And
public bool And( params bool[] facts){ return facts.Aggregate( true, (m, x) => m && x);}
And True
Set List
• And
• Or
• Length
• Reverse
• Map
• Filter
• Zip
Or
T/F
T/F
T/F
T/F
Or
or :: [Bool] → Boolor = fold (∨) False
FalseOr
f1
f2
fn
Fold f
Given
We
Or
False
Or
False Or
public bool Or( params bool[] facts){ return facts.Aggregate( false, (m, x) => m || x);}
Or False
var sut = new Folder(); sut.Or(false, true, false);
Or
False
False True False
Or
Or
False
False True False
M
X
result False
Or
Or
False
True False
M
X
result True
Or
Or
True
False
M
X
result True
Or
Or
False
False True False
result True
Or
public bool Or( params bool[] facts){ return facts.Aggregate( false, (m, x) => m || x);}
Or False
Set List
• And
• Or
• Length
• Reverse
• Map
• Filter
• Zip
Length size
Length
length :: [α] → Intlength = fold (λx n → 1 + n) 0
0+ 1
x1
x2
xn
Fold #
Given
We
+ 1
0
+ 1
0 Length
public int Length(ICollection<T> coll){ return coll.Aggregate( 0, (m, _) => m + 1);}
+ 1 0
var sut = new Folder(); sut.Length("Mike".ToCharArray());
+ 1
0
M i k e
Length
+ 1
0M
result 1
M i k e
Length
+ 1
1M
result 2
i k e
Length
+ 1
2M
result 3
k e
Length
+ 1
3M
result 4
e
Length
+ 1
0
result 4
M i k e
Length
public int Length(ICollection<T> coll){ return coll.Aggregate( 0, (m, _) => m + 1);}
+ 1 0
Set List
• And
• Or
• Length
• Reverse
• Map
• Filter
• Zip
Reverse
x1
x2
xn
xn
x2
x1
Reverse
reverse :: [α] → [α]reverse = fold (λx m → m ++ [x]) [ ]
[ ]Cons
x1
x2
xn
Fold [x]
Given
We
Cons
[ ]
Cons
[ ] Reverse
public IEnumerable<T>Reverse(IEnumerable<T> coll){ return coll.Aggregate( new List<T>(), (m, x) => new List<T> {x} .Concat(m).ToList()););}
Cons [ ]
var sut = new Folder(); sut.Reverse("Mike".ToCharArray());
Cons
[ ]
M i k e
Reverse
Cons
[ ]
M i k
M
X
result M
e
Reverse
Cons
M
i k e
M
X
result iM
Reverse
Cons
iM
k e
M
X
result kiM
Reverse
Cons
kiM
e
M
X
result ekiM
Reverse
Cons
[ ]
result ekiM
M i k e
Reverse
public IEnumerable<T>Reverse(IEnumerable<T> coll){ return coll.Aggregate( new List<T>(), (m, x) => new List<T> {x} .Concat(m).ToList()););}
Cons [ ]
Set List
• And
• Or
• Length
• Reverse
• Map
• Filter
• Zip
Map
x1
x2
xn
z1
z2
zn
func
Map
map :: (α → β) → ([α] → [β])map f = fold (λx xs → f x : xs) [ ]
[ ]Conj
x1
x2
xn
Fold [z]
Given
We
Conj
[ ]
Conj
[ ]
func
Map
public IEnumerable<U> Map<T, U>( IEnumerable<T> coll, Func<T, U> func){ return coll.Aggregate( new List<U>(), (m, x) => { m.Add(func(x)); return m;});}
Conj [ ]
var sut = new Folder(); sut.Map( “Mike".ToCharArray(), s => s.ToUpper());
Conj
[ ]
M i k e
upper
Map
Conj
[ ]
M i k
M
X
result M
e
upper
Map
Conj
M
i k e
M
X
result MIupper
Map
Conj
MI
k e
M
X
result MIKupper
Map
Conj
MIK
e
M
X
result MIKEupper
Map
Conj
[ ]
M i k
result
e
upper MIKE
Map
public IEnumerable<U> Map<T, U>( IEnumerable<T> coll, Func<T, U> func){ return coll.Aggregate( new List<U>(), (m, x) => { m.Add(func(x)); return m;});}
Conj [ ]
Set List
• And
• Or
• Length
• Reverse
• Map
• Filter
• Zip
Filter
x1
x2
xn
x1
xn
pred
Filter
filter :: (α → Bool) → ([α] → [α])filter p = fold (λx xs → if p x then x : xs else xs) [ ]
if
Conj
[ ]
x1
x2
xn
Fold [x]
Given
We
[ ]
if
Conj
if
[ ]
pred Conj
Filter
public IEnumerable<T>Filter<T>( IEnumerable<T> coll, Func<T, bool> pred){ return coll.Aggregate( new List<T>(), (m, x) => { if(pred(x)) m.Add(x); return m;});} [ ]if Conj
var sut = new Folder(); sut.Filter( “Mike".ToCharArray(), s => s.All(char.IsLower));
if
[ ]
M i k e
isLower Conj
Filter
if
[ ]
M i k
M
X
result [ ]
e
isLower Conj
Filter
if
[ ]
i k e
M
X
isLower result iConj
Filter
if
i
k e
M
X
isLower result ikConj
Filter
if
ik
e
M
X
isLower result ikeConj
Filter
if
[ ]
isLower
M i k e
result ikeConj
Filter
public IEnumerable<T>Filter<T>( IEnumerable<T> coll, Func<T, bool> pred){ return coll.Aggregate( new List<T>(), (m, x) => { if(pred(x)) m.Add(x); return m;});} [ ]if Conj
Set List
• And
• Or
• Length
• Reverse
• Map
• Filter
• Zip
Zip
y1
y2
yj
z1
z2
zk
funcx1
x2
xi
Zip
zip2 :: (α → β → γ) → ([α] → [β] → [γ])zip2 f = fold (λx y xs ys → f x y : xs ys) [ ]
[ ]Conj
y1
y2
ym
Fold [z]
Given
We
Conj
[ ]
x1
x2
xn
Conj
[ ]
func
Zip
public ICollection<TZ>Zip<TX, TY, TZ>( ICollection<TX> xs, ICollection<TY> ys, Func<TX, TY, TZ> func){ return xs.Zip(ys,(x, y) => new Tuple<TX, TY>(x, y)) .Aggregate( new List<TZ>(), (m, p) => { m.Add(func.Invoke(p.Item1, p.Item2)); return m; });} Conj [ ]
return xs.Zip(ys, (x, y) => new Tuple<TX, TY>(x, y)) .Aggregate( new List<TZ>(), (m, p) => { m.Add( func.Invoke(p.Item1, p.Item2)); return m; });
Conj [ ]
var sut = new Folder(); sut.Zip( new[] {1, 2}, new[] {10, 20}, (x, y) => x + y);
Conj
[ ]
1 2
+
10 20
Zip
Conj
[ ]
1 2
+
10 20
M
result 11
X
Y
Zip
Conj
11
2
+
20
M
result 11 22
X
Y
Zip
Conj
[ ]
+ result 11 22
1 2
10 20
Zip
public ICollection<TZ>Zip<TX, TY, TZ>( ICollection<TX> xs, ICollection<TY> ys, Func<TX, TY, TZ> func){ return xs.Zip(ys,(x, y) => new Tuple<TX, TY>(x, y)) .Aggregate( new List<TZ>(), (m, p) => { m.Add(func.Invoke(p.Item1, p.Item2)); return m; });} Conj [ ]
Encore
Coin Changer
Change
coin1
coin2
coinn
c1
c2
cn
amount
Coin Changer kata
changeFor :: [α] → α → [α]changeFor a = fold (λa x xs → (a % x, a / x) : xs (a, [ ])
Conj
Changer
[ ]
amount
c1
c2
cn
Fold
Given
We
[c]
0
Conj
Changer
[ ]
amount
Conj
amount [ ]
Changer
Change
public class CoinChanger { public IEnumerable<int> Coins { get; set; }
public IEnumerable<int> ChangeFor(int amount) { return Coins.Aggregate( new Tuple<int, List<int>>(amount, new List<int>()), (m, coin) => { m.Item2.Add(m.Item1/coin); return new Tuple<int, List<int>>( m.Item1%coin, m.Item2); }).Item2; } }
Conj [ ]
Changer amount
public IEnumerable<int> ChangeFor(int amount) { return Coins.Aggregate( new Tuple<int, List<int>>(amount, new List<int>()), (m, coin) => { m.Item2.Add(m.Item1/coin); return new Tuple<int, List<int>>( m.Item1%coin, m.Item2); }).Item2; }
Conj [ ]
Changer amount
var sut = new CoinChanger { Coins = new[] {25, 10, 5, 1} };
sut.ChangeFor(99);
Conj
amount
25 10 5 1
[ ]
Changer
Change
Conj
99
25 10 5 1
[ ]M
X
result 24 3Changer
Change
Conj
24
10 5 1
3M
X
result 4 3 2Changer
Change
Conj
4
5 1
3 2M
X
result 4 3 2 0Changer
Change
Conj
4
1
3 2 0M
X
result 0 3 2 0 4Changer
Change
Conj result 0 3 2 0 4Changer
amount [ ]
25 10 5 1
Change
public class CoinChanger { public IEnumerable<int> Coins { get; set; }
public IEnumerable<int> ChangeFor(int amount) { return Coins.Aggregate( new Tuple<int, List<int>>(amount, new List<int>()), (m, coin) => { m.Item2.Add(m.Item1/coin); return new Tuple<int, List<int>>( m.Item1%coin, m.Item2); }).Item2; } }
Conj [ ]
Changer amount
— Paul FeyerabendAgainst Method Chapter 18
“[A]ll methodologies, even the most obvious ones, have their limits”
Thank you!
Mike Harris@MikeMKHhttp://comp-phil.blogspot.com/Remember, all you need is Fold!
Talks
• Rich Hickey - “Reducers”, EuroClojure 2012. https://vimeo.com/45561411
• Rich Hickey - “Transducers”, StrangeLoop 2014. https://www.youtube.com/watch?v=6mTbuzafcII
• Tomas Petricek - “History and Philosophy of Types”, StrangeLoop 2015. http://tpetricek.github.io/Talks/2015/philosophy-of-types/#/
Books
• Richard Bird and Phil Wadler - Introduction to Functional Programming. Prentice-Hall,1988.http://usi-pl.github.io/lc/sp-2015/doc/Bird_Wadler.%20Introduction%20to%20Functional%20Programming.1ed.pdf
• Paul Feyerabend - Against Method. Verso, 2010.
• Michael Fogus - Functional JavaScript: Introducing Functional Programming with Underscore.js. O’Reilly, 2013.http://functionaljavascript.com/
Papers
• Erik Meijer, Maarten Fokkinga, and Ross Paterson - “Functional Programming with Bananas, Lenses, Envelopes and Barbed Wire”. http://eprints.eemcs.utwente.nl/7281/01/db-utwente-40501F46.pdf
• Graham Hutton - “A tutorial on the universality and expressiveness of fold”.http://www.cs.nott.ac.uk/~gmh/fold.pdf
Blog Posts
• Brian McNamara - “Catamorphisms, part one”https://lorgonblog.wordpress.com/2008/04/05/catamorphisms-part-one/
• Edward Kmett - “Catamorphisms”https://www.fpcomplete.com/user/edwardk/recursion-schemes/catamorphisms
Websites
• ClojureDocs - https://clojuredocs.org/
• HaskellWiki - https://wiki.haskell.org/Haskell
• Inside F# - https://lorgonblog.wordpress.com/
• lodash - https://lodash.com/docs
• MDN - https://developer.mozilla.org/en-US/
• ReactiveX - http://reactivex.io/
Images (in order used)• "Abbey Rd Studios" by Misterweiss at en.wikipedia - Transfered from en.wikipedia Transfer was stated to be made by User:Blast..
Licensed under Public Domain via Commons - https://commons.wikimedia.org/wiki/File:Abbey_Rd_Studios.jpg#/media/File:Abbey_Rd_Studios.jpg
• "60s wallpaper" by Domincspics - Flickr. Licensed under CC BY 2.0 via Commons - https://commons.wikimedia.org/wiki/File:60s_wallpaper.jpg#/media/File:60s_wallpaper.jpg
• "70's Wallpaper" by Liz Sullivan - Own work. Licensed under CC BY-SA 4.0 via Wikimedia Commons - https://commons.wikimedia.org/wiki/File:70%27s_Wallpaper.JPG#/media/File:70%27s_Wallpaper.JPG
• "Flickr - ronsaunders47 - The Beatles-Sgt Pepper backdrop.". Licensed under CC BY-SA 2.0 via Wikimedia Commons - https://commons.wikimedia.org/wiki/File:Flickr_-_ronsaunders47_-_The_Beatles-Sgt_Pepper_backdrop..jpg#/media/File:Flickr_-_ronsaunders47_-_The_Beatles-Sgt_Pepper_backdrop..jpg
• "All you need is love graffiti Osijek" by Objavljeno - Own work. Licensed under CC BY-SA 3.0 via Wikimedia Commons - https://commons.wikimedia.org/wiki/File:All_you_need_is_love_graffiti_Osijek.JPG#/media/File:All_you_need_is_love_graffiti_Osijek.JPG
• "Illumined Pleasure Salvador Dali" by Salvador Dalí - Own workMrArifnajafov (Photography from the original). Licensed under CC BY-SA 3.0 via Wikimedia Commons - https://commons.wikimedia.org/wiki/File:Illumined_Pleasure_Salvador_Dali.JPG#/media/File:Illumined_Pleasure_Salvador_Dali.JPG
• "3 Savile Row" by Original uploader was Misterweiss at en.wikipedia - Transfered from en.wikipedia Transfer was stated to be made by User:Vinhtantran.. Licensed under Public Domain via Commons - https://commons.wikimedia.org/wiki/File:3_Savile_Row.jpg#/media/File:3_Savile_Row.jpg
• "Paul Feyerabend 2" by Grazia Borrini-Feyerabend. Licensed under Attribution via Commons - https://commons.wikimedia.org/wiki/File:Paul_Feyerabend_2.jpg#/media/File:Paul_Feyerabend_2.jpg
Images (in order used)• "The Beatles on Green Hill in Almaty, Kazakhstan" by Ken and Nyetta - Flickr: The Beatles on
Green Hill in Almaty. Licensed under CC BY 2.0 via Commons - https://commons.wikimedia.org/wiki/File:The_Beatles_on_Green_Hill_in_Almaty,_Kazakhstan.jpg#/media/File:The_Beatles_on_Green_Hill_in_Almaty,_Kazakhstan.jpg
• "The Beatles in America" by United Press International, photographer unknown - This image is available from the United States Library of Congress's Prints and Photographs division under the digital ID cph.3c11094.This tag does not indicate the copyright status of the attached work.
• "The Beatles rooftop concert" by Source. Licensed under Fair use via Wikipedia - https://en.wikipedia.org/wiki/File:The_Beatles_rooftop_concert.jpg#/media/File:The_Beatles_rooftop_concert.jpg
• "Paul Feyerabend 2" by Grazia Borrini-Feyerabend. Licensed under Attribution via Commons - https://commons.wikimedia.org/wiki/File:Paul_Feyerabend_2.jpg#/media/File:Paul_Feyerabend_2.jpg
• Myself taken at StrangeLoop 2014 by my wife, Kelsey Harris