280

# Equational Reasoning in Programming

June 21, 2016

## Transcript

2. None

4. ### Equational reasoning is the method of manipulating structures such as

formulas and expressions. The basic idea is that equals can be replaced by equals in any context.

10 = ?
6. ### Example f = sum . take 5 . repeat f

10 = ? f 10 = sum . take 5 . repeat \$ 10
7. ### Example f = sum . take 5 . repeat f

10 = ? f 10 = sum . take 5 . repeat \$ 10 repeat x = x : repeat x take n (x:xs) | n > 0 = x : take (n - 1) xs | otherwise = [] sum [] = 0 sum (x:xs) = x + sum xs
8. ### Example (beta reduction) repeat x = x : repeat x

take n (x:xs) | n > 0 = x : take (n - 1) xs | otherwise = [] sum [] = 0 sum (x:xs) = x + sum xs f 10 = sum (take 5 (repeat 10))
9. ### Example (beta reduction) repeat x = x : repeat x

take n (x:xs) | n > 0 = x : take (n - 1) xs | otherwise = [] sum [] = 0 sum (x:xs) = x + sum xs f 10 = sum (take 5 (repeat 10)) 5 > 0 so we take branch n > 0 of take
10. ### Example (beta reduction) repeat x = x : repeat x

take n (x:xs) | n > 0 = x : take (n - 1) xs | otherwise = [] sum [] = 0 sum (x:xs) = x + sum xs f 10 = sum (take 5 (repeat 10)) 5 > 0 so we take branch n > 0 of take Pattern match on (x:xs) so, expand repeat first
11. ### Example (beta reduction) repeat x = x : repeat x

take n (x:xs) | n > 0 = x : take (n - 1) xs | otherwise = [] sum [] = 0 sum (x:xs) = x + sum xs f 10 = sum (take 5 (repeat 10)) 5 > 0 so we take branch n > 0 of take Pattern match on (x:xs) so, expand repeat first
12. ### Example (beta reduction) repeat x = x : repeat x

take n (x:xs) | n > 0 = x : take (n - 1) xs | otherwise = [] sum [] = 0 sum (x:xs) = x + sum xs f 10 = sum (take 5 (repeat 10)) 5 > 0 so we take branch n > 0 of take Pattern match on (x:xs) so, expand repeat first f 10 = sum (take 5 (10 : repeat 10))
13. ### Example (beta reduction) repeat x = x : repeat x

take n (x:xs) | n > 0 = x : take (n - 1) xs | otherwise = [] sum [] = 0 sum (x:xs) = x + sum xs f 10 = sum (take 5 (repeat 10)) 5 > 0 so we take branch n > 0 of take Pattern match on (x:xs) so, expand repeat first f 10 = sum (take 5 (10 : repeat 10)) f 10 = sum (10 : take 4 (repeat 10))
14. ### Example repeat x = x : repeat x take n

(x:xs) | n > 0 = x : take (n - 1) xs | otherwise = [] sum [] = 0 sum (x:xs) = x + sum xs f 10 = sum (10 : take 4 (repeat 10))
15. ### Example repeat x = x : repeat x take n

(x:xs) | n > 0 = x : take (n - 1) xs | otherwise = [] sum [] = 0 sum (x:xs) = x + sum xs f 10 = sum (10 : take 4 (repeat 10)) Multiple possibilities to evaluate the expression
16. ### Example repeat x = x : repeat x take n

(x:xs) | n > 0 = x : take (n - 1) xs | otherwise = [] sum [] = 0 sum (x:xs) = x + sum xs f 10 = sum (10 : take 4 (repeat 10)) Multiple possibilities to evaluate the expression lazy vs eager evaluation
17. ### Diamond theorem Excluding ⊥, all evaluation paths lead to the

same result. Diamond theorem, Church-Rosser exp1 exp2 exp1 arg fun exp2 fun arg res
18. ### Example repeat x = x : repeat x take n

(x:xs) | n > 0 = x : take (n - 1) xs | otherwise = [] sum [] = 0 sum (x:xs) = x + sum xs f 10 = sum (10 : take 4 (repeat 10))
19. ### Example repeat x = x : repeat x take n

