Slide 1

Slide 1 text

PROGRAMMING @tomstuart — RU3Y MANOR — 2011-10-29 WITH NOTHING

Slide 2

Slide 2 text

RUBY I LOVE

Slide 3

Slide 3 text

expressive flexible beautiful loads of language features loads of core functionality loads of standard libraries loads of third-party libraries

Slide 4

Slide 4 text

RUBY LET’S RUIN

Slide 5

Slide 5 text

How much can Ruby do if we remove all its features?

Slide 6

Slide 6 text

no gems no standard library no modules no classes no objects no methods

Slide 7

Slide 7 text

no control flow no assignment no arrays no strings no numbers no booleans

Slide 8

Slide 8 text

GAME JUST A

Slide 9

Slide 9 text

NOT SOFTWARE ENGINEERING ADVICE

Slide 10

Slide 10 text

HERE ARE THE RULES

Slide 11

Slide 11 text

create procs call procs (abbreviate with constants)

Slide 12

Slide 12 text

HERE IS THE GOAL

Slide 13

Slide 13 text

” Write a program that prints the numbers from 1 to 100. But for multiples of three print “Fizz” instead of the number and for the multiples of five print “Buzz”. For numbers which are multiples of both three and five print “FizzBuzz”. “ — Imran Ghory

Slide 14

Slide 14 text

LET’S TALK ABOUT PROCS

Slide 15

Slide 15 text

Procs are just plumbing. lambda { |x| x + 1 }.call(41) = 41 + 1 The rest of the language does the actual work.

Slide 16

Slide 16 text

Procs don’t need multiple arguments.

Slide 17

Slide 17 text

lambda { |x, y| x + y }.call(3, 4) is the same as lambda { |x| lambda { |y| x + y } }.call(3).call(4)

Slide 18

Slide 18 text

The only way to use the body of a proc is to call it.

Slide 19

Slide 19 text

lambda { |x| p.call(x) } If p is a proc, then is the same as just p

Slide 20

Slide 20 text

SYNTAX TIME STOP

Slide 21

Slide 21 text

Proc.new { |x| x + 1 } proc { |x| x + 1 } lambda { |x| x + 1 } -> x { x + 1 } Creating a proc: 1.9 1.8

Slide 22

Slide 22 text

1.9 1.8 p === 41 Calling a proc: p.call(41) p[41] p.(41)

Slide 23

Slide 23 text

I’m going to say: lambda { |x| x + 1 }.call(41) Instead of: -> x { x + 1 }[41]

Slide 24

Slide 24 text

GO

Slide 25

Slide 25 text

(1..100). if (n % 15).zero? elsif (n % 3).zero? elsif (n % 5).zero? else end end each puts puts puts puts 'FizzBuzz' 'Fizz' 'Buzz' n.to_s do |n|

Slide 26

Slide 26 text

(1..100). if (n % 15).zero? elsif (n % 3).zero? elsif (n % 5).zero? else end end 'FizzBuzz' 'Fizz' 'Buzz' n.to_s map do |n|

Slide 27

Slide 27 text

Numbers

Slide 28

Slide 28 text

How do we represent numbers using no data, only code? All our code can do is make or call a proc.

Slide 29

Slide 29 text

Represent a number n with code that calls a proc n times.

Slide 30

Slide 30 text

def zero(proc, x) x end def one(proc, x) proc[x] end def two(proc, x) proc[proc[x]] end def three(proc, x) proc[proc[proc[x]]] end

Slide 31

Slide 31 text

ZERO = -> p { -> x { x } } ONE = -> p { -> x { p[x] } } TWO = -> p { -> x { p[p[x]] } } THREE = -> p { -> x { p[p[p[x]]] } }

Slide 32

Slide 32 text

def to_integer(proc) proc[-> n { n + 1 }][0] end >> to_integer(ZERO) => 0 >> to_integer(THREE) => 3

Slide 33

Slide 33 text

FIVE = -> p { -> x { p[p[p[p[p[x]]]]] } } FIFTEEN = -> p { -> x { p[p[p[p[p[p[p[p[p[ p[p[p[p[p[p[x]]]]]]]]]]]]]]] } } HUNDRED = -> p { -> x { p[p[p[p[p[p[p[p[p[ p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[ p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[ p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[ p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[ p[p[p[p[p[p[p[x]]]]]]]]]]]]]]]]]]]]]]]]]]] ]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]] ]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]] } }

Slide 34

Slide 34 text

1 100 15 3 5 ( if (n % 'FizzBuzz' elsif (n % 'Fizz' elsif (n % 'Buzz' else n.to_s end end ).zero? ).zero? ).zero? .. ).map do |n|

Slide 35

Slide 35 text

ONE HUNDRED FIFTEEN THREE FIVE ( if (n % 'FizzBuzz' elsif (n % 'Fizz' elsif (n % 'Buzz' else n.to_s end end ).zero? ).zero? ).zero? .. ).map do |n|

Slide 36

Slide 36 text

This code doesn’t work: the numbers aren’t Fixnums. The numeric operations must be replaced too.

Slide 37

Slide 37 text

Booleans

Slide 38

Slide 38 text

How do we represent booleans using no data, only code?

Slide 39

Slide 39 text

Booleans are used for choosing between two options. Represent a boolean with code that chooses one of two values.

Slide 40

Slide 40 text

def true(x, y) x end def false(x, y) y end

