Slide 1

Slide 1 text

What About the Natural Numbers? JMCT

Slide 2

Slide 2 text

N

Slide 3

Slide 3 text

N?

Slide 4

Slide 4 text

“Some thirty years into the history of machine-independent programming language design, the treatment of numbers is still problematic.” — Colin Runciman, 1989

Slide 5

Slide 5 text

“Some sixty years into the history of machine-independent programming language design, the treatment of numbers is still problematic.” — Me, just now

Slide 6

Slide 6 text

Main takeaway The number system we use should relate to the structures of the problem we’re solving.

Slide 7

Slide 7 text

Main takeaway For some domains, the use of Reals1 may be appropriate: 1or their approximation via Floats

Slide 8

Slide 8 text

Main takeaway For some domains, the use of Reals1 may be appropriate: e.g. physics calculations involving volume, speed, or mass 1or their approximation via Floats

Slide 9

Slide 9 text

Main takeaway For many problems Integers are appropriate:

Slide 10

Slide 10 text

Main takeaway For many problems Integers are appropriate: Fixed-precision DSP

Slide 11

Slide 11 text

Main takeaway For many problems Integers are appropriate: Fixed-precision DSP Bank account balance :’(

Slide 12

Slide 12 text

Main takeaway Runciman’s argument: For many of the discrete structures involved in the day-to-day practice of programming, the natural numbers are the most appropriate number system.

Slide 13

Slide 13 text

How? In the process of exploring the Natural Numbers, we’ll be developing an API. As we progress we’ll see how different representations affect our API.

Slide 14

Slide 14 text

#goals

Slide 15

Slide 15 text

#goals 1. Show you that the [lazy?] Ns are Good and Proper

Slide 16

Slide 16 text

#goals 1. Show you that the [lazy?] Ns are Good and Proper 2. Demonstrate that even simple choices of types for an API have deep consequences

Slide 17

Slide 17 text

#goals 1. Show you that the [lazy?] Ns are Good and Proper 2. Demonstrate that even simple choices of types for an API have deep consequences 3. Have you asking “What about the Natural Numbers?” next time you create an API.

Slide 18

Slide 18 text

Shape of things to come

Slide 19

Slide 19 text

Shape of things to come 1. Overview of the Ns themselves

Slide 20

Slide 20 text

Shape of things to come 1. Overview of the Ns themselves 2. Programming with Nat

Slide 21

Slide 21 text

Shape of things to come 1. Overview of the Ns themselves 2. Programming with Nat 3. Arithmetic with Nat and properties we care about

Slide 22

Slide 22 text

Shape of things to come 1. Overview of the Ns themselves 2. Programming with Nat 3. Arithmetic with Nat and properties we care about 4. How does Nat influence API design?

Slide 23

Slide 23 text

Shape of things to come 1. Overview of the Ns themselves 2. Programming with Nat 3. Arithmetic with Nat and properties we care about 4. How does Nat influence API design? 5. Implementation concerns

Slide 24

Slide 24 text

Shape of things to come 1. Overview of the Ns themselves 2. Programming with Nat 3. Arithmetic with Nat and properties we care about 4. How does Nat influence API design? 5. Implementation concerns 6. Beyond Nat

Slide 25

Slide 25 text

Shape of things to come 1. Overview of the Ns themselves 2. Programming with Nat 3. Arithmetic with Nat and properties we care about 4. How does Nat influence API design? 5. Implementation concerns 6. Beyond Nat 7. Conclude

Slide 26

Slide 26 text

Let’s start 1. Overview of the Ns themselves 2. Programming with Nat 3. Arithmetic with Nat and properties we care about 4. How does Nat influence API design? 5. Implementation concerns 6. Beyond Nat 7. Conclude

Slide 27

Slide 27 text

What are they? The Natural numbers have a few definitions:

Slide 28

Slide 28 text

What are they? The Natural numbers have a few definitions: 1. Set Theoretic

Slide 29

Slide 29 text

What are they? The Natural numbers have a few definitions: 1. Set Theoretic 2. Peano Axioms

Slide 30

Slide 30 text

Setting Yourself Up For Success

Slide 31

Slide 31 text

Setting Yourself Up For Success Several possible Set-theoretic definitions, von Neumann proposed the following:

Slide 32

Slide 32 text

Setting Yourself Up For Success Several possible Set-theoretic definitions, von Neumann proposed the following: 0 = {}

Slide 33

Slide 33 text

Setting Yourself Up For Success Several possible Set-theoretic definitions, von Neumann proposed the following: 0 = {} 1 = 0 ∪ {0}

Slide 34

Slide 34 text

Setting Yourself Up For Success Several possible Set-theoretic definitions, von Neumann proposed the following: 0 = {} 1 = 0 ∪ {0} 2 = 1 ∪ {1}

Slide 35

Slide 35 text

Setting Yourself Up For Success Several possible Set-theoretic definitions, von Neumann proposed the following: 0 = {} 1 = 0 ∪ {0} = {0} = {{}} 2 = 1 ∪ {1} = {0, 1} = {{}, {{}}}

Slide 36

Slide 36 text

Setting Yourself Up For Success oof

Slide 37

Slide 37 text

Setting Yourself Up For Success In 1889 Giuseppe Peano published “The principles of arithmetic presented by a new method”

Slide 38

Slide 38 text

Setting Yourself Up For Success The two axioms we care about most (right now) are simple enough:

Slide 39

Slide 39 text

Setting Yourself Up For Success The two axioms we care about most (right now) are simple enough: 0 ∈ N

Slide 40

Slide 40 text

Setting Yourself Up For Success The two axioms we care about most (right now) are simple enough: 0 ∈ N ∀n ∈ N. S(n) ∈ N

Slide 41

Slide 41 text

Sign post 1. Overview of the Ns themselves 2. Programming with Nat 3. Arithmetic with Nat and properties we care about 4. How does Nat influence API design? 5. Implementation concerns 6. Beyond Nat 7. Conclude

Slide 42

Slide 42 text

Setting Yourself Up For Success Okay, but we’re concerned with the practice of programming . . .

Slide 43

Slide 43 text

Setting Yourself Up For Success type Nat where Z : Nat Succ : Nat -> Nat

Slide 44

Slide 44 text

Setting Yourself Up For Success Now we can easily represent any N we want!

Slide 45

Slide 45 text

Setting Yourself Up For Success Now we can easily represent any N we want! Z = 0 Succ n = 1 + n

Slide 46

Slide 46 text

Talk over?

Slide 47

Slide 47 text

Talk over? This is all very nice and elegant, but the ergonomics suck

Slide 48

Slide 48 text

RSI risk Even just typing this slide made my RSI flare up: 3 ⇒ Succ (Succ (Succ Z)) 11 ⇒ Succ (Succ (Succ (Succ (Succ (Succ (Succ (Succ (Succ (S

Slide 49

Slide 49 text

Spoonful of sugar What do we do for other types?

Slide 50

Slide 50 text

Spoonful of sugar type List elem where [] : List elem (::) : elem -> List elem -> List elem

Slide 51

Slide 51 text

Spoonful of sugar Lists are flexible and easy to reason about, but they have the same problem!

Slide 52

Slide 52 text

Spoonful of sugar Lists are flexible and easy to reason about, but they have the same problem! type String = List Char

Slide 53

Slide 53 text

Spoonful of sugar Lists are flexible and easy to reason about, but they have the same problem! type String = List Char initials = ’P’ :: (’W’ :: (’L’ :: []))

Slide 54

Slide 54 text

Spoonful of sugar Because of this ubiquity of lists, compiler writers quickly came up with syntactic sugar for them:

Slide 55

Slide 55 text

Spoonful of sugar Because of this ubiquity of lists, compiler writers quickly came up with syntactic sugar for them: "PWL" ⇒ ’P’ :: (’W’ :: (’L’ :: []))

Slide 56

Slide 56 text

Spoonful of sugar Because of this ubiquity of lists, compiler writers quickly came up with syntactic sugar for them: "PWL" ⇒ ’P’ :: (’W’ :: (’L’ :: [])) [1..3] ⇒ 1 :: (2 :: (3 :: []))

Slide 57

Slide 57 text

Spoonful of sugar Similarly, we can implement syntactic sugar for the natural numbers:

Slide 58

Slide 58 text

Spoonful of sugar Similarly, we can implement syntactic sugar for the natural numbers: 3 ⇒ Succ (Succ (Succ Z))

Slide 59

Slide 59 text

Spoonful of sugar We lose nothing with the syntactic sugar, we can still pattern match on naturals and retain all of our inductive reasoning.

Slide 60

Slide 60 text

Natural usage ... if length xs <= 5 then ... else ...

Slide 61

Slide 61 text

Pattern Matching still available... (<=) : Nat -> Nat -> Bool Z _ = True (Succ _) Z = False (Succ x) (Succ y) = x <= y

Slide 62

Slide 62 text

Sign post 1. Overview of the Ns themselves 2. Programming with Nat 3. Arithmetic with Nat and properties we care about 4. How does Nat influence API design? 5. Implementation concerns 6. Beyond Nat 7. Conclude

Slide 63

Slide 63 text

Reading, Writing and ...

Slide 64

Slide 64 text

Reading, Writing and ... 1. Programmers expect some arithmetic ‘out of the box’ when dealing with numbers.

Slide 65

Slide 65 text

Reading, Writing and ... 1. Programmers expect some arithmetic ‘out of the box’ when dealing with numbers. 2. At the very least they expect +, −, ×, ÷

Slide 66

Slide 66 text

Real data structures When programming with the discrete structures which are common in programming, there is a correspondence between the operations on numbers and the operations on the data structures.

Slide 67

Slide 67 text

Real data structures When programming with the discrete structures which are common in programming, there is a correspondence between the operations on numbers and the operations on the data structures. 1. Think ‘array indices’, or ‘size’

Slide 68

Slide 68 text

Real data structures When programming with the discrete structures which are common in programming, there is a correspondence between the operations on numbers and the operations on the data structures. 1. Think ‘array indices’, or ‘size’ 2. What would a negative size mean?

Slide 69

Slide 69 text

Who would even do that?

Slide 70

Slide 70 text

Who would even do that? Figure: lol

Slide 71

Slide 71 text

Exceptional negatives Think of how many APIs return an “Int”.

Slide 72

Slide 72 text

Exceptional negatives Think of how many APIs return an “Int”. 1. How many of these APIs only use the negative numbers to signal errors?

Slide 73

Slide 73 text

What do we want? If we think a bit about arithmetic we may conclude the following:

Slide 74

Slide 74 text

What do we want? If we think a bit about arithmetic we may conclude the following: 1. Ideally, our operators would be total

Slide 75

Slide 75 text

What do we want? If we think a bit about arithmetic we may conclude the following: 1. Ideally, our operators would be total 2. When possible, we want our operators to be closed

Slide 76

Slide 76 text

Why? These properties, when combined, allow us to be confident that when we operate on two Nats, we get another Nat.

Slide 77

Slide 77 text

Why? These properties, when combined, allow us to be confident that when we operate on two Nats, we get another Nat. 1. This isn’t true for arithmetic over all number systems (nor should it be!)

Slide 78

Slide 78 text

Why? These properties, when combined, allow us to be confident that when we operate on two Nats, we get another Nat. 1. This isn’t true for arithmetic over all number systems (nor should it be!) 2. Many languages fail even where it should be!

Slide 79

Slide 79 text

Totality Our functions being total gives us confidence that for any input, we get a result.

Slide 80

Slide 80 text

Closure Our functions being closed means that the result values lie within the same number system as their arguments.

Slide 81

Slide 81 text

What do we want? (part 2) “The aim is a total closed system of arithmetic with results that can be safely interpreted in the context of the discrete structures in general programming” — Colin Runciman, 1989

Slide 82

Slide 82 text

Back to arithmetic Addition and Multiplication present no difficulties.

Slide 83

Slide 83 text

Back to arithmetic What about Subtraction?

Slide 84

Slide 84 text

Don’t wait, saturate

Slide 85

Slide 85 text

Don’t wait, saturate (.-.) : Nat -> Nat -> Nat n .-. Z = n Z .-. _ = Z (Succ n) .-. (Succ m) = n .-. m

Slide 86

Slide 86 text

Relate back to data structures

Slide 87

Slide 87 text

Relate back to data structures drop : Nat -> List a -> List a drop Z xs = xs drop _ [] = [] drop (Succ n) (x::xs) = drop n xs

Slide 88

Slide 88 text

Relate back to data structures We want a correspondence between operations on data structures and on numbers: length (drop n xs) === length xs .-. n

Slide 89

Slide 89 text

Relate back to data structures These sorts of correspondences are what we use (often in our head) when programming or refactoring.

Slide 90

Slide 90 text

A divisive issue Unlike Subtraction, division is already closed over Natural Numbers

Slide 91

Slide 91 text

A divisive issue Unlike Subtraction, division is already closed over Natural Numbers (for the cases for which it is defined!)

Slide 92

Slide 92 text

Back to square zero Some mathematicians define the Natural Numbers as starting from One! Would that save us from this issue?

Slide 93

Slide 93 text

Back to square zero Maybe, but then we’d lose the important correspondence with real data structures.

Slide 94

Slide 94 text

Quick digression

Slide 95

Slide 95 text

Quick digression Zero is not nothing!

Slide 96

Slide 96 text

Two solutions Runciman proposes two solutions to the ‘division by zero’ problem:

Slide 97

Slide 97 text

Two solutions Runciman proposes two solutions to the ‘division by zero’ problem: 1. based on viewing division on Ns as ‘slicing’

Slide 98

Slide 98 text

Two solutions Runciman proposes two solutions to the ‘division by zero’ problem: 1. based on viewing division on Ns as ‘slicing’ 2. based on using lazy Nats

Slide 99

Slide 99 text

Division as slicing Think of dividing x by y as cutting x in y places.

Slide 100

Slide 100 text

Division as slicing We can write a total division, //, in terms of a partial (fails when dividing by zero) division, /:

Slide 101

Slide 101 text

Division as slicing We can write a total division, //, in terms of a partial (fails when dividing by zero) division, /: x // y = x / (Succ y)

Slide 102

Slide 102 text

Umm... We get one intuitive property

Slide 103

Slide 103 text

Umm... We get one intuitive property Slicing zero times gets you the original thing back

Slide 104

Slide 104 text

... that’s wrong At the cost of it being incorrect at every other Nat

Slide 105

Slide 105 text

Let’s fix it We get back correctness by subtracting 1 from the divisor before passing it // x ./. y = x // (y .-. 1)

Slide 106

Slide 106 text

You coward!

Slide 107

Slide 107 text

You coward! In a sense we’ve only side-stepped the problem!

Slide 108

Slide 108 text

You coward! In a sense we’ve only side-stepped the problem! If you think this is the lazy solution...

Slide 109

Slide 109 text

Even lazier Runciman proposes another solution to this problem:

Slide 110

Slide 110 text

Even lazier Runciman proposes another solution to this problem: Lazy Natural Numbers

Slide 111

Slide 111 text

Lazy Nats If we’re in a lazy language we can have infinite structures!

Slide 112

Slide 112 text

Go infinity... If we’re in a lazy language we can have infinite structures! infinity = Succ infinity

Slide 113

Slide 113 text

Back to division x ./. 0 = infinity x ./. y = x / y

Slide 114

Slide 114 text

No cheating

Slide 115

Slide 115 text

No cheating x ./. y = if x < y then 0 else Succ ((x .-. y) ./. y)

Slide 116

Slide 116 text

More power to you Exponentiation is not closed over the Integers, but over Naturals it is!

Slide 117

Slide 117 text

More power to you Exponentiation is not closed over the Integers, but over Naturals it is! pow n 0 = 1 pow n (Succ p) = n * pow n p

Slide 118

Slide 118 text

Laziness, revisited Let’s not start a war here

Slide 119

Slide 119 text

Laziness, revisited Infinite values also allow you to avoid ‘cheating’ in some standard algorithms

Slide 120

Slide 120 text

Laziness, revisited How many times have you seen inf = 999999 in a graph algorithm?

Slide 121

Slide 121 text

Save yourself some computation Are there more than 10 people in your company?

Slide 122

Slide 122 text

Save yourself some computation Are there more than 10 people in your company? ... expensive > 10 ...

Slide 123

Slide 123 text

Laziness, revisited Lazy numbers let us compare the sizes of things without necessarily fully computing the size!

Slide 124

Slide 124 text

Sign post 1. Overview of the Ns themselves 2. Programming with Nat 3. Arithmetic with Nat and properties we care about 4. How does Nat influence API design? 5. Implementation concerns 6. Beyond Nat 7. Conclude

Slide 125

Slide 125 text

APIs We’ve alredy defined an API for arithmetic, with various tradeoffs.

Slide 126

Slide 126 text

APIs We’ve alredy defined an API for arithmetic, with various tradeoffs. 1. Now let’s define some non-arithmetic functions and see how the Nats guide us

Slide 127

Slide 127 text

Size Size of structures is very straightforward

Slide 128

Slide 128 text

Size size : List elem -> Nat size [] = Z size (x::xs) = Succ (size xs)

Slide 129

Slide 129 text

Position/Index Finding the index of a thing is a little more interesting

Slide 130

Slide 130 text

Position/Index: Mark 1 position : elem -> List elem -> ??????????

Slide 131

Slide 131 text

Position/Index: Mark 1 position : elem -> List elem -> ?????????? position a xs = pos xs 0 where pos (x::xs) n =

Slide 132

Slide 132 text

Position/Index: Mark 1 position : elem -> List elem -> ?????????? position a xs = pos xs 0 where pos (x::xs) n = if a == x then n else pos xs (Succ n)

Slide 133

Slide 133 text

Position/Index: Mark 1 position : elem -> List elem -> ?????????? position a xs = pos xs 0 where pos (x::xs) n = if a == x then n else pos xs (Succ n) pos [] n = ????

Slide 134

Slide 134 text

Position/Index: Mark 1 position : elem -> List elem -> Option Nat position a xs = pos xs 0 where pos (x::xs) n = if a == x then Some n else pos xs (Succ n) pos [] n = None

Slide 135

Slide 135 text

Thoughts: Mark 1 This is satisfying because we’re explicit about the possibility of failure

Slide 136

Slide 136 text

Position/Index: Mark 2 It should really be positions!

Slide 137

Slide 137 text

Position/Index: Mark 2 It should really be positions! positions : elem -> List elem -> List Nat positions a xs = pos xs 0 where pos (x::xs) n = if a == x then n :: pos xs (Succ n) else pos xs (Succ n) pos [] n = []

Slide 138

Slide 138 text

Thoughts: Mark 2 In a lazy language positions is strictly more flexible

Slide 139

Slide 139 text

Thoughts: Mark 1 & 2 Mind the gap

Slide 140

Slide 140 text

Thoughts: Mark 1 & 2 Mind the gap There were none!

Slide 141

Slide 141 text

sublist Take the sublist of a list: sublist m n = take (n - m+1) . drop m

Slide 142

Slide 142 text

sublist The sublist function has invariants that the user has to keep in mind sublist m n = take (n - m+1) . drop m

Slide 143

Slide 143 text

sublist The sublist function has invariants that the user has to keep in mind sublist m n = take (n - m+1) . drop m What if n < (m-1)?

Slide 144

Slide 144 text

sublist The sublist function has invariants that the user has to keep in mind sublist m n = take (n - m+1) . drop m What if n < (m-1)? take would be passed a negative argument!

Slide 145

Slide 145 text

sublist Fix is straightforward sublist : Nat -> Nat -> List elem -> List elem sublist 0 n = take n sublist (Succ m) n = take (n .-. m) . drop (Succ m)

Slide 146

Slide 146 text

Sign post 1. Overview of the Ns themselves 2. Programming with Nat 3. Arithmetic with Nat and properties we care about 4. How does Nat influence API design? 5. Implementation concerns 6. Beyond Nat 7. Conclude

Slide 147

Slide 147 text

Issues Why don’t we see Nats everywhere?

Slide 148

Slide 148 text

Issues Why don’t we see Nats everywhere? Language designers don’t include them in the stdlibs

Slide 149

Slide 149 text

Issues Why don’t we see Nats everywhere? Language designers don’t include them in the stdlibs Concerns about performance

Slide 150

Slide 150 text

Interesting observation Even languages that try to have some sort of non-negative number end up tripping over themselves!

Slide 151

Slide 151 text

Interesting observation Even languages that try to have some sort of non-negative number end up tripping over themselves! e.g. C with size t and ssize t

Slide 152

Slide 152 text

I’m not making this up

Slide 153

Slide 153 text

Slide 154

Slide 154 text

:’(

Slide 155

Slide 155 text

Reality check This person is not wrong!

Slide 156

Slide 156 text

Reality check This person is not wrong! understanding the behavior of casts (especially implicit ones) is hard!

Slide 157

Slide 157 text

Is all hope lost? The issue is twofold:

Slide 158

Slide 158 text

Is all hope lost? The issue is twofold: Unsigned values can be coerced away

Slide 159

Slide 159 text

Is all hope lost? The issue is twofold: Unsigned values can be coerced away Programmers aren’t forced to recon with 0!

Slide 160

Slide 160 text

All hope is not lost Some languages do it right!

Slide 161

Slide 161 text

All hope is not lost Some languages do it right! Idris and Agda compile Peano Nats to machine words

Slide 162

Slide 162 text

What about the lazy Nats? There are issues with implementing the lazy Nats

Slide 163

Slide 163 text

What about the lazy Nats? There are issues with implementing the lazy Nats Lazy languages can have poor memory usage if lazy structures are implemented naively

Slide 164

Slide 164 text

What about the lazy Nats? What are the alternatives?

Slide 165

Slide 165 text

What about the lazy Nats? What are the alternatives? 1. a machine number

Slide 166

Slide 166 text

What about the lazy Nats? What are the alternatives? 1. a machine number 2. an unevaluated computation (i.e. a thunk)

Slide 167

Slide 167 text

What about the lazy Nats? What are the alternatives? 1. a machine number 2. an unevaluated computation (i.e. a thunk) 3. a pair (m,n) of machine number and thunk

Slide 168

Slide 168 text

Why not machine?

Slide 169

Slide 169 text

Why not machine? 1. Suitable for eager languages (IMO)

Slide 170

Slide 170 text

Why not machine? 1. Suitable for eager languages (IMO) 2. We lose infinity in lazy languages

Slide 171

Slide 171 text

Why not thunks?

Slide 172

Slide 172 text

Why not thunks? 1. Uses O(n) space

Slide 173

Slide 173 text

Why not thunks? 1. Uses O(n) space 2. where n is the value of the Nat!

Slide 174

Slide 174 text

Perfect pair? This leaves some combination of machine number and thunk

Slide 175

Slide 175 text

Perfect pair? This leaves some combination of machine number and thunk 1. Static analyses can help make it more efficient

Slide 176

Slide 176 text

Perfect pair? This leaves some combination of machine number and thunk 1. Static analyses can help make it more efficient 2. ‘dirty’ implementation techniques can be hidden from the user

Slide 177

Slide 177 text

Sign post 1. Overview of the Ns themselves 2. Programming with Nat 3. Arithmetic with Nat and properties we care about 4. How does Nat influence API design? 5. Implementation concerns 6. Beyond Nat 7. Conclude

Slide 178

Slide 178 text

What else

Slide 179

Slide 179 text

What else 1. Sets!

Slide 180

Slide 180 text

Consider the following:

Slide 181

Slide 181 text

Consider the following: 1. A function from an API you’re using returns a List

Slide 182

Slide 182 text

Consider the following: 1. A function from an API you’re using returns a List 2. Does order matter?

Slide 183

Slide 183 text

Consider the following: 1. A function from an API you’re using returns a List 2. Does order matter? 3. What does a duplicate element signal?

Slide 184

Slide 184 text

Mind the gap!

Slide 185

Slide 185 text

Mind the gap! 1. What if the same function returned a Set?

Slide 186

Slide 186 text

Mind the gap! 1. What if the same function returned a Set? 2. No order in the representation

Slide 187

Slide 187 text

Mind the gap! 1. What if the same function returned a Set? 2. No order in the representation 3. No duplicate elements

Slide 188

Slide 188 text

Picking up the signals

Slide 189

Slide 189 text

Picking up the signals 1. Every data structure is signaling something

Slide 190

Slide 190 text

Picking up the signals 1. Every data structure is signaling something 2. Asking the consumers of your API to ignore a signal only serves to increas the cognitive burden of your API

Slide 191

Slide 191 text

Picking up the signals 1. Every data structure is signaling something 2. Asking the consumers of your API to ignore a signal only serves to increas the cognitive burden of your API 3. Try choosing structures that are necessary and sufficient

Slide 192

Slide 192 text

Picking up the signals 1. Every data structure is signaling something 2. Asking the consumers of your API to ignore a signal only serves to increas the cognitive burden of your API 3. Try choosing structures that are necessary and sufficient 4. This way, all signals are meant to be heeded

Slide 193

Slide 193 text

Closing thoughts

Slide 194

Slide 194 text

Closing thoughts No one seems to disagree, and yet...

Slide 195

Slide 195 text

Ahead of his time

Slide 196

Slide 196 text

Ahead of his time “The benefits of lazy evaluation generally are now widely recognised (though still regarded as controversial by some)” — Colin Runciman, The year of TS’s birth

Slide 197

Slide 197 text

Smash that subscribe button Thanks for your time! You can read more of my rants @josecalderon

Slide 198

Slide 198 text

N!