(x:xs) | n > 0 = x : take (n - 1) xs | otherwise = [] sum [] = 0 sum (x:xs) = x + sum xs f 10 = sum (10 : take 4 (repeat 10)) f 10 = sum (10 : take 4 (repeat 10)) f 10 = sum (10 : 10 : take 3 (repeat 10)) f 10 = sum (10 : 10 : 10 : take 2 (repeat 10)) f 10 = sum (10 : 10 : 10 : 10 : take 1 (repeat 10)) f 10 = sum (10 : 10 : 10 : 10 : 10 : take 0 (repeat 10)) f 10 = sum [10, 10, 10, 10, 10] f 10 = 50

21. ### Functional programming encourages equational reasoning understanding evaluation / debugging typeclass

rules GHC rewrite rules refactoring theorem proving optimizations algorithm design data structure design

24. ### Evaluation/Debugging evaluation: see previous example cool tool for teaching hard

to do for big programs
25. ### Evaluation/Debugging evaluation: see previous example cool tool for teaching hard

to do for big programs lazy evaluation vs. stack-based debugging
26. ### Evaluation/Debugging evaluation: see previous example cool tool for teaching hard

to do for big programs lazy evaluation vs. stack-based debugging GHCi debugger
27. ### Evaluation/Debugging evaluation: see previous example cool tool for teaching hard

to do for big programs lazy evaluation vs. stack-based debugging GHCi debugger hard to use for large programs
28. ### Evaluation/Debugging evaluation: see previous example cool tool for teaching hard

to do for big programs lazy evaluation vs. stack-based debugging GHCi debugger hard to use for large programs Hood: Haskell Object Observation Debugger
29. ### Evaluation/Debugging evaluation: see previous example cool tool for teaching hard

to do for big programs lazy evaluation vs. stack-based debugging GHCi debugger hard to use for large programs Hood: Haskell Object Observation Debugger print intermediate data structure
30. ### Evaluation/Debugging evaluation: see previous example cool tool for teaching hard

to do for big programs lazy evaluation vs. stack-based debugging GHCi debugger hard to use for large programs Hood: Haskell Object Observation Debugger print intermediate data structure use equational reasoning to reason about state around bug
31. ### Typeclass rules class Functor f where fmap :: (a ->

b) -> f a -> f b
32. ### Typeclass rules class Functor f where fmap :: (a ->

b) -> f a -> f b fmap id = id fmap (f . g) = fmap f . fmap g
33. ### Typeclass rules class (Functor f) => Applicative f where pure

:: a -> f a (<*>) :: f (a -> b) -> f a -> f b
34. ### Typeclass rules class (Functor f) => Applicative f where pure

:: a -> f a (<*>) :: f (a -> b) -> f a -> f b pure f <*> x = fmap f x pure id <*> v = v pure (.) <*> u <*> v <*> w = u <*> (v <*> w) pure f <*> pure x = pure (f x) u <*> pure y = pure (\$ y) <*> u
35. ### Typeclass rules class Monoid m where mempty :: m mappend

:: m -> m -> m mconcat :: [m] -> m mconcat = foldr mappend mempty (<>) = mappend
36. ### Typeclass rules class Monoid m where mempty :: m mappend

:: m -> m -> m mconcat :: [m] -> m mconcat = foldr mappend mempty (<>) = mappend mempty <> x = x x <> mempty = x (x <> y) <> z = x <> (y <> z)

them
39. ### Typeclass rules these rules are not checked by compiler prove

them test with QuickCheck or similar
40. ### Typeclass rules these rules are not checked by compiler prove

them test with QuickCheck or similar http://austinrochford.com/posts/ 2014-05-27-quickcheck-laws.html
41. ### Typeclass rules these rules are not checked by compiler prove

them test with QuickCheck or similar http://austinrochford.com/posts/ 2014-05-27-quickcheck-laws.html parametricity makes some rules be always valid (Functor)
42. ### Typeclass rules these rules are not checked by compiler prove

them test with QuickCheck or similar http://austinrochford.com/posts/ 2014-05-27-quickcheck-laws.html parametricity makes some rules be always valid (Functor) these rules hold over all instances of typeclass
43. ### Typeclass rules these rules are not checked by compiler prove

them test with QuickCheck or similar http://austinrochford.com/posts/ 2014-05-27-quickcheck-laws.html parametricity makes some rules be always valid (Functor) these rules hold over all instances of typeclass same reasoning holds when moving from Maybe a to [a]
44. ### Typeclass rules these rules are not checked by compiler prove