Slide 41

Slide 41 text

TRUE = -> x { -> y { x } } FALSE = -> x { -> y { y } }

Slide 42

Slide 42 text

def to_boolean(proc) proc[true][false] end >> to_boolean(TRUE) => true >> to_boolean(FALSE) => false

Slide 43

Slide 43 text

def if(proc, x, y) proc[x][y] end

Slide 44

Slide 44 text

b [x] } -> x { } IF = -> b { TRUE = -> x { -> y { x } } FALSE = -> x { -> y { y } } -> y { [y] }

Slide 45

Slide 45 text

b [x] -> x { } } IF = -> b { TRUE = -> x { -> y { x } } FALSE = -> x { -> y { y } }

Slide 46

Slide 46 text

b } IF = -> b { TRUE = -> x { -> y { x } } FALSE = -> x { -> y { y } }

Slide 47

Slide 47 text

b IF = -> b { } TRUE = -> x { -> y { x } } FALSE = -> x { -> y { y } } proc [true][false] def to_boolean(proc) end

Slide 48

Slide 48 text

proc [true][false] def to_boolean(proc) end b IF = -> b { } TRUE = -> x { -> y { x } } FALSE = -> x { -> y { y } } IF[ ]

Slide 49

Slide 49 text

(n % THREE).zero? (n % FIVE).zero? (ONE..HUNDRED).map do |n| (n % FIFTEEN).zero? 'FizzBuzz' 'Fizz' 'Buzz' n.to_s end if elsif elsif else end

Slide 50

Slide 50 text

(n % THREE).zero? (n % FIVE).zero? (ONE..HUNDRED).map do |n| (n % FIFTEEN).zero? 'FizzBuzz' 'Fizz' 'Buzz' n.to_s end IF[ ][ ][IF[ ][ ][IF[ ][ ][ ]]]

Slide 51

Slide 51 text

Predicates

Slide 52

Slide 52 text

if == 0 else end false true n end def zero?(n) ZERO = -> p { -> x { x } } ONE = -> p { -> x { p[x] } } TWO = -> p { -> x { p[p[x]] } } THREE = -> p { -> x { p[p[p[x]]] } }

Slide 53

Slide 53 text

end [-> x { }][ ] false true n def zero?(n) ZERO = -> p { -> x { x } } ONE = -> p { -> x { p[x] } } TWO = -> p { -> x { p[p[x]] } } THREE = -> p { -> x { p[p[p[x]]] } }

Slide 54

Slide 54 text

IS_ZERO = -> n { n[-> x { FALSE }][TRUE] } >> to_boolean(IS_ZERO[ZERO]) => true >> to_boolean(IS_ZERO[THREE]) => false

Slide 55

Slide 55 text

( ).zero? ( ).zero? ( ).zero? (ONE..HUNDRED).map do |n| IF[ 'FizzBuzz' ][IF[ 'Fizz' ][IF[ 'Buzz' ][ n.to_s ]]] end ][ ][ ][ n % FIFTEEN n % THREE n % FIVE

Slide 56

Slide 56 text

][ ][ ][ IS_ZERO[ ] IS_ZERO[ ] IS_ZERO[ ] n % FIFTEEN n % THREE n % FIVE (ONE..HUNDRED).map do |n| IF[ 'FizzBuzz' ][IF[ 'Fizz' ][IF[ 'Buzz' ][ n.to_s ]]] end

Slide 57

Slide 57 text

Numeric operations

Slide 58

Slide 58 text

Here’s some basic arithmetic I made earlier: INCREMENT = -> n { -> f { -> x { f[n[f][x]] } } } DECREMENT = -> n { -> f { -> x { n[-> g { -> h { h[g[f]] } }] [-> y { x }][-> y { y }] } } } ADD = -> m { -> n { n[INCREMENT][m] } } SUBTRACT = -> m { -> n { n[DECREMENT][m] } } MULTIPLY = -> m { -> n { n[ADD[m]][ZERO] } } POWER = -> m { -> n { n[MULTIPLY[m]][ONE] } }

Slide 59

Slide 59 text

def mod(m, n) if n <= m mod(m - n, n) else m end end

Slide 60

Slide 60 text

m def less_or_equal?(m, n) end - <= 0 n

Slide 61

Slide 61 text

n m def less_or_equal?(m, n) end IS_ZERO[SUBTRACT[ ][ ]]

Slide 62

Slide 62 text

IS_LESS_OR_EQUAL = -> m { -> n { IS_ZERO[SUBTRACT[m][n]] } }

Slide 63

Slide 63 text

def mod(m, n) if n <= m mod(m - n, n) else m end end

Slide 64

Slide 64 text

MOD = -> m { -> n { IF[IS_LESS_OR_EQUAL[n][m]][ MOD[SUBTRACT[m][n]][n] ][ m ] } }

Slide 65

Slide 65 text

PROBLEM

Slide 66

Slide 66 text

>> to_integer(MOD[THREE][TWO]) SystemStackError: stack level too deep

Slide 67

Slide 67 text

Ruby’s if/else statement only evaluates one of its two blocks. Our IF implementation takes two values, not blocks to evaluate.

Slide 68

Slide 68 text

MOD[SUBTRACT[m][n]][n] ][ m ] } } MOD = -> m { -> n { IF[IS_LESS_OR_EQUAL[n][m]][

Slide 69

Slide 69 text

-> x { [x] } MOD[SUBTRACT[m][n]][n] ][ m ] } } MOD = -> m { -> n { IF[IS_LESS_OR_EQUAL[n][m]][

Slide 70

Slide 70 text

>> to_integer(MOD[THREE][TWO]) => 1 >> to_integer(MOD[ POWER[THREE][THREE] ][ ADD[THREE][TWO] ]) => 2

Slide 71

Slide 71 text

ANOTHER PROBLEM

Slide 72

Slide 72 text

= -> m { -> n { IF[IS_LESS_OR_EQUAL[n][m][ -> x { [x] } [SUBTRACT[m][n]][n] ][ m ] } } MOD MOD This is not an abbreviation.

Slide 73

Slide 73 text

We can solve this problem with the “Y combinator”, a famous piece of helper code for defining recursive functions.

Slide 74

Slide 74 text

Y = -> f { -> x { f[x[x]] } [-> x { f[x[x]] }] }

Slide 75

Slide 75 text

Actually, this loops forever too. We need a modified version.

Slide 76

Slide 76 text

] } ] }] } x[x] x[x] = -> f { -> x { f[ [-> x { f[ Y

Slide 77

Slide 77 text

] } ] }] } x[x] x[x] = -> f { -> x { f[ [-> x { f[ Z -> y { [y] } -> y { [y] }

Slide 78

Slide 78 text

[SUBTRACT[m][n]][n][x] -> m { -> n { MOD = IF[IS_LESS_OR_EQUAL[n][m]][ -> x { } ][ m ] } } MOD

Slide 79

Slide 79 text

[SUBTRACT[m][n]][n][x] -> m { -> n { MOD = IF[IS_LESS_OR_EQUAL[n][m]][ -> x { } ][ m ] } } Z[-> f { f }]

Slide 80

Slide 80 text

(ONE..HUNDRED).map do |n| IF[IS_ZERO[ 'FizzBuzz' ][IF[IS_ZERO[ 'Fizz' ][IF[IS_ZERO[ 'Buzz' ][ n.to_s ]]] end FIFTEEN THREE FIVE % % % n n n ]][ ]][ ]][

Slide 81

Slide 81 text

]][ ]][ ]][ FIFTEEN THREE FIVE MOD[ ][ ] MOD[ ][ ] MOD[ ][ ] (ONE..HUNDRED).map do |n| IF[IS_ZERO[ 'FizzBuzz' ][IF[IS_ZERO[ 'Fizz' ][IF[IS_ZERO[ 'Buzz' ][ n.to_s ]]] end n n n

Slide 82

Slide 82 text

Lists

Slide 83

Slide 83 text

PAIR = -> x { -> y { -> f { f[x][y] } } } LEFT = -> p { p[-> x { -> y { x } } ] } RIGHT = -> p { p[-> x { -> y { y } } ] }

Slide 84

Slide 84 text

EMPTY = PAIR[TRUE][TRUE] UNSHIFT = -> l { -> x { PAIR[FALSE][PAIR[x][l]] } } IS_EMPTY = LEFT FIRST = -> l { LEFT[RIGHT[l]] } REST = -> l { RIGHT[RIGHT[l]] }

Slide 85

Slide 85 text

def range(m, n) if m <= n range(m + 1, n).unshift(m) else [] end end

Slide 86

Slide 86 text

RANGE = Z[-> f { -> m { -> n { IF[IS_LESS_OR_EQUAL[m][n]][ -> x { UNSHIFT[f[INCREMENT[m]][n]][m][x] } ][ EMPTY ] } } }]

Slide 87

Slide 87 text

( .. ) IF[IS_ZERO[MOD[n][FIFTEEN]]][ 'FizzBuzz' ][IF[IS_ZERO[MOD[n][THREE]]][ 'Fizz' ][IF[IS_ZERO[MOD[n][FIVE]]][ 'Buzz' ][ n.to_s ]]] end ONE HUNDRED .map do |n|

Slide 88

Slide 88 text

IF[IS_ZERO[MOD[n][FIFTEEN]]][ 'FizzBuzz' ][IF[IS_ZERO[MOD[n][THREE]]][ 'Fizz' ][IF[IS_ZERO[MOD[n][FIVE]]][ 'Buzz' ][ n.to_s ]]] end RANGE[ ][ ] ONE HUNDRED .map do |n|

Slide 89

Slide 89 text

FOLD = Z[-> f { -> l { -> x { -> g { IF[IS_EMPTY[l]][ x ][ -> y { g[f[REST[l]][x][g]][FIRST[l]][y] } ] } } } }] MAP = -> k { -> f { FOLD[k][EMPTY][ -> l { -> x { UNSHIFT[l][f[x]] } } ] } }

Slide 90

Slide 90 text

n IF[IS_ZERO[MOD[n][FIFTEEN]]][ 'FizzBuzz' ][IF[IS_ZERO[MOD[n][THREE]]][ 'Fizz' ][IF[IS_ZERO[MOD[n][FIVE]]][ 'Buzz' ][ n.to_s ]]] .map do | | end RANGE[ONE][HUNDRED]

Slide 91

Slide 91 text

RANGE[ONE][HUNDRED] n IF[IS_ZERO[MOD[n][FIFTEEN]]][ 'FizzBuzz' ][IF[IS_ZERO[MOD[n][THREE]]][ 'Fizz' ][IF[IS_ZERO[MOD[n][FIVE]]][ 'Buzz' ][ n.to_s ]]] MAP[ ][-> { }]

Slide 92

Slide 92 text

Strings

Slide 93

Slide 93 text

Strings can be represented as lists of numbers. Just choose an encoding.

Slide 94

Slide 94 text

def to_char(c) '0123456789BFiuz'.slice(to_integer(c)) end def to_string(s) to_array(s).map { |c| to_char(c) }.join end

Slide 95

Slide 95 text

TEN = MULTIPLY[TWO][FIVE] RADIX = TEN TO_STRING = Z[-> f { -> n { PUSH[ IF[IS_LESS_OR_EQUAL[n][DECREMENT[RADIX]]][ EMPTY ][ -> x { f[DIV[n][RADIX]][x] } ] ][MOD[n][RADIX]] } }]

Slide 96

Slide 96 text

MAP[RANGE[ONE][HUNDRED]][-> n { IF[IS_ZERO[MOD[n][FIFTEEN]]][ ][IF[IS_ZERO[MOD[n][THREE]]][ ][IF[IS_ZERO[MOD[n][FIVE]]][ ][ ]]] }] .to_s n 'FizzBuzz' 'Fizz' 'Buzz'

Slide 97

Slide 97 text

'FizzBuzz' 'Fizz' 'Buzz' MAP[RANGE[ONE][HUNDRED]][-> n { IF[IS_ZERO[MOD[n][FIFTEEN]]][ ][IF[IS_ZERO[MOD[n][THREE]]][ ][IF[IS_ZERO[MOD[n][FIVE]]][ ][ ]]] }] TO_STRING[ ] n

Slide 98

Slide 98 text

FIZZBUZZ FIZZ BUZZ MAP[RANGE[ONE][HUNDRED]][-> n { IF[IS_ZERO[MOD[n][FIFTEEN]]][ ][IF[IS_ZERO[MOD[n][THREE]]][ ][IF[IS_ZERO[MOD[n][FIVE]]][ ][ ]]] }] TO_STRING[ ] n

Slide 99

Slide 99 text

The constants are just abbreviations. Replace each constant with its definition to get the full program.

Slide 100

Slide 100 text

-> k { -> f { -> f { -> x { f[-> y { x[x][y] }] }[-> x { f[-> y { x[x][y] }] }] }[-> f { -> l { -> x { ->g { -> b { b }[-> p { p[-> x { -> y { x } } ] }[l]][x][-> y { g[f[-> l { -> p { p[-> x { -> y { y } } ] }[-> p { p[-> x { -> y { y } } ] }[l]] }[l]][x][g]][-> l { -> p { p[-> x { -> y { x } } ] }[-> p { p[-> x {-> y { y } } ] }[l]] }[l]][y] }] } } } }][k][-> x { - > y { -> f { f[x][y] } } }[-> x { -> y { x } }][-> x { -> y { x } }]][-> l { -> x { -> l { -> x { -> x { -> y { -> f { f[x][y] } } }[-> x { -> y { y } }][-> x { -> y { -> f { f[x] [y] } } }[x][l]] } }[l][f[x]] } }] } }[-> f { -> x { f[-> y { x[x][y] }] }[-> x { f[->y { x[x][y] }] }] }[-> f { -> m { -> n { -> b { b }[-> m { -> n { -> n { n[-> x { -> x { -> y { y } } }][-> x { -> y { x } }] }[-> m { -> n { n[-> n { -> f { -> x { n[-> g { -> h { h[g[f]] } }][-> y { x }][-> y { y }] } } }][m] } }[m][n]] } }[m][n]][-> x { -> l { -> x { -> x { -> y { -> f { f[x][y] } } }[-> x { -> y { y } }][-> x { -> y { -> f { f[x][y] } } }[x][l]] } }[f[-> n { -> f { -> x { f[n[f][x]] } } }[m]][n]][m][x] }][-> x { -> y { -> f { f[x][y] } } }[-> x { -> y { x } }][-> x { -> y { x } }]] } } }][-> f { -> x { f[x] } }][-> f { -> x { f[f[f[f[f[f[f[f[f[f[f[f[f[f[f[f[f[f[f[f[f[f[f[f[f[f[f[f[f[f[f[f[f[f[f[f[f[f[f[f[f[f[f[f[f[f[f[f[f[f[f [f[f[f[f[f[f[f[f[f[f[f[f[f[f[f[f[f[f[f[f[f[f[f[f[f[f[f[f[f[f[f[f[f[f[f[f[f[f[f[f[f[f[f[f[f[f[f[f[f[x]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]] ]]]]]]]]]]]]]] }}]][-> n { -> b { b }[-> n { n[-> x { -> x { -> y { y } } }][-> x { -> y { x } }] }[-> f { -> x { f[-> y { x[x][y] }] }[-> x { f[-> y { x[x][y] }] }] }[-> f { -> m { -> n { -> b { b }[-> m { -> n { -> n { n[-> x { -> x { -> y { y } } }][-> x { -> y { x } }] }[-> m { -> n { n[-> n { -> f { -> x { n[-> g { -> h { h[g[f]] } }][-> y { x }][-> y { y }] } } }] [m] } }[m][n]] } }[n][m]][-> x { f[-> m { -> n { n[-> n { -> f { -> x { n[-> g { -> h { h[g[f]] } }][-> y { x }][-> y { y }] } } }][m] } }[m][n]][n][x] }][m] } } }][n][-> f { -> x { f[f[f[f[f[f[f[f[f[f[f[f[f[f[f[x]]]]]]]]]]]]]]] } }]]][-> k { -> l { -> f { -> x { f[-> y { x[x][y] }] }[-> x { f[-> y { x[x][y] }] }] }[-> f { -> l { -> x { -> g { -> b { b }[-> p { p[-> x { -> y { x } } ] }[l]][x][-> y { g[f[-> l { -> p { p[-> x { -> y { y } } ] }[-> p { p[-> x { -> y { y } } ] }[l]] }[l]][x][g]][-> l { -> p { p[-> x { -> y { x } } ] }[-> p { p[- > x { -> y { y } } ] }[l]] }[l]][y] }] } } } }][k][l][-> l { -> x { -> x { -> y { -> f { f[x][y] } } }[-> x { -> y { y } }][-> x { -> y { -> f { f[x][y] } } }[x][l]] } }] } }[-> k { -> f { -> f { -> x { f[-> y { x[x][y] }] }[-> x { f[-> y { x[x][y] }] }] }[-> f { -> l { -> x { -> g { -> b { b }[-> p { p[-> x { -> y { x } } ] }[l]][x][-> y { g[f[-> l { -> p { p[-> x { -> y { y } } ] }[-> p { p[-> x { -> y { y } } ] }[l]] }[l]][x][g]][-> l { -> p { p[-> x { -> y { x } } ] }[-> p { p[-> x { -> y { y } } ] }[l]] }[l]][y] }] } } } }][k][-> x { -> y { -> f { f[x][y] } } }[-> x { -> y { x } }][-> x { -> y { x } }]][-> l { -> x { -> l { -> x { -> x { -> y { -> f { f[x][y] } } }[-> x { -> y { y } }][-> x { -> y { -> f { f[x][y] } } }[x] [l]] } }[l][f[x]] } }] } }[-> l { -> x { -> x {-> y { -> f { f[x][y] } } }[-> x { -> y { y } }][-> x { -> y { -> f { f[x][y] } } }[x][l]] } }[-> l { -> x { -> x { -> y { -> f { f[x] [y] } } }[-> x { -> y { y } }][-> x { -> y { -> f { f[x][y] } } }[x][l]] } }[->l { -> x { -> x { -> y { -> f { f[x][y] } } }[-> x { -> y { y } }][-> x { -> y { -> f { f[x][y] } } }[x] [l]] } }[-> l { -> x { -> x { -> y { -> f { f[x][y] } } }[-> x { -> y { y } }][-> x { -> y { -> f { f[x][y] } } }[x][l]] } }[-> x { -> y { -> f { f[x][y] } } }[-> x { -> y { x } }][-> x { -> y { x } }]][-> f {-> x { f[f[f[f[x]]]] } }]][-> f { -> x { f[f[f[f[x]]]] } }]][-> f { -> x { f[f[x]] } }]][-> f { -> x { f[x] } }]][-> m { -> n { n[-> n { -> f { -> x { f[n[f] [x]] } } }][m] } }[-> m { -> n { n[-> m { -> n { n[-> n { -> f { -> x { f[n[f][x]] } } }][m] } }[m]][-> f { -> x { x } }] } }[-> f { -> x { f[f[x]] } }][-> f { -> x { f[f[f[f[f[x]]]]] } }]]]][-> k { -> f { -> f { -> x { f[-> y { x[x][y] }] }[-> x { f[-> y { x[x][y] }] }] }[-> f { -> l { -> x { -> g { -> b { b }[-> p { p[-> x { -> y { x } } ] }[l]] [x][-> y { g[f[-> l { -> p { p[-> x { -> y { y } } ] }[-> p { p[-> x { -> y { y } } ] }[l]] }[l]][x][g]][-> l { -> p { p[-> x { -> y { x } } ] }[-> p { p[-> x { -> y { y } } ] }[l]] } [l]][y] }] } } } }][k][-> x { -> y { -> f { f[x][y] } } }[-> x { -> y { x } }][-> x { -> y { x } }]][-> l { -> x { -> l { -> x { -> x { -> y { -> f { f[x][y] } } }[-> x { -> y { y } }][- > x { -> y { -> f { f[x][y] } } }[x][l]] } }[l][f[x]] } }] } }[-> l { -> x { -> x { -> y { -> f { f[x][y] } } }[-> x { -> y { y } }][-> x { -> y { -> f { f[x][y] } } }[x][l]] } }[->l { - > x { -> x { -> y { -> f { f[x][y] } } }[-> x { -> y { y } }][-> x { -> y { -> f { f[x][y] } } }[x][l]] } }[-> l { -> x { -> x { -> y { -> f { f[x][y] } } }[-> x { -> y { y } }][-> x { - > y { -> f { f[x][y] } } }[x][l]] } }[-> l { -> x { -> x { -> y { -> f { f[x][y] } } }[-> x { -> y { y } }][-> x { -> y { -> f { f[x][y] } } }[x][l]] } }[-> x { -> y { -> f { f[x] [y] } } }[-> x { -> y { x } }][-> x { -> y { x } }]][-> f { -> x { f[f[f[f[x]]]] } }]][-> f { -> x { f[f[f[f[x]]]] } }]][-> f { -> x { f[f[f[x]]] } }]][->f { -> x { x } }]][-> m { -> n { n[-> n { -> f { -> x { f[n[f][x]] } } }][m] } }[-> m { -> n { n[-> m { ->n { n[-> n { -> f { -> x { f[n[f][x]] } } }][m] } }[m]][-> f { -> x { x } }] } }[-> f { -> x { f[f[x]] } }][-> f { -> x { f[f[f[f[f[x]]]]] } }]]]]][-> b { b }[-> n { n[-> x { -> x { -> y { y } } }][-> x { -> y { x } }] }[-> f { -> x { f[-> y { x[x][y] }] }[-> x { f[-> y { x[x][y] }] }] }[-> f { - > m { -> n { -> b { b }[-> m { -> n { -> n { n[-> x { -> x { -> y { y } } }][-> x { -> y { x } }] }[-> m { -> n { n[-> n { -> f { -> x { n[-> g { -> h { h[g[f]] } }][-> y { x }][-> y { y }] } } }][m] } }[m][n]] } }[n][m]][-> x { f[->m { -> n { n[-> n { -> f { -> x { n[-> g { -> h { h[g[f]] } }][-> y { x }][-> y { y }] } } }][m] } }[m][n]][n][x] }][m] } } }][n][-> f { -> x { f[f[f[x]]] } }]]][-> k { -> f { -> f { -> x { f[-> y { x[x][y] }] }[-> x { f[-> y { x[x][y] }] }] }[-> f { -> l { -> x { -> g { -> b { b }[-> p { p[-> x { -> y { x } } ] }[l]] [x][-> y { g[f[-> l { -> p { p[-> x { -> y { y } } ] }[-> p { p[-> x { -> y { y } } ] }[l]] }[l]][x][g]][-> l { -> p { p[-> x { -> y { x } } ] }[-> p { p[-> x { -> y { y } } ] }[l]] } [l]][y] }] } } } }][k][-> x { -> y { -> f { f[x][y] } } }[-> x { -> y { x } }][-> x { -> y { x } }]][-> l { -> x { -> l { -> x {-> x { -> y { -> f { f[x][y] } } }[-> x { -> y { y } }][-> x { -> y { -> f { f[x][y] } } }[x][l]] } }[l][f[x]] } }] } }[-> l { -> x { -> x { -> y { -> f { f[x][y] } } }[-> x { -> y { y } }][-> x { -> y { -> f { f[x][y] } } }[x][l]] } }[-> l { -> x { -> x { -> y { -> f { f[x][y] } } }[-> x { -> y { y } }][-> x { -> y { -> f { f[x][y] } } }[x][l]] } }[-> l { -> x { -> x { -> y { -> f { f[x][y] } } }[-> x { -> y { y } }][->x { -> y { -> f { f[x][y] } } }[x][l]] } }[-> l { -> x { -> x { -> y { -> f { f[x][y] } } }[-> x { -> y { y } }][-> x { -> y { -> f { f[x][y] } } }[x][l]] } }[-> x { -> y { -> f { f[x][y] } } }[- > x { -> y { x } }][-> x { -> y { x } }]][-> f { -> x { f[f[f[f[x]]]] } }]][-> f { -> x { f[f[f[f[x]]]] } }]][-> f { -> x { f[f[x]] } }]][-> f { -> x { f[x] } }]][-> m { -> n { n[-> n { -> f { -> x { f[n[f][x]] } } }][m] } }[-> m { -> n { n[-> m { -> n { n[-> n { -> f { -> x { f[n[f][x]] } } }][m] } }[m]][-> f { -> x { x } }] } }[-> f { -> x { f[f[x]] } }][-> f { -> x { f[f[f[f[f[x]]]]] } }]]]][-> b { b }[-> n { n[-> x { -> x { -> y { y } } }][-> x { -> y { x } }] }[-> f { -> x { f[-> y { x[x][y] }] }[-> x { f[-> y { x[x][y] }] }] }[-> f { ->m { -> n { -> b { b }[-> m { -> n { -> n { n[-> x { -> x { -> y { y } } }][-> x { -> y { x } }] }[-> m { -> n { n[-> n { -> f { -> x { n[-> g { -> h { h[g[f]] } }][-> y { x }][-> y { y }] } } }] [m] } }[m][n]] } }[n][m]][-> x { f[-> m { -> n { n[-> n { -> f { -> x { n[-> g { -> h { h[g[f]] } }][-> y { x }][-> y { y }] } } }][m] } }[m][n]][n][x] }][m] } } }][n][-> f { -> x { f[f[f[f[f[x]]]]] } }]]][-> k { -> f { -> f { -> x { f[-> y { x[x][y] }] }[-> x { f[-> y { x[x][y] }] }] }[-> f { -> l { -> x { -> g { -> b { b }[-> p { p[->x { -> y { x } } ] }[l]][x] [-> y { g[f[-> l { -> p { p[-> x { -> y { y } } ] }[-> p { p[-> x { -> y { y } } ] }[l]] }[l]][x][g]][-> l { -> p { p[-> x { -> y { x } } ] }[-> p { p[-> x { -> y { y } } ] }[l]] }[l]] [y] }] } } } }][k][-> x { -> y { -> f { f[x][y] } } }[-> x { -> y { x } }][-> x { -> y { x } }]][-> l { ->x { -> l { -> x { -> x { -> y { -> f { f[x][y] } } }[-> x { -> y { y } }][-> x { -> y { -> f { f[x][y] } } }[x][l]] } }[l][f[x]] } }] } }[-> l { -> x { -> x { -> y { -> f { f[x][y] } } }[-> x { -> y { y } }][-> x { -> y { -> f { f[x][y] } } }[x][l]] } }[-> l { -> x { -> x { -> y { -> f { f[x][y] } } }[-> x { -> y { y } }][-> x { -> y { -> f { f[x][y] } } }[x][l]] } }[-> l { -> x { -> x { -> y { -> f { f[x][y] } } }[-> x {-> y { y } }][-> x { -> y { -> f { f[x][y] } } }[x][l]] } }[-> l { -> x { -> x { -> y { -> f { f[x][y] } } }[-> x { -> y { y } }][-> x { -> y { -> f { f[x][y] } } }[x][l]] } }[-> x { -> y { -> f { f[x][y] } } }[- >x { -> y { x } }][-> x { -> y { x } }]][-> f { -> x { f[f[f[f[x]]]] } }]][-> f { -> x { f[f[f[f[x]]]] } }]][-> f { -> x { f[f[f[x]]] } }]][-> f { -> x { x } }]][-> m { -> n { n[-> n { - > f { -> x { f[n[f][x]] } } }][m] } }[-> m { -> n { n[-> m { -> n { n[-> n { -> f { -> x { f[n[f][x]] } } }][m] } }[m]][-> f { -> x { x } }] } }[-> f { -> x { f[f[x]] } }][-> f { -> x { f[f[f[f[f[x]]]]] } }]]]][-> f { -> x { f[-> y { x[x][y] }] }[-> x { f[-> y { x[x][y] }] }] }[-> f { -> n { -> l { -> x { -> k { -> l { -> f { -> x { f[-> y { x[x][y] }] }[-> x { f[-> y { x[x][y] }] }] }[-> f { -> l { -> x { -> g { -> b { b }[-> p { p[-> x { -> y { x } } ] }[l]][x][-> y { g[f[-> l { -> p { p[-> x { -> y { y } } ] }[-> p { p[-> x { -> y { y } } ] }[l]] } [l]][x][g]][-> l { -> p { p[-> x { -> y { x } } ] }[-> p { p[-> x { -> y { y } } ] }[l]] }[l]][y] }] } } } }][k][l][-> l { -> x { -> x { -> y { -> f { f[x][y] } } }[-> x { -> y { y } }] [-> x { -> y { -> f { f[x][y] } } }[x][l]] } }] } }[l][-> l { -> x { -> x { -> y { -> f { f[x][y] } } }[-> x { -> y { y } }][-> x {-> y { -> f { f[x][y] } } }[x][l]] } }[-> x { -> y { -> f { f[x][y] } } }[-> x { -> y { x } }][-> x { -> y { x } }]][x]] } }[-> b { b }[-> m { -> n { -> n { n[-> x { -> x { -> y { y } } }][-> x { -> y { x } }] }[-> m { -> n { n[-> n { -> f { -> x { n[-> g { -> h { h[g[f]] } }][-> y { x }][-> y { y }] } } }][m] } }[m][n]] } }[n][-> n { -> f { -> x { n[-> g { -> h { h[g[f]] } }][-> y { x }][-> y { y }] } } }[-> m { -> n { n[-> m { -> n { n[-> n { -> f { -> x { f[n[f][x]] } } }][m] } }[m]][-> f { -> x { x } }] } }[-> f { -> x { f[f[x]] } }][-> f { -> x { f[f[f[f[f[x]]]]] } }]]]][-> x { -> y { -> f { f[x] [y] } } }[-> x { -> y { x } }][-> x { -> y { x } }]][ -> x { f[-> f { -> x { f[-> y { x[x][y] }] }[-> x { f[-> y { x[x][y] }] }] }[->f { -> m { -> n { -> b { b }[-> m { -> n { -> n { n[- > x { -> x { -> y { y } } }][-> x { -> y { x } }] }[-> m { -> n { n[-> n { -> f { -> x { n[-> g { -> h { h[g[f]] } }][-> y { x }][-> y { y }] } } }][m] } }[m][n]] } }[n][m]][-> x { -> n { -> f { -> x { f[n[f][x]] } } }[f[-> m { -> n { n[-> n { -> f { -> x { n[-> g { -> h { h[g[f]] } }][-> y { x }][-> y { y }] } } }][m] } }[m][n]][n]][x] }][-> f { -> x { x } }] } } }][n] [-> m { -> n { n[-> m { -> n { n[-> n { -> f { -> x { f[n[f][x]] } } }][m] } }[m]][-> f { -> x { x } }] } }[-> f { -> x { f[f[x]] } }][-> f { -> x { f[f[f[f[f[x]]]]] } }]]][x] } ]][-> f { -> x { f[-> y { x[x][y] }] }[-> x { f[-> y { x[x][y] }] }] }[-> f { -> m { -> n { -> b { b }[-> m { -> n { -> n { n[-> x { ->x { -> y { y } } }][-> x { -> y { x } }] }[-> m { -> n { n[-> n { -> f { -> x { n[-> g { -> h { h[g[f]] } }][-> y { x }][-> y { y }] } } }][m] } }[m][n]] } }[n][m]][-> x { f[-> m { -> n { n[-> n { -> f { -> x { n[-> g { -> h { h[g[f]] } }][- > y { x }][-> y { y }] } } }][m] } }[m][n]][n][x] }][m] } } }][n][-> m { ->n { n[-> m { -> n { n[-> n { -> f { -> x { f[n[f][x]] } } }][m] } }[m]][-> f { -> x { x } }] } }[-> f { ->x { f[f[x]] } }][-> f { -> x { f[f[f[f[f[x]]]]] } }]]] } }][n]]]] }]

Slide 101

Slide 101 text

WHY

Slide 102

Slide 102 text

Within these constraints, we can build any data structure and implement any algorithm.

Slide 103

Slide 103 text

There is no data, only code.

Slide 104

Slide 104 text

No programming language has more computational power than -> and [].

Slide 105

Slide 105 text

What differentiates languages?

Slide 106

Slide 106 text

expressiveness aesthetic appeal safety vs. flexibility performance ecosystem community

Slide 107

Slide 107 text

Ruby is in our sweet spot. There are many languages like it, but this one is ours.

Slide 108

Slide 108 text

describe 'natural numbers' do specify { ADD[representation_of 2][representation_of 3].should represent 2 + 3 } specify { MULTIPLY[representation_of 2][representation_of 3].should represent 2 * 3 } specify { POWER[representation_of 2][representation_of 3].should represent 2 ** 3 } specify { SUBTRACT[representation_of 3][representation_of 2].should represent 3 - 2 } context 'with booleans' do (0..3).each do |n| specify { IS_ZERO[representation_of n].should represent n.zero? } specify { IS_EQUAL[representation_of n][representation_of 2].should represent n == 2 } end end context 'with recursion' do (0..5).zip([1, 1, 2, 6, 24, 120]) do |n, n_factorial| specify { FACTORIAL[representation_of n].should represent n_factorial } end [0, 1, 11, 27].product([1, 3, 11]) do |m, n| specify { DIV[representation_of m][representation_of n].should represent m / n } specify { MOD[representation_of m][representation_of n].should represent m % n } end end context 'with strings' do specify { TO_STRING[representation_of 42].should represent '42' } end end https://github.com/tomstuart/nothing

Slide 109

Slide 109 text

https://github.com/tomstuart/nothing Implement ADD, MULTIPLY and POWER for natural numbers --- a/lib/nothing.rb +++ b/lib/nothing.rb @@ -9,9 +9,9 @@ module Nothing TIMES = -> n { -> f { -> x { n[f][x] } } } INCREMENT = -> n { -> f { -> x { f[n[f][x]] } } } - # ADD = - # MULTIPLY = - # POWER = + ADD = -> m { -> n { n[INCREMENT][m] } } + MULTIPLY = -> m { -> n { n[ADD[m]][ZERO] } } + POWER = -> m { -> n { n[MULTIPLY[m]][ONE] } } # DECREMENT = # SUBTRACT = --- a/spec/nothing_spec.rb +++ b/spec/nothing_spec.rb @@ -11,9 +11,9 @@ describe Nothing do specify { TIMES[representation_of 3][-> s { s + 'o' }]['hell'].should == 'hellooo' } specify { INCREMENT[representation_of 2].should represent 2 + 1 } - specify { pending { ADD[representation_of 2][representation_of 3].should represent 2 + 3 } } - specify { pending { MULTIPLY[representation_of 2][representation_of 3].should represent 2 * 3 } } - specify { pending { POWER[representation_of 2][representation_of 3].should represent 2 ** 3 } } + specify { ADD[representation_of 2][representation_of 3].should represent 2 + 3 } + specify { MULTIPLY[representation_of 2][representation_of 3].should represent 2 * 3 } + specify { POWER[representation_of 2][representation_of 3].should represent 2 ** 3 } specify { pending { DECREMENT[representation_of 3].should represent 3 - 1 } } specify { pending { SUBTRACT[representation_of 3][representation_of 2].should represent 3 - 2 } }

Slide 110

Slide 110 text

https://github.com/tomstuart/nothing Extract INJECT from SUM and PRODUCT --- a/lib/nothing.rb +++ b/lib/nothing.rb @@ -56,9 +56,11 @@ module Nothing FIRST = -> l { LEFT[RIGHT[l]] } REST = -> l { RIGHT[RIGHT[l]] } + INJECT = Z[-> f { -> l { -> x { -> g { IF[IS_EMPTY[l]][x][-> _ { f[REST[l]][g[x] [FIRST[l]]][g][_] }] } } } }] + RANGE = Z[-> f { -> x { -> y { IF[IS_LESS_OR_EQUAL][x][y][-> _ { UNSHIFT[x] [f[INCREMENT[x]][y]][_] }][EMPTY] } } }] - SUM = Z[-> f { -> l { IF[IS_EMPTY[l]][ZERO][-> _ { ADD[FIRST[l]][f[REST[l]]] [_] }] } }] - PRODUCT = Z[-> f { -> l { IF[IS_EMPTY[l]][ONE][-> _ { MULTIPLY[FIRST[l]][f[REST[l]]] [_] }] } }] + SUM = -> l { INJECT[l][ZERO][ADD] } + PRODUCT = -> l { INJECT[l][ONE][MULTIPLY] } # CONCAT = # PUSH = # REVERSE =

Slide 111

Slide 111 text

THANK YOU https://github.com/tomstuart/nothing [email protected] @tomstuart