Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Programming with Nothing

Programming with Nothing

We love Ruby for being powerful & expressive, but how much power does Ruby have if you remove all of its datatypes except for Proc and all of its features except for Proc.new and Proc#call?

The answer is roughly "the same as before", computationally speaking, but I show this practically by demonstrating proc-only Ruby implementations (i.e. Church encodings) of the booleans, the integers, lists etc and using them to build executable programs. If you haven't seen this before, you may be surprised by how far you can get without any of the "fundamental" operations and datatypes of a conventional programming language.

I'm mostly interested in the parlour game of building these representations and showing how they work; there wasn't time to go into much detail, give much motivation, or assemble much of a broad thread. So this is a fairly practical and hackish exploration of how to build simple datatypes in Ruby using only procs rather than a protracted meditation on the nature of computation.

Given at Ru3y Manor (http://rubymanor.org/3). There's a video of this talk at http://rubymanor.org/3/videos/programming_with_nothing/. The accompanying code is at https://github.com/tomstuart/nothing, and an article version is available at https://tomstu.art/programming-with-nothing.

Tom Stuart

October 29, 2011
Tweet

More Decks by Tom Stuart

Other Decks in Programming

Transcript

  1. expressive flexible beautiful loads of language features loads of core

    functionality loads of standard libraries loads of third-party libraries
  2. ” 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
  3. Procs are just plumbing. lambda { |x| x + 1

    }.call(41) = 41 + 1 The rest of the language does the actual work.
  4. lambda { |x, y| x + y }.call(3, 4) is

    the same as lambda { |x| lambda { |y| x + y } }.call(3).call(4)
  5. lambda { |x| p.call(x) } If p is a proc,

    then is the same as just p
  6. Proc.new { |x| x + 1 } proc { |x|

    x + 1 } lambda { |x| x + 1 } -> x { x + 1 } Creating a proc: 1.9 1.8
  7. I’m going to say: lambda { |x| x + 1

    }.call(41) Instead of: -> x { x + 1 }[41]
  8. GO

  9. (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|
  10. (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|
  11. How do we represent numbers using no data, only code?

    All our code can do is make or call a proc.
  12. 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
  13. ZERO = -> p { -> x { x }

    } ONE = -> p { -> x { p[x] } } TWO = -> p { -> x { p[p[x]] } } THREE = -> p { -> x { p[p[p[x]]] } }
  14. def to_integer(proc) proc[-> n { n + 1 }][0] end

    >> to_integer(ZERO) => 0 >> to_integer(THREE) => 3
  15. 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]]]]]]]]]]]]]]]]]]]]]]]]]]] ]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]] ]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]] } }
  16. 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|
  17. 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|
  18. Booleans are used for choosing between two options. Represent a

    boolean with code that chooses one of two values.
  19. TRUE = -> x { -> y { x }

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

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

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

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

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

    { } TRUE = -> x { -> y { x } } FALSE = -> x { -> y { y } } IF[ ]
  25. (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
  26. (n % THREE).zero? (n % FIVE).zero? (ONE..HUNDRED).map do |n| (n

    % FIFTEEN).zero? 'FizzBuzz' 'Fizz' 'Buzz' n.to_s end IF[ ][ ][IF[ ][ ][IF[ ][ ][ ]]]
  27. 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]]] } }
  28. 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]]] } }
  29. IS_ZERO = -> n { n[-> x { FALSE }][TRUE]

    } >> to_boolean(IS_ZERO[ZERO]) => true >> to_boolean(IS_ZERO[THREE]) => false
  30. ( ).zero? ( ).zero? ( ).zero? (ONE..HUNDRED).map do |n| IF[

    'FizzBuzz' ][IF[ 'Fizz' ][IF[ 'Buzz' ][ n.to_s ]]] end ][ ][ ][ n % FIFTEEN n % THREE n % FIVE
  31. ][ ][ ][ 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
  32. 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] } }
  33. Ruby’s if/else statement only evaluates one of its two blocks.

    Our IF implementation takes two values, not blocks to evaluate.
  34. MOD[SUBTRACT[m][n]][n] ][ m ] } } MOD = -> m

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

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

    { [x] } [SUBTRACT[m][n]][n] ][ m ] } } MOD MOD This is not an abbreviation.
  37. We can solve this problem with the “Y combinator”, a

    famous piece of helper code for defining recursive functions.
  38. Y = -> f { -> x { f[x[x]] }

    [-> x { f[x[x]] }] }
  39. ] } ] }] } x[x] x[x] = -> f

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

    { -> x { f[ [-> x { f[ Z -> y { [y] } -> y { [y] }
  41. ]][ ]][ ]][ 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
  42. PAIR = -> x { -> y { -> f

    { f[x][y] } } } LEFT = -> p { p[-> x { -> y { x } } ] } RIGHT = -> p { p[-> x { -> y { y } } ] }
  43. 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]] }
  44. def range(m, n) if m <= n range(m + 1,

    n).unshift(m) else [] end end
  45. RANGE = Z[-> f { -> m { -> n

    { IF[IS_LESS_OR_EQUAL[m][n]][ -> x { UNSHIFT[f[INCREMENT[m]][n]][m][x] } ][ EMPTY ] } } }]
  46. 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]] } } ] } }
  47. 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]] } }]
  48. -> 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]]]] }]
  49. WHY

  50. 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
  51. 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 } }
  52. 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 =