them test with QuickCheck or similar http://austinrochford.com/posts/ 2014-05-27-quickcheck-laws.html parametricity makes some rules be always valid (Functor) these rules hold over all instances of typeclass same reasoning holds when moving from Maybe a to [a] allow higher-level reasoning
45. ### Typeclass rules these rules are not checked by compiler prove

them test with QuickCheck or similar http://austinrochford.com/posts/ 2014-05-27-quickcheck-laws.html parametricity makes some rules be always valid (Functor) these rules hold over all instances of typeclass same reasoning holds when moving from Maybe a to [a] allow higher-level reasoning easily change the semantics of the program with minimal impact on performance/accuracy/etc.
46. ### GHC rewrite rules {-# RULES "map/map" forall f g xs.

map f (map g xs) = map (f.g) xs #-}
47. ### GHC rewrite rules {-# RULES "map/map" forall f g xs.

map f (map g xs) = map (f.g) xs #-} map f . map g = map (f . g)
48. ### GHC rewrite rules {-# RULES "map/map" forall f g xs.

map f (map g xs) = map (f.g) xs #-} map f . map g = map (f . g) List fusion function generating list function consuming list to generate result list = temporary data structure why not eliminate it?
49. ### List fusion :: Good producers List comprehensions Enumerations of simple

types Explicit lists The (:) constructor
50. ### List fusion :: Good producers List comprehensions Enumerations of simple

types Explicit lists The (:) constructor (++)
51. ### List fusion :: Good producers List comprehensions Enumerations of simple

types Explicit lists The (:) constructor (++) map take, drop, filter iterate, repeat zip, zipWith
52. ### List fusion :: Good consumers List comprehensions array (++) foldr

sum, product, all, any map take, drop, filter concat unzip zip, zipWith partition head sortBy
53. ### GHC rewrite rules (2) What if some equation is valid

only for one type?
54. ### GHC rewrite rules (2) What if some equation is valid

only for one type? or effective only for some types
55. ### GHC rewrite rules (2) What if some equation is valid

only for one type? or effective only for some types specialize rules
56. ### GHC rewrite rules (2) What if some equation is valid

only for one type? or effective only for some types specialize rules
57. ### GHC rewrite rules (2) What if some equation is valid

only for one type? or effective only for some types specialize rules toDouble :: Real a => a -> Double toDouble = fromRational . toRational
58. ### GHC rewrite rules (2) What if some equation is valid

only for one type? or effective only for some types specialize rules toDouble :: Real a => a -> Double toDouble = fromRational . toRational {-# RULES "toDouble/Int" toDouble = i2d #-} i2d (I# i) = D# (int2Double# i)

62. ### Theorem Proving Structural induction. data and codata final algebras and

final coalgebras
63. ### Theorem Proving Structural induction. data and codata final algebras and

final coalgebras
64. ### Theorem Proving Structural induction. data and codata final algebras and

final coalgebras sum [] = 0 sum (a:as) = a + sum as
65. ### Theorem Proving Structural induction. data and codata final algebras and

final coalgebras sum [] = 0 sum (a:as) = a + sum as sumSoFar x [] = [x] sumSoFar x (y:ys) = x : sumSoFar (x+y) ys
66. ### Data and (Structural) Induction sum [] = 0 sum (a:as)

= a + sum as sum (map (+1) x) = length x + sum x
67. ### Data and (Structural) Induction sum [] = 0 sum (a:as)

= a + sum as sum (map (+1) x) = length x + sum x Base case:
68. ### Data and (Structural) Induction sum [] = 0 sum (a:as)

= a + sum as sum (map (+1) x) = length x + sum x Base case: [] sum (map (+1) []) = sum [] = 0 length [] + sum [] = 0 + 0 = 0
69. ### Data and (Structural) Induction sum [] = 0 sum (a:as)

= a + sum as sum (map (+1) x) = length x + sum x Base case: [] sum (map (+1) []) = sum [] = 0 length [] + sum [] = 0 + 0 = 0 Inductive case:
70. ### Data and (Structural) Induction sum [] = 0 sum (a:as)

= a + sum as sum (map (+1) x) = length x + sum x Base case: [] sum (map (+1) []) = sum [] = 0 length [] + sum [] = 0 + 0 = 0 Inductive case:(for all constructors) sum (map (+1) (x:xs)) = sum ((x+1) : map (+1) xs) = (x+1) + sum (map (+1) xs) = (x+1) + length xs + sum xs = (1 + length xs) + (x + sum xs) = length (x:xs) + sum (x:xs)
71. ### Codata and (Structural) Coinduction fib = 1 : 1 :

zipWith (+) fib (tail fib) luc = 2 : 1 : zipWith (+) luc (tail luc)
72. ### Codata and (Structural) Coinduction fib = 1 : 1 :

zipWith (+) fib (tail fib) luc = 2 : 1 : zipWith (+) luc (tail luc) 1, 1, 2, 3, 5, 8, 13, 21, 34 2, 1, 3, 4, 7, 11, 18, 29, 47
73. ### Codata and (Structural) Coinduction fib = 1 : 1 :

zipWith (+) fib (tail fib) luc = 2 : 1 : zipWith (+) luc (tail luc) 1, 1, 2, 3, 5, 8, 13, 21, 34 2, 1, 3, 4, 7, 11, 18, 29, 47 Ln+2 = Fn+1 + 2 ∗ Fn
74. ### Codata and (Structural) Coinduction fib = 1 : 1 :

zipWith (+) fib (tail fib) luc = 2 : 1 : zipWith (+) luc (tail luc) 1, 1, 2, 3, 5, 8, 13, 21, 34 2, 1, 3, 4, 7, 11, 18, 29, 47 Ln+2 = Fn+1 + 2 ∗ Fn luc !! (n+2) = fib !! (n+1) + 2 * fib !! n
75. ### Codata and (Structural) Coinduction fib = 1 : 1 :

zipWith (+) fib (tail fib) luc = 2 : 1 : zipWith (+) luc (tail luc) 1, 1, 2, 3, 5, 8, 13, 21, 34 2, 1, 3, 4, 7, 11, 18, 29, 47 Ln+2 = Fn+1 + 2 ∗ Fn luc !! (n+2) = fib !! (n+1) + 2 * fib !! n tail (tail luc) = zipWith (+) (tail fib) (map (*2) fib)
76. ### Codata and (Structural) Coinduction fib = 1 : 1 :

zipWith (+) fib (tail fib) luc = 2 : 1 : zipWith (+) luc (tail luc) tail (tail luc) = zipWith (+) (tail fib) (map (*2) fib) zipWith (+) (tail fib) (map (*2) fib) = zipWith (+) (1 : zipWith (+) fib (tail fib)) (2 : 2 : map (*2) (zipWith (+)fib (tail fib))) = 3 : zipWith (+) (zipWith (+) fib (tail fib)) (2 : map (*2) (zipWith (+) fib (tail fib))) = ...
77. ### More on codata Firstly, induction principles are well known and

much used. The coinductive definition and proof principles for coalgebras are less well known by far, and often even not very clearly formulated. Rutten, 2000, seminal paper
78. ### More on codata Firstly, induction principles are well known and

much used. The coinductive definition and proof principles for coalgebras are less well known by far, and often even not very clearly formulated. Rutten, 2000, seminal paper bisimilarity, bisimulation A property holds by induction if there is good reason for it to hold; whereas a property holds by coinduction if there is no good reason for it not to hold. Induction is about finite data, coinduction is about infinite codata.

Coq, Idris
81. ### Hermit Haskell Equational Reasoning Model-to-Implementation Tunnel http://ku-fpg.github.io/software/hermit/ https://hackage.haskell.org/package/hermit http://www.ittc.ku.edu/~afarmer/talks/unsw.html Similar:

Coq, Idris (dependent languages)
82. ### Hermit Haskell Equational Reasoning Model-to-Implementation Tunnel http://ku-fpg.github.io/software/hermit/ https://hackage.haskell.org/package/hermit http://www.ittc.ku.edu/~afarmer/talks/unsw.html Similar:

Coq, Idris (dependent languages) Proving 4 color theorem

85. ### Solving sudoku type Matrix a = [Row a] type Row

a = [a] type Grid = Matrix Digit type Digit = Char digits = [’1’..’9’] blank = (== ’0’) solve = filter valid . expand . choices
86. ### Solving sudoku type Matrix a = [Row a] type Row

a = [a] type Grid = Matrix Digit type Digit = Char digits = [’1’..’9’] blank = (== ’0’) solve = filter valid . expand . choices 147 808 829 414 345 923 316 083 210 206 383 297 601

. choices
88. ### Solving sudoku solve = filter valid . expand . prune

. choices 12 157 665 459 056 928 801
89. ### Solving sudoku solve = filter valid . expand . prune

. choices 12 157 665 459 056 928 801 After some calculation solve = search . choices search m | not (safe m) = [] | complete m’ = [map (map (head) m’] | otherwise = concat (map search (expand1 m’)) where m’ = prune m
90. ### Solving sudoku solve = filter valid . expand . prune

. choices 12 157 665 459 056 928 801 After some calculation solve = search . choices search m | not (safe m) = [] | complete m’ = [map (map (head) m’] | otherwise = concat (map search (expand1 m’)) where m’ = prune m Blazingly fast: 8s on all puzzles

92. ### In other languages lazy, functional languages: everything applies eager, functional

languages: beware ⊥
93. ### In other languages lazy, functional languages: everything applies eager, functional

languages: beware ⊥ non-functional languages: possible?
94. ### In other languages lazy, functional languages: everything applies eager, functional

languages: beware ⊥ non-functional languages: possible?
95. ### In other languages lazy, functional languages: everything applies eager, functional

languages: beware ⊥ non-functional languages: possible? C++ code for cypto code on CUDA
96. ### In other languages lazy, functional languages: everything applies eager, functional

languages: beware ⊥ non-functional languages: possible? C++ code for cypto code on CUDA C++ templates
97. ### In other languages lazy, functional languages: everything applies eager, functional

languages: beware ⊥ non-functional languages: possible? C++ code for cypto code on CUDA C++ templates compilation: 24 hours
98. ### In other languages lazy, functional languages: everything applies eager, functional

languages: beware ⊥ non-functional languages: possible? C++ code for cypto code on CUDA C++ templates compilation: 24 hours running time: 500ms
99. ### In other languages lazy, functional languages: everything applies eager, functional

languages: beware ⊥ non-functional languages: possible? C++ code for cypto code on CUDA C++ templates compilation: 24 hours running time: 500ms equational reasoning to translate to non-template version
100. ### In other languages lazy, functional languages: everything applies eager, functional

languages: beware ⊥ non-functional languages: possible? C++ code for cypto code on CUDA C++ templates compilation: 24 hours running time: 500ms equational reasoning to translate to non-template version compile time: 10s
101. ### In other languages lazy, functional languages: everything applies eager, functional

languages: beware ⊥ non-functional languages: possible? C++ code for cypto code on CUDA C++ templates compilation: 24 hours running time: 500ms equational reasoning to translate to non-template version compile time: 10s running time: 550ms
102. ### In other languages lazy, functional languages: everything applies eager, functional

languages: beware ⊥ non-functional languages: possible? C++ code for cypto code on CUDA C++ templates compilation: 24 hours running time: 500ms equational reasoning to translate to non-template version compile time: 10s running time: 550ms
103. ### In other languages lazy, functional languages: everything applies eager, functional

languages: beware ⊥ non-functional languages: possible? C++ code for cypto code on CUDA C++ templates compilation: 24 hours running time: 500ms equational reasoning to translate to non-template version compile time: 10s running time: 550ms lack of tooling → every calculation must be done by hand
104. ### In other languages lazy, functional languages: everything applies eager, functional

languages: beware ⊥ non-functional languages: possible? C++ code for cypto code on CUDA C++ templates compilation: 24 hours running time: 500ms equational reasoning to translate to non-template version compile time: 10s running time: 550ms lack of tooling → every calculation must be done by hand IDE & automatic refactorings rarely help

107. ### Warning Beware of code that is too smart. https://mail.haskell.org/pipermail/haskell-cafe/ 2009-March/058475.html

different versions of same code different coding styles and levels of Haskell knowledge timings between versions derivation of efficient solution
108. ### Warning Beware of code that is too smart. https://mail.haskell.org/pipermail/haskell-cafe/ 2009-March/058475.html

different versions of same code different coding styles and levels of Haskell knowledge timings between versions derivation of efficient solution and a not-so-trivial bug
109. ### Clever Perl code is what you hope you understood in

the past, when you wrote it; clever Haskell code is what you hope you’ll understand in the future, when you’ll write it yourself! Sjur Gjøstein Karevoll, paraphrased