Save 37% off PRO during our Black Friday Sale! »

Programming with Something

6521e9a519b47e36983283ca0b577cb0?s=47 Tom Stuart
November 08, 2021

Programming with Something

The computational behaviour of Ruby procs (aka “lambdas” and “anonymous functions”) gives us enough power to implement any data structure and algorithm. Let’s reimplement that behaviour from scratch and then explore how to make our implementation more efficient.

Given at RubyConf 2021. A video, transcript and code repo are available at https://tomstu.art/programming-with-something.

6521e9a519b47e36983283ca0b577cb0?s=128

Tom Stuart

November 08, 2021
Tweet

Transcript

  1. Tom Stuart @ Shopify, RubyConf 2021 Programming with Something https://tomstu.art/programming-with-something

  2. Ten years ago…

  3. https://tomstu.art/programming-with-nothing PROGRAMMING @tomstuart — RU3Y MANOR — 2011-10-29 WITH NOTHING

  4. create procs call procs (abbreviate with constants) https://tomstu.art/programming-with-nothing

  5. ZERO = -> p { -> x { x }

    } ONE = -> p { -> x { p[x] } } TWO = -> p { -> x { p[p[x]] } } THREE = -> p { -> x { p[p[p[x]]] } } = lambda { |p| lambda { |x| p.call(p.call(p.call(x))) } } 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]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]] ]]]]]]]]]]]]]]]]]]]]]]]]]]]]] } }
  6. >> THREE[-> n { n + 1 }][0] => 3

    >> HUNDRED[-> n { n + 1 }][0] => 100 >> ZERO[-> n { n + 1 }][0] => 0
  7. INCREMENT = -> n { -> p { -> x

    { p[n[p][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] } }
  8. >> EIGHT = ADD[FIVE][THREE] => #<Proc (lambda)> >> EIGHT[-> n

    { n + 1 }][0] => 8 >> POWER[TWO][EIGHT][-> n { n + 1 }][0] => 256
  9. PAIR = -> x { -> y { -> f

    { f[x][y] } } } LEFT = -> p { p[-> x { -> y { x } } ] } RIGHT = -> p { p[-> x { -> y { y } } ] } 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]] }
  10. RANGE = Z[-> f { -> m { -> n

    { IF[IS_LESS_OR_EQUAL[m][n]][ -> x { UNSHIFT[f[INCREMENT[m]][n]][m][x] } ][ EMPTY ] } } }] MAP = -> k { -> f { FOLD[k][EMPTY][ -> l { -> x { UNSHIFT[l][f[x]] } } ] } }
  11. FIZZBUZZ = MAP[RANGE[ONE][HUNDRED]][-> n { IF[IS_ZERO[MOD[n][FIFTEEN]]][ FIZZ_BUZZ ][IF[IS_ZERO[MOD[n][THREE]]][ FIZZ ][IF[IS_ZERO[MOD[n][FIVE]]][

    BUZZ ][ TO_DIGITS[n] ]]] }]
  12. FIZZBUZZ = -> 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 { -> p { -> x { p[n[p][x]] } } }[m]][n]][m][x] }][-> x { -> y { -> f { f[x][y] } } }[-> x { -> y { x } }][- > x { -> y { x } }]] } } }][-> p { -> x { p[x] } }][-> 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]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]] } }]][-> 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][-> p { -> x { p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[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]] } }[-> 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 } }]][-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p] [x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> m { -> n { n[-> m { -> n { n[-> n { -> p { -> x { p[n[p][x]] } } }][m] } }[m]][-> p { -> x { x } }] } }[-> p { -> x { p[p[x]] } }][-> p { -> x { p[p[p[p[p[x]]]]] } }]]]]]]][-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> m { -> n { n[-> m { -> n { n[-> n { - > p { -> x { p[n[p][x]] } } }][m] } }[m]][-> p { -> x { x } }] } }[-> p { -> x { p[p[x]] } }][-> p { -> x { p[p[p[p[p[x]]]]] } }]]]]]]][-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { - > x { p[n[p][x]] } } }[-> m { -> n { n[-> m { -> n { n[-> n { -> p { -> x { p[n[p][x]] } } }][m] } }[m]][-> p { -> x { x } }] } }[-> p { -> x { p[p[x]] } }][-> p { -> x { p[p[p[p[p[x]]]]] } }]]]]]][-> m { -> n { n[-> m { -> n { n[-> n { -> p { -> x { p[n[p][x]] } } }][m] } }[m]][-> p { -> x { x } }] } }[-> p { -> x { p[p[x]] } }][-> p { -> x { p[p[p[p[p[x]]]]] } }]]][-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> m { -> n { n[-> m { -> n { n[-> n { -> p { -> x { p[n[p][x]] } } }][m] } }[m]][-> p { -> x { x } }] } }[-> p { -> x { p[p[x]] } }][-> p { -> x { p[p[p[p[p[x]]]]] } }]]]]]]][-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> m { -> n { n[-> m { -> n { n[-> n { -> p { -> x { p[n[p][x]] } } }][m] } }[m]][-> p { -> x { x } }] } }[-> p { -> x { p[p[x]] } }][-> p { -> x { p[p[p[p[p[x]]]]] } }]]]]]]][-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> m { -> n { n[-> m { -> n { n[-> n { -> p { -> x { p[n[p][x]] } } }][m] } }[m]][-> p { -> x { x } }] } }[-> p { -> x { p[p[x]] } }][-> p { -> x { p[p[p[p[p[x]]]]] } }]]]]][-> n { -> p { -> x { p[n[p][x]] } } }[-> m { -> n { n[-> m { -> n { n[-> n { -> p { -> x { p[n[p][x]] } } }][m] } }[m]][-> p { -> x { x } }] } }[-> p { -> x { p[p[x]] } }][-> p { -> x { p[p[p[p[p[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][-> p { -> x { p[p[p[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 } }]][-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> m { -> n { n[-> m { -> n { n[-> n { -> p { -> x { p[n[p][x]] } } }][m] } }[m]][-> p { -> x { x } }] } }[-> p { -> x { p[p[x]] } }][-> p { -> x { p[p[p[p[p[x]]]]] } }]]]]]]][-> n { -> p { -> x { p[n[p] [x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> m { -> n { n[-> m { -> n { n[-> n { -> p { -> x { p[n[p][x]] } } }][m] } }[m]][-> p { -> x { x } }] } }[-> p { -> x { p[p[x]] } }][-> p { -> x { p[p[p[p[p[x]]]]] } }]]]]]]][-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> m { -> n { n[-> m { -> n { n[-> n { -> p { -> x { p[n[p][x]] } } }][m] } } [m]][-> p { -> x { x } }] } }[-> p { -> x { p[p[x]] } }][-> p { -> x { p[p[p[p[p[x]]]]] } }]]]]][-> n { -> p { -> x { p[n[p][x]] } } }[-> m { -> n { n[-> m { -> n { n[-> n { -> p { -> x { p[n[p][x]] } } }][m] } }[m]][-> p { -> x { x } }] } }[-> p { -> x { p[p[x]] } }][-> p { -> x { p[p[p[p[p[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][-> p { -> x { p[p[p[p[p[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 } }]][-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> m { -> n { n[-> m { -> n { n[-> n { -> p { -> x { p[n[p][x]] } } }][m] } }[m]][-> p { -> x { x } }] } }[-> p { -> x { p[p[x]] } }][-> p { -> x { p[p[p[p[p[x]]]]] } }]]]]]]][-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> m { -> n { n[-> m { -> n { n[-> n { -> p { -> x { p[n[p][x]] } } }][m] } }[m]][-> p { -> x { x } }] } }[-> p { -> x { p[p[x]] } }][-> p { -> x { p[p[p[p[p[x]]]]] } }]]]]]]][-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> m { -> n { n[-> m { -> n { n[-> n { -> p { -> x { p[n[p][x]] } } }][m] } }[m]][- > p { -> x { x } }] } }[-> p { -> x { p[p[x]] } }][-> p { -> x { p[p[p[p[p[x]]]]] } }]]]]]][-> m { -> n { n[-> m { -> n { n[-> n { -> p { -> x { p[n[p][x]] } } }][m] } }[m]][-> p { -> x { x } }] } }[-> p { -> x { p[p[x]] } }][- > p { -> x { p[p[p[p[p[x]]]]] } }]]][-> f { -> x { f[-> y { x[x][y] }] }[-> x { f[-> y { x[x][y] }] }] }[-> f { -> n { -> l { -> x { -> 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] }] } } } }][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]][-> l { -> x { -> x { -> y { -> f { f[x][y] } } }[-> x { -> y { y } }][-> x { -> y { -> f { f[x][y] } } }[x][l]] } }] } }[-> 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 { -> p { -> x { p[n[p][x]] } } }][m] } }[m]][-> p { -> x { x } }] } }[-> p { -> x { p[p[x]] } }][-> p { -> x { p[p[p[p[p[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 { -> p { -> x { p[n[p][x]] } } }[f[-> m { -> n { n[-> n { -> f { -> x { n[-> g { -> h { h[g[f]] } }][-> y { x }][-> y { y }] } } }][m] } }[m][n]][n]][x] }][-> p { - > x { x } }] } } }][n][-> m { -> n { n[-> m { -> n { n[-> n { -> p { -> x { p[n[p][x]] } } }][m] } }[m]][-> p { -> x { x } }] } }[-> p { -> x { p[p[x]] } }][-> p { -> x { p[p[p[p[p[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 { -> p { -> x { p[n[p][x]] } } }][m] } }[m]][-> p { -> x { x } }] } }[-> p { -> x { p[p[x]] } }][-> p { -> x { p[p[p[p[p[x]]]]] } }]]] } }][n]]]] }]
  13. Ten years later…

  14. Could we represent these encoded values ourselves? Could we evaluate

    these encoded values ourselves? Could we decode these encoded values ourselves?
  15. -> p { -> x { p[p[p[x]]] } }

  16. -> p { -> x { p[p[p[x]]] } }

  17. -> p { -> x { p[p[p[x]]] } }

  18. -> p { -> x { p[p[p[x]]] } }

  19. -> p { -> x { p[p[p[x]]] } }

  20. FIZZBUZZ = -> 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 { -> p { -> x { p[n[p][x]] } } }[m]][n]][m][x] }][-> x { -> y { -> f { f[x][y] } } }[-> x { -> y { x } }][- > x { -> y { x } }]] } } }][-> p { -> x { p[x] } }][-> 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]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]] } }]][-> 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][-> p { -> x { p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[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]] } }[-> 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 } }]][-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p] [x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> m { -> n { n[-> m { -> n { n[-> n { -> p { -> x { p[n[p][x]] } } }][m] } }[m]][-> p { -> x { x } }] } }[-> p { -> x { p[p[x]] } }][-> p { -> x { p[p[p[p[p[x]]]]] } }]]]]]]][-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> m { -> n { n[-> m { -> n { n[-> n { - > p { -> x { p[n[p][x]] } } }][m] } }[m]][-> p { -> x { x } }] } }[-> p { -> x { p[p[x]] } }][-> p { -> x { p[p[p[p[p[x]]]]] } }]]]]]]][-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { - > x { p[n[p][x]] } } }[-> m { -> n { n[-> m { -> n { n[-> n { -> p { -> x { p[n[p][x]] } } }][m] } }[m]][-> p { -> x { x } }] } }[-> p { -> x { p[p[x]] } }][-> p { -> x { p[p[p[p[p[x]]]]] } }]]]]]][-> m { -> n { n[-> m { -> n { n[-> n { -> p { -> x { p[n[p][x]] } } }][m] } }[m]][-> p { -> x { x } }] } }[-> p { -> x { p[p[x]] } }][-> p { -> x { p[p[p[p[p[x]]]]] } }]]][-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> m { -> n { n[-> m { -> n { n[-> n { -> p { -> x { p[n[p][x]] } } }][m] } }[m]][-> p { -> x { x } }] } }[-> p { -> x { p[p[x]] } }][-> p { -> x { p[p[p[p[p[x]]]]] } }]]]]]]][-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> m { -> n { n[-> m { -> n { n[-> n { -> p { -> x { p[n[p][x]] } } }][m] } }[m]][-> p { -> x { x } }] } }[-> p { -> x { p[p[x]] } }][-> p { -> x { p[p[p[p[p[x]]]]] } }]]]]]]][-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> m { -> n { n[-> m { -> n { n[-> n { -> p { -> x { p[n[p][x]] } } }][m] } }[m]][-> p { -> x { x } }] } }[-> p { -> x { p[p[x]] } }][-> p { -> x { p[p[p[p[p[x]]]]] } }]]]]][-> n { -> p { -> x { p[n[p][x]] } } }[-> m { -> n { n[-> m { -> n { n[-> n { -> p { -> x { p[n[p][x]] } } }][m] } }[m]][-> p { -> x { x } }] } }[-> p { -> x { p[p[x]] } }][-> p { -> x { p[p[p[p[p[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][-> p { -> x { p[p[p[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 } }]][-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> m { -> n { n[-> m { -> n { n[-> n { -> p { -> x { p[n[p][x]] } } }][m] } }[m]][-> p { -> x { x } }] } }[-> p { -> x { p[p[x]] } }][-> p { -> x { p[p[p[p[p[x]]]]] } }]]]]]]][-> n { -> p { -> x { p[n[p] [x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> m { -> n { n[-> m { -> n { n[-> n { -> p { -> x { p[n[p][x]] } } }][m] } }[m]][-> p { -> x { x } }] } }[-> p { -> x { p[p[x]] } }][-> p { -> x { p[p[p[p[p[x]]]]] } }]]]]]]][-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> m { -> n { n[-> m { -> n { n[-> n { -> p { -> x { p[n[p][x]] } } }][m] } } [m]][-> p { -> x { x } }] } }[-> p { -> x { p[p[x]] } }][-> p { -> x { p[p[p[p[p[x]]]]] } }]]]]][-> n { -> p { -> x { p[n[p][x]] } } }[-> m { -> n { n[-> m { -> n { n[-> n { -> p { -> x { p[n[p][x]] } } }][m] } }[m]][-> p { -> x { x } }] } }[-> p { -> x { p[p[x]] } }][-> p { -> x { p[p[p[p[p[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][-> p { -> x { p[p[p[p[p[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 } }]][-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> m { -> n { n[-> m { -> n { n[-> n { -> p { -> x { p[n[p][x]] } } }][m] } }[m]][-> p { -> x { x } }] } }[-> p { -> x { p[p[x]] } }][-> p { -> x { p[p[p[p[p[x]]]]] } }]]]]]]][-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> m { -> n { n[-> m { -> n { n[-> n { -> p { -> x { p[n[p][x]] } } }][m] } }[m]][-> p { -> x { x } }] } }[-> p { -> x { p[p[x]] } }][-> p { -> x { p[p[p[p[p[x]]]]] } }]]]]]]][-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> m { -> n { n[-> m { -> n { n[-> n { -> p { -> x { p[n[p][x]] } } }][m] } }[m]][- > p { -> x { x } }] } }[-> p { -> x { p[p[x]] } }][-> p { -> x { p[p[p[p[p[x]]]]] } }]]]]]][-> m { -> n { n[-> m { -> n { n[-> n { -> p { -> x { p[n[p][x]] } } }][m] } }[m]][-> p { -> x { x } }] } }[-> p { -> x { p[p[x]] } }][- > p { -> x { p[p[p[p[p[x]]]]] } }]]][-> f { -> x { f[-> y { x[x][y] }] }[-> x { f[-> y { x[x][y] }] }] }[-> f { -> n { -> l { -> x { -> 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] }] } } } }][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]][-> l { -> x { -> x { -> y { -> f { f[x][y] } } }[-> x { -> y { y } }][-> x { -> y { -> f { f[x][y] } } }[x][l]] } }] } }[-> 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 { -> p { -> x { p[n[p][x]] } } }][m] } }[m]][-> p { -> x { x } }] } }[-> p { -> x { p[p[x]] } }][-> p { -> x { p[p[p[p[p[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 { -> p { -> x { p[n[p][x]] } } }[f[-> m { -> n { n[-> n { -> f { -> x { n[-> g { -> h { h[g[f]] } }][-> y { x }][-> y { y }] } } }][m] } }[m][n]][n]][x] }][-> p { - > x { x } }] } } }][n][-> m { -> n { n[-> m { -> n { n[-> n { -> p { -> x { p[n[p][x]] } } }][m] } }[m]][-> p { -> x { x } }] } }[-> p { -> x { p[p[x]] } }][-> p { -> x { p[p[p[p[p[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 { -> p { -> x { p[n[p][x]] } } }][m] } }[m]][-> p { -> x { x } }] } }[-> p { -> x { p[p[x]] } }][-> p { -> x { p[p[p[p[p[x]]]]] } }]]] } }][n]]]] }]
  21. Variable = Struct.new(:name) do def inspect = "#{name}" end Call

    = Struct.new(:receiver, :argument) do def inspect = "#{receiver.inspect}[#{argument.inspect}]" end Definition = Struct.new(:parameter, :body) do def inspect = "-> #{parameter} { #{body.inspect} }" end
  22. >> variable = Variable.new(:x) => x >> call = Call.new(variable,

    variable) => x[x] >> definition = Definition.new(:x, call) => -> x { x[x] }
  23. >> three = => -> p { -> x {

    p[p[p[x]]] } } Definition.new(:p, Definition.new(:x, Call.new( Variable.new(:p), Call.new( Variable.new(:p), Call.new( Variable.new(:p), Variable.new(:x) ) ) ) ) )
  24. :p Definition :x Call Call Call Variable Variable Variable Variable

    :x :p :p :p Definition.new(:p, Definition.new(:x, Call.new( Variable.new(:p), Call.new( Variable.new(:p), Call.new( Variable.new(:p), Variable.new(:x) ) ) ) ) ) Definition
  25. -> p { -> x { p[p[p[x]]] } } !

    Definition.new(:p, Definition.new(:x, Call.new( Variable.new(:p), Call.new( Variable.new(:p), Call.new( Variable.new(:p), Variable.new(:x) ) ) ) ) )
  26. >> instructions = RubyVM::InstructionSequence.of(-> p { -> x { p[p[p[x]]]

    } }) => <RubyVM::InstructionSequence:block in <main>@(irb):1> >> instructions.to_a => ["YARVInstructionSequence/SimpleDataFormat", 3, 0, 1, {:arg_size=>1, :local_size=>1, :stack_max=>1, :node_id=>19, :code_location=>[1, 49, 1, 74]}, "block in <main>", "(irb)", "(irb)", 1, :block, [:p], {:lead_num=>1, :ambiguous_param0=>true}, [[:redo, nil, :label_1, :label_6, :label_1, 0], [:next, nil, :label_1, :label_6, :label_6, 0]], [1, :RUBY_EVENT_B_CALL, [:nop], :label_1, :RUBY_EVENT_LINE, [:putspecialobject, 1], [:send, {:mid=>:lambda, :flag=>4, :orig_argc=>0}, ["YARVInstructionSequence/ SimpleDataFormat", 3, 0, 1, {:arg_size=>1, :local_size=>1, :stack_max=>4, :node_id=>17, :code_location=>[1, 56, 1, 72]}, "block (2 levels) in <main>", "(irb)", "(irb)", 1, :block, [:x], {:lead_num=>1, :ambiguous_param0=>true}, [[:redo, nil, :label_1, :label_15, :label_1, 0], [:next, nil, :label_1, :label_15, :label_15, 0]], [1, :RUBY_EVENT_B_CALL, [:nop], :label_1, :RUBY_EVENT_LINE, [:getlocal_WC_1, 3], [:getlocal_WC_1, 3], [:getlocal_WC_1, 3], [:getlocal_WC_0, 3], [:opt_aref, {:mid=>: [], :flag=>16, :orig_argc=>1}], [:opt_aref, {:mid=>:[], :flag=>16, :orig_argc=>1}], [:opt_aref, {:mid=>:[], :flag=>16, :orig_argc=>1}], :label_15, [:nop], :RUBY_EVENT_B_RETURN, [:leave]]]], :label_6, [:nop], :RUBY_EVENT_B_RETURN, [:leave]]]
  27. >> instructions = RubyVM::InstructionSequence.of(-> p { -> x { p[p[p[x]]]

    } }) => <RubyVM::InstructionSequence:block in <main>@(irb):1> >> puts instructions.disassemble == disasm: #<ISeq:block in <main>@(irb):1 (1,49)-(1,74)> (catch: FALSE) == catch table | catch type: redo st: 0001 ed: 0006 sp: 0000 cont: 0001 | catch type: next st: 0001 ed: 0006 sp: 0000 cont: 0006 |------------------------------------------------------------------------ local table (size: 1, argc: 1 [opts: 0, rest: -1, post: 0, block: -1, kw: -1@-1, kwrest: -1]) [ 1] p@0<Arg> 0000 nop ( 1)[Bc] 0001 putspecialobject 1[Li] 0003 send <calldata!mid:lambda, argc:0, FCALL>, block (2 levels) in <main> 0006 nop 0007 leave ( 1)[Br] == disasm: #<ISeq:block (2 levels) in <main>@(irb):1 (1,56)-(1,72)> (catch: FALSE) == catch table | catch type: redo st: 0001 ed: 0015 sp: 0000 cont: 0001 | catch type: next st: 0001 ed: 0015 sp: 0000 cont: 0015 |------------------------------------------------------------------------ local table (size: 1, argc: 1 [opts: 0, rest: -1, post: 0, block: -1, kw: -1@-1,
  28. [ 1] p@0<Arg> 0000 nop ( 1)[Bc] 0001 putspecialobject 1[Li]

    0003 send <calldata!mid:lambda, argc:0, FCALL>, block (2 levels) in <main> 0006 nop 0007 leave ( 1)[Br] == disasm: #<ISeq:block (2 levels) in <main>@(irb):1 (1,56)-(1,72)> (catch: FALSE) == catch table | catch type: redo st: 0001 ed: 0015 sp: 0000 cont: 0001 | catch type: next st: 0001 ed: 0015 sp: 0000 cont: 0015 |------------------------------------------------------------------------ local table (size: 1, argc: 1 [opts: 0, rest: -1, post: 0, block: -1, kw: -1@-1, kwrest: -1]) [ 1] x@0<Arg> 0000 nop ( 1)[Bc] 0001 getlocal_WC_1 p@0[Li] 0003 getlocal_WC_1 p@0 0005 getlocal_WC_1 p@0 0007 getlocal_WC_0 x@0 0009 opt_aref <calldata!mid:[], argc:1, ARGS_SIMPLE> 0011 opt_aref <calldata!mid:[], argc:1, ARGS_SIMPLE> 0013 opt_aref <calldata!mid:[], argc:1, ARGS_SIMPLE> 0015 nop 0016 leave ( 1)[Br] => nil
  29. $ echo 'THREE = -> p { -> x {

    p[p[p[x]]] } }' > three.rb $ irb -I. >> require 'three' => true >> file_name, line_number = THREE.source_location => ["three.rb", 1] >> line = IO.readlines(file_name)[line_number - 1] => "THREE = -> p { -> x { p[p[p[x]]] } }\n"
  30. >> pp Ripper.sexp(line) [:program, [[:assign, [:var_field, [:@const, "THREE", [1, 0]]],

    [:lambda, [:params, [[:@ident, "p", [1, 11]]], nil, nil, nil, nil, nil, nil], [[:lambda, [:params, [[:@ident, "x", [1, 18]]], nil, nil, nil, nil, nil, nil], [[:aref, [:var_ref, [:@ident, "p", [1, 22]]], [:args_add_block, [[:aref, [:var_ref, [:@ident, "p", [1, 24]]], [:args_add_block, [[:aref, [:var_ref, [:@ident, "p", [1, 26]]], [:args_add_block, [[:var_ref, [:@ident, "x", [1, 28]]]], false]]], false]]], false]]]]]]]]]
  31. >> THREE = -> p { -> x { p[p[p[x]]]

    } } => #<Proc (lambda)> >> THREE.parameters => [[:req, :p]] >> parameter = THREE.parameters[0][1] => :p >> body = # ???
  32. >> IDENTITY = -> x { x } => #<Proc

    (lambda)> >> variable = Variable.new(IDENTITY.parameters[0][1]) => x >> body = IDENTITY.call(variable) => x
  33. >> OMEGA = -> x { x[x] } => #<Proc

    (lambda)> >> variable = Variable.new(OMEGA.parameters[0][1]) => x >> body = OMEGA.call(variable) in `[]': no implicit conversion of Variable into Integer (TypeError) >> class Variable def [](argument) Call.new(self, argument) end end => :[] >> body = OMEGA.call(variable) => x[x]
  34. >> THREE = -> p { -> x { p[p[p[x]]]

    } } => #<Proc (lambda)> >> variable = Variable.new(THREE.parameters[0][1]) => p >> body = THREE.call(variable) => #<Proc (lambda)> >> variable = Variable.new(body.parameters[0][1]) => x >> body.call(variable) => p[p[p[x]]]
  35. def from_proc(proc) return proc unless proc.is_a?(Proc) case proc.parameters in [[:req,

    parameter]] argument = Variable.new(parameter) body = from_proc(proc.call(argument)) Definition.new(parameter, body) end end
  36. [Variable, Call, Proc].each do |klass| klass.define_method :[] do |argument| receiver

    = from_proc(self) argument = from_proc(argument) Call.new(receiver, argument) end end
  37. >> THREE => #<Proc (lambda)> >> from_proc(THREE) => -> p

    { -> x { p[p[p[x]]] } } >> from_proc(THREE).class => Definition >> FIZZBUZZ => #<Proc (lambda)> >> from_proc(FIZZBUZZ) => -> m { -> k { -> f { -> l { -> l { -> x { -> g { -> b { -> b { -> b { b }[b] }[b] }[-> p { -> p { -> p { p[-> x { -> y { x } }] }[p] }[p] } [l]][x][-> _ { g[-> _ { -> _ { -> _ { -> _ { -> x { -> x { -> x { -> x { -> f { -> f { -> f { -> f { -> l { -> x { -> g { -> b { -> b { -> b { -> b { -> b { b }[b] }[b] }[b] }[b] }[-> … >> from_proc(FIZZBUZZ).class => Definition
  38. Could we represent these encoded values ourselves? Could we evaluate

    these encoded values ourselves? Could we decode these encoded values ourselves?
  39. Variable = Struct.new(:name) Call = Struct.new(:receiver, :argument) Definition = Struct.new(:parameter,

    :body) def evaluate(expression) case expression in Variable(name) # TODO — get value from the correct parameter? in Call(receiver, argument) # TODO — evaluate(receiver), evaluate(argument)? in Definition(parameter, body) # TODO — evaluate(body)? end end
  40. AN UNSOLVABLE PROBLEM OF ELEMENTARY NUMBER THEORY.= 1. Introduction. There

    is a class of problems of elementary number theory which can be stated in the form that it is required to find an effectively calculable function f of n positive integers, such that f (x,, x,, . . . ,x,) = 2 is a necessary and sufficient condition for the truth of a certain proposition of elementary number theory involving x,, x,, . . .,x, as free variables. An example of such a problem is the problem to find a means of de- termining of any given positive integer n whether or not there exist positive integers 2, y, z, such that xn -/- yn = xn. For this may be interpreted, required t o find an effectively calculable function f, such that f (n) is equal to 2 if and only if there exist positive integers x, y, z, such that xn +yn = xn. Clearly the condition that the function f be effectively calculable is an essential part of the problem, since without it the problem becomes trivial. Another example of a problem of this class is, for instance, the problem of topology, to find a complete set of effectively calculable invariants of closed three-dimensional simplicia1 manifolds under homeomorphisms. This problem can be interpreted as a problem of elementary number theory in view of the fact that topological complexes are representable by matrices of incidence. I n fact, as is well known, the property of a set of incidence matrices that it represent a closed three-dimensional manifold, and the property of two sets of incidence matrices that they represent homeomorphic complexes, can both be described in purely number-theoretic terms. If we enumerate, in a straight- forward way, the sets of incidence matrices which represent closed three- dimensional manifolds, it will then be immediately provable that the problem under consideration (to find a complete set of effectively calculable invariants of closed three-dimensional manifolds) is equivalent to the problem, to find an effectively calculable function f of positive integers, such that f (m, lz) is equal to 2 if and only if the m-th set of incidence matrices and the lz-th set of incidence matrices in the enumeration represent homeomorphic complexes. Other examples will readily occur to the reader. Presented to the American Mathematical Society, April 19, 1935. The selection of the particular positive integer 2 instead of some other is, of course, accidental and non-essential. 345
  41. AN UNSOLVABLE PROBLEM OF NUMBER THEORY. 347 We shall use

    heavy type letters to stand for variable or undetermined formulas. And we adopt the convention that, unless otherwise stated, each heavy type letter shall represent a well-formed formula and each set of symbols standing apart which contains a heavy type letter shall represent a well- formed formula. When writing particular well-formed formulas, we adopt the following abbreviations. A formula {F) (X) may be abbreviated as F(X) in any case where F is or is represented by a single symbol. A formula {{F) (X)) (Y) may be abbreviated as {F)(X, Y), or, if F is or is represented by a single symbol, as F(X, Y) . And {{{F) (X) ) (Y) ) ( 2 ) may be abbreviated as {F) (X, Y, Z), or as F(X, Y, Z), and so on. A formula Ax, [I&,[. . . Xx,[M] . . .]] may be abbreviated as Ax,x,. . . & .M or as Xx,x, . . . x,M. We also allow ourselves at any time to introduce abbreviations of the form that a particular symbol a shall stand for a particular sequence of symbols A, and indicate the introduction of such an abbreviation by the nota- tion a -+ A, to be read, " a stands for A." We introduce at once the following infinite list of abbreviations, 1 4hub. a(b), 2 -+ Xab . a(a(b)), 3 -+hub9 a(a(a(b))), and so on, each positive integer in Arabic notation standing for a formula of the form hab.a(a(. . .a(b) . . .)). The expression S>M I is used to stand for the result of substituting N for x throughout M. We consider the three following operations on well-formed formulas : I. To replace any part h [ M ] of a formula by hy[S;M I], where y is a variable which does not occur in M. 11. To replace any part {Ax[M]) (N) of a formula by S;;M I, provided that the bound variables in M are distinct both from x and from the free variables in N. 1 1 1 . To replace any part S;M I (not immediately following A) of a fornzula by {Ax [MI ) (N), provided that the bound variables in M are distinct both from x and from the free variables in N. Any finite sequence of these operations is called a conversion, and if B is obtainable from A by a conversion we say that A is convertible into B, or, " A conv B." If B is identical with A or is obtainable from A by a single abbreviated as Ax,x,. . . & .M or as Xx,x, . . . x,M. We also allow ourselves at any time to introduce abbreviations of the form that a particular symbol a shall stand for a particular sequence of symbols A, and indicate the introduction of such an abbreviation by the nota- tion a -+ A, to be read, " a stands for A." We introduce at once the following infinite list of abbreviations, 1 4hub. a(b), 2 -+ Xab . a(a(b)), 3 -+hub9 a(a(a(b))), and so on, each positive integer in Arabic notation standing for a formula of the form hab.a(a(. . .a(b) . . .)). The expression S>M I is used to stand for the result of substituting N for x throughout M. We consider the three following operations on well-formed formulas : I. To replace any part h [ M ] of a formula by hy[S;M I], where y is
  42. AN UNSOLVABLE PROBLEM OF NUMBER THEORY. 347 We shall use

    heavy type letters to stand for variable or undetermined formulas. And we adopt the convention that, unless otherwise stated, each heavy type letter shall represent a well-formed formula and each set of symbols standing apart which contains a heavy type letter shall represent a well- formed formula. When writing particular well-formed formulas, we adopt the following abbreviations. A formula {F) (X) may be abbreviated as F(X) in any case where F is or is represented by a single symbol. A formula {{F) (X)) (Y) may be abbreviated as {F)(X, Y), or, if F is or is represented by a single symbol, as F(X, Y) . And {{{F) (X) ) (Y) ) ( 2 ) may be abbreviated as {F) (X, Y, Z), or as F(X, Y, Z), and so on. A formula Ax, [I&,[. . . Xx,[M] . . .]] may be abbreviated as Ax,x,. . . & .M or as Xx,x, . . . x,M. We also allow ourselves at any time to introduce abbreviations of the form that a particular symbol a shall stand for a particular sequence of symbols A, and indicate the introduction of such an abbreviation by the nota- tion a -+ A, to be read, " a stands for A." We introduce at once the following infinite list of abbreviations, 1 4hub. a(b), 2 -+ Xab . a(a(b)), 3 -+hub9 a(a(a(b))), and so on, each positive integer in Arabic notation standing for a formula of the form hab.a(a(. . .a(b) . . .)). The expression S>M I is used to stand for the result of substituting N for x throughout M. We consider the three following operations on well-formed formulas : I. To replace any part h [ M ] of a formula by hy[S;M I], where y is a variable which does not occur in M. 11. To replace any part {Ax[M]) (N) of a formula by S;;M I, provided that the bound variables in M are distinct both from x and from the free variables in N. 1 1 1 . To replace any part S;M I (not immediately following A) of a fornzula by {Ax [MI ) (N), provided that the bound variables in M are distinct both from x and from the free variables in N. Any finite sequence of these operations is called a conversion, and if B is obtainable from A by a conversion we say that A is convertible into B, or, " A conv B." If B is identical with A or is obtainable from A by a single 3 -+hub9 a(a(a(b))), and so on, each positive integer in Arabic notation standing for a formula of the form hab.a(a(. . .a(b) . . .)). The expression S>M I is used to stand for the result of substituting N for x throughout M. We consider the three following operations on well-formed formulas : I. To replace any part h [ M ] of a formula by hy[S;M I], where y is a variable which does not occur in M. 11. To replace any part {Ax[M]) (N) of a formula by S;;M I, provided that the bound variables in M are distinct both from x and from the free variables in N. 1 1 1 . To replace any part S;M I (not immediately following A) of a fornzula by {Ax [MI ) (N), provided that the bound variables in M are distinct both from x and from the free variables in N. Any finite sequence of these operations is called a conversion, and if B
  43. >> p = -> greeting { -> name { "#{greeting},

    #{name}!" } } => #<Proc (lambda)> >> p['Hello'] # -> name { "Hello, #{name}!" } => #<Proc (lambda)> >> p['Hello']['RubyConf'] => "Hello, RubyConf!"
  44. def replace(name, replacement, original) case original in Variable(^name) replacement in

    Variable original in Call Call.new( replace(name, replacement, original.receiver), replace(name, replacement, original.argument) ) in Definition(^name, _) original in Definition Definition.new( original.parameter, replace(name, replacement, original.body) ) end end
  45. def replace(name, replacement, original) case original in Variable(^name) replacement in

    Variable original in Call Call.new( replace(name, replacement, original.receiver), replace(name, replacement, original.argument) ) in Definition(^name, _) original in Definition Definition.new( original.parameter, replace(name, replacement, original.body) ) end end DANGER! I. To replace any part h [ M ] of a formula by hy[S;M I], where y is a variable which does not occur in M. 11. To replace any part {Ax[M]) (N) of a formula by S;;M I, provided that the bound variables in M are distinct both from x and from the free variables in N. 1 1 1 . To replace any part S;M I (not immediately following A) of a fornzula by {Ax [MI ) (N), provided that the bound variables in M are distinct both from x and from the free variables in N. Any finite sequence of these operations is called a conversion, and if B is obtainable from A by a conversion we say that A is convertible into B, or, " A conv B." If B is identical with A or is obtainable from A by a single
  46. >> a, b, c = [:a, :b, :c].map { |name|

    Variable.new(name) } => [a, b, c] >> expression = Call.new(Call.new(a, b), c) => a[b][c] >> replace(:b, from_proc(-> x { x }), expression) => a[-> x { x }][c] >> replace(:a, from_proc(-> x { x }), expression) => -> x { x }[b][c] >> replace(:c, from_proc(-> x { x }), expression) => a[b][-> x { x }]
  47. def value?(expression) case expression in Definition true else false end

    end def reduce(expression) case expression in Call(receiver, argument) unless value?(receiver) Call.new(reduce(receiver), argument) in Call(receiver, argument) unless value?(argument) Call.new(receiver, reduce(argument)) in Call(Definition(parameter, body), argument) replace(parameter, argument, body) end end and so on, each positive integer in Arabic notation standing for a formula of the form hab.a(a(. . .a(b) . . .)). The expression S>M I is used to stand for the result of substituting N for x throughout M. We consider the three following operations on well-formed formulas : I. To replace any part h [ M ] of a formula by hy[S;M I], where y is a variable which does not occur in M. 11. To replace any part {Ax[M]) (N) of a formula by S;;M I, provided that the bound variables in M are distinct both from x and from the free variables in N. 1 1 1 . To replace any part S;M I (not immediately following A) of a fornzula by {Ax [MI ) (N), provided that the bound variables in M are distinct both from x and from the free variables in N. Any finite sequence of these operations is called a conversion, and if B is obtainable from A by a conversion we say that A is convertible into B, or, " A conv B." If B is identical with A or is obtainable from A by a single
  48. >> add, one, two = from_proc(ADD), from_proc(ONE), from_proc(TWO) => [->

    m { -> n { n[-> n { -> p { -> x { p[n[p][x]] } } }][m] } }, -> p { -> x { p[x] } }, -> p { -> x { p[p[x]] } }] >> expression = Call.new(Call.new(add, one), two) => -> m { -> n { n[-> n { -> p { -> x { p[n[p][x]] } } }][m] } }[-> p { -> x { p[x] } }][-> p { -> x { p[p[x]] } }] >> expression = reduce(expression) => -> n { n[-> n { -> p { -> x { p[n[p][x]] } } }][-> p { -> x { p[x] } }] }[-> p { -> x { p[p[x]] } }] >> expression = reduce(expression) => -> p { -> x { p[p[x]] } }[-> n { -> p { -> x { p[n[p][x]] } } }][-> p { -> x { p[x] } }] >> expression = reduce(expression) => -> x { -> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[x]] }[-> p { -> x { p[x] } }] >> expression = reduce(expression) => -> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> p { -> x { p[x] } }]] >> expression = reduce(expression) => -> n { -> p { -> x { p[n[p][x]] } } }[-> p { -> x { p[-> p { -> x { p[x] } }[p][x]] } }] >> expression = reduce(expression) => -> p { -> x { p[-> p { -> x { p[-> p { -> x { p[x] } }[p][x]] } }[p][x]] } } >> expression = reduce(expression) in `reduce': #<struct Definition> (NoMatchingPatternError)
  49. def evaluate(expression) loop do expression = reduce(expression) rescue NoMatchingPatternError return

    expression end end
  50. >> add, one, two = from_proc(ADD), from_proc(ONE), from_proc(TWO) => [->

    m { -> n { n[-> n { -> p { -> x { p[n[p][x]] } } }][m] } }, -> p { -> x { p[x] } }, -> p { -> x { p[p[x]] } }] >> expression = Call.new(Call.new(add, one), two) => -> m { -> n { n[-> n { -> p { -> x { p[n[p][x]] } } }][m] } }[-> p { -> x { p[x] } }][-> p { -> x { p[p[x]] } }] >> expression = evaluate(expression) => -> p { -> x { p[-> p { -> x { p[-> p { -> x { p[x] } }[p][x]] } }[p][x]] } }
  51. Could we represent these encoded values ourselves? Could we evaluate

    these encoded values ourselves? Could we decode these encoded values ourselves?
  52. >> add, one, two = from_proc(ADD), from_proc(ONE), from_proc(TWO) => [->

    m { -> n { n[-> n { -> p { -> x { p[n[p][x]] } } }][m] } }, -> p { -> x { p[x] } }, -> p { -> x { p[p[x]] } }] >> expression = Call.new(Call.new(add, one), two) => -> m { -> n { n[-> n { -> p { -> x { p[n[p][x]] } } }][m] } }[-> p { -> x { p[x] } }][-> p { -> x { p[p[x]] } }] >> expression = evaluate(expression) => -> p { -> x { p[-> p { -> x { p[-> p { -> x { p[x] } }[p][x]] } }[p][x]] } } >> three = from_proc(THREE) => -> p { -> x { p[p[p[x]]] } } !
  53. Variable = Struct.new(:name) do def inspect = "#{name}" end Call

    = Struct.new(:receiver, :argument) do def inspect = "#{receiver.inspect}[#{argument.inspect}]" end Definition = Struct.new(:parameter, :body) do def inspect = "-> #{parameter} { #{body.inspect} }" end Constant = Struct.new(:name) do def inspect = "#{name}" end
  54. def value?(expression) case expression in Definition | Constant true in

    Call(Constant, argument) if value?(argument) true else false end end
  55. >> add, one, two = from_proc(ADD), from_proc(ONE), from_proc(TWO) => [->

    m { -> n { n[-> n { -> p { -> x { p[n[p][x]] } } }][m] } }, -> p { -> x { p[x] } }, -> p { -> x { p[p[x]] } }] >> expression = Call.new(Call.new(add, one), two) => -> m { -> n { n[-> n { -> p { -> x { p[n[p][x]] } } }][m] } }[-> p { -> x { p[x] } }][-> p { -> x { p[p[x]] } }] >> expression = evaluate(expression) => -> p { -> x { p[-> p { -> x { p[-> p { -> x { p[x] } }[p][x]] } }[p][x]] } } >> expression = Call.new(Call.new(expression, Constant.new('INCREMENT')), Constant.new('ZERO')) => -> p { -> x { p[-> p { -> x { p[-> p { -> x { p[x] } }[p][x]] } }[p][x]] } }[INCREMENT][ZERO] >> evaluate(expression) => INCREMENT[INCREMENT[INCREMENT[ZERO]]]
  56. def to_integer(n) increment = Constant.new('INCREMENT') zero = Constant.new('ZERO') expression =

    evaluate(Call.new(Call.new(n, increment), zero)) identify_integer(expression, increment, zero) end def identify_integer(expression, increment, zero) integer = 0 loop do case expression in Call(^increment, expression) integer += 1 in ^zero return integer end end end
  57. >> add, one, two = from_proc(ADD), from_proc(ONE), from_proc(TWO) => [->

    m { -> n { n[-> n { -> p { -> x { p[n[p][x]] } } }][m] } }, -> p { -> x { p[x] } }, -> p { -> x { p[p[x]] } }] >> expression = Call.new(Call.new(add, one), two) => -> m { -> n { n[-> n { -> p { -> x { p[n[p][x]] } } }][m] } }[-> p { -> x { p[x] } }][-> p { -> x { p[p[x]] } }] >> to_integer(expression) => 3
  58. Could we represent these encoded values ourselves? Yes. Could we

    evaluate these encoded values ourselves? Yes. Could we decode these encoded values ourselves? Yes.
  59. Could we make this faster?

  60. The mechanical evaluation of expressions By P. J. Landin This

    paper is a contribution to the "theory" of the activity of using computers. It shows how some forms of expression used in current programming languages can be modelled in Church's X-notation, and then describes a way of "interpreting" such expressions. This suggests a method, of analyzing the things computer users write, that applies to many different problem orientations and to different phases of the activity of using a computer. Also a technique is introduced by which the various composite information structures involved can be formally characterized in their essentials, without commitment to specific written or other representations. Introduction The point of departure of this paper is the idea of a machine for evaluating schoolroom sums, such as 1. (3 + 4)(5 + 6)(7 + 8) 2. if 219 < 312 then 12V2 else 5 V 2 17 cos n/l7 ~ "V^1 ~ 1 7 sin 3 If l7 cos TT/17 + V(l + 17 sin Any experienced computer user knows that his activity scarcely resembles giving a machine a numerical expression and waiting for the answer. He is involved with flow diagrams, with replacement and sequencing, with programs, data and jobs, and with input and output. There are good reasons why current information- processing systems are ill-adapted to doing sums. Nevertheless, the questions arise: Is there any way of extending the notion of "sums" so as to serve some of the needs of computer users without all the elaborations of using computers? Are there features of "sums" that correspond to such characteristically computerish con- cepts as flow diagrams, jobs, output, etc.? This paper is an introduction to a current attempt to provide affirmative answers to these questions. It leaves many gaps, gets rather cursory towards the end and, even so, does not take the development very far. It is hoped that further piecemeal reports, putting right these defects, will appear elsewhere. Expressions Applicative structure Many symbolic expressions can be characterized by their "operator/operand" structure. For instance al(2b + 3) can be characterized as the expression whose operator is V and whose two operands are respectively 'a,' and the expression whose operator is ' + ' and whose two operands are respectively the expression whose operator is ' x ' and whose two operands are respectively '2' and '6,' and '3.' Operator/operand structure, or "applica- tive" structure, as it will be called here, can be exhibited more clearly by using a notation in which each operator is written explicitly and prefixed to its operand(s), and each operand (or operand-list) is enclosed in brackets, e.g. /(a,+(x(2,6),3)). This notation is a sort of standard notation in which all the expressions in this paper could (with some loss of legibility) be rendered. The following remarks about applicative structure will be illustrated by examples in -which an expression is written in two ways: on the left in some notation whose applicative structure is being discussed, and on the right in a form that displays the applicative structure more explicitly, e.g. /(fl, a/(2b + 3) (a + 3)(6 - 4) + (c-5)(d-6) In both these examples the right-hand version is in the "standard" notation. In most of the illustrations that follow, the right-hand version will not adhere rigorously to the standard notation. The particular point illus- trated by each example will be more clearly emphasized if irrelevant features of the left-hand version are carried over in non-standard form. Thus the applicative structure of subscripts is illustrated by Oib,, a{j)b(J,k). Some familiar expressions have features that offer several alternative applicative structures, with no obvious criterion by which to choose between them. For example 3 + 4 + 5 + 6 f +(+(+(3, 4), 5), 6) \ +(3, +(4, +(5, 6))) [£'(3,4,5,6) where 2' is taken to be a function that operates on a list of numbers and produces their sum. Again / t («. 2) \ square (a) where t is taken to be exponentiation. 308 Downloaded from https://academic.oup.com/comjnl/article/6/4/308/375725 by guest on 01 October 2021
  61. Mechanical evaluation the A-expression and the environment relative to which

    it was evaluated. We must therefore arrange that such a bundle is correctly interpreted whenever it has to be applied to some argument. More precisely: a closure has an environment part which is a list whose two items are: (1) an environment (2) an identifier or list of identifiers, and a control part which consists of a list whose sole item is an AE. The value relative to E of a A-expression X is represented by the closure denoted by constructclosure((E, bvX), unitlist(bodyX)). This particular arrangement of the information in a closure has been chosen for our later convenience. We now describe a "mechanization" of evaluation in the following sense. We define a class of COs, called "states," constructed out of AEs and their values; and we define a "transition" rule whose successive application starting at a "state" that contains an environment E and an AE X (in a certain arrangement), leads eventually to a "state" that contains (in a certain position) either valEX or a closure representing valEX. (We use the phrase "result of evaluation" to cover both objects and closures. We suppose that the identifier closure designates a predicate that detects whether or not a given result of evaluation is a closure.) A state consists of a stack, which is a list, each of whose items is an intermediate result of evaluation, awaiting subsequent use; and an environment, which is a list-structure made up of name/value pairs; and a control, which is a list, each of whose items is either an AE awaiting evaluation, or a special object designated by 'ap,' distinct from all AEs; and a dump, which is a complete state, i.e. com- prising four components as listed here. We denote a state thus: (S, E, C, D). The environment-part (both of states and of closures) would be unnecessary if A-expressions containing free variables were prohibited. Also the dump would be unnecessary if all A-expressions were prohibited. Each step of evaluation is completely determined by the current state (S, E, C, D) in the following way: 1. If C is null, suppose the current dump D is (S\ E', C, D'). Then the current state is replaced by the state denoted by (hS : S', E', C, £>')• 2. If C is not null, then hC is inspected, and: (2a) If hC is an identifier X (whose value relative to E occupies the position locationEX in E), then S is replaced by locationEXE : 5 and C is replaced by tC. We describe this step as follows: "Scanning X causes locationEXE to be loaded." (2b) If hC is a A-expression X, scanning it causes the closure derived from E and X (as indicated above) to be loaded on to the stack. (2c) If hC is ap, scanning it changes £ as follows: hS is inspected and: (2cl) If hS is a closure, derived from E' and X', then: S is replaced by the nullist, E is replaced by derive(assoc(bvX', 2ndS))E', C is replaced by unitlist(bodyX'), D is replaced by (t(tS), E, tC, D). (2c2) If hS is not a closure, then scanning ap causes S to be replaced by ((1st S)(lnd S) : t(tS)). (2d) If hC is a combination X, C is replaced by randX : (ratorX : (ap : tC)). Formally this transformation of one state into another is Transform(S,E,C,D) = nullC->[hS:S',E',C,D'] where S',E',C,D' = D else-*- identifierX-+ [locationEXE:S, E, tC, D] [constructclosure((E, bvX),unitlist(bodyX)) :S, E, tC, D] X = ap-> closure(hS) -> [(), derive{assoc(J,2ndS)E'), C, (t(tS), E, tC, D)] where E',J = environmentparl(hS) and C" = controlpart(hS) else->[(lstS)(2nd):t(tS), E, tC, D] else-*- [S, E, randX:(ratorX:(ap:tC)), D] where X — hC We assume here that an AE composed of a single identifier is the same object as the identifier itself. This suggests a more general assumption that whenever one of the alternative formats of a structure definition has just one component, the corresponding selector and constructor are both merely the identity function. We also assume that a state is identical to a list of its four components. This suggests a more general assumption that whenever a structure definition allows just one format, the constructor is the identity function. Without these assumptions the above definition would be a bit more 317 Downloaded from https://academic.oup.com/comjnl/article/6/4/308/375725 by guest on 01 October 2021 Mechanical evaluation the A-expression and the environment relative to which it was evaluated. We must therefore arrange that such a bundle is correctly interpreted whenever it has to be applied to some argument. More precisely: a closure has an environment part which is a list whose two items are: (1) an environment (2) an identifier or list of identifiers, and a control part which consists of a list whose sole item is an AE. The value relative to E of a A-expression X is represented by the closure denoted by constructclosure((E, bvX), unitlist(bodyX)). This particular arrangement of the information in a closure has been chosen for our later convenience. We now describe a "mechanization" of evaluation in the following sense. We define a class of COs, called "states," constructed out of AEs and their values; and we define a "transition" rule whose successive application starting at a "state" that contains an environment E and an AE X (in a certain arrangement), leads eventually to a "state" that contains (in a certain position) either valEX or a closure representing valEX. (We use the phrase "result of evaluation" to cover both objects and closures. We suppose that the identifier closure designates a predicate that detects whether or not a given result of evaluation is a closure.) A state consists of a stack, which is a list, each of whose items is an intermediate result of evaluation, awaiting subsequent use; and an environment, which is a list-structure made up of name/value pairs; and a control, which is a list, each of whose items is either an AE awaiting evaluation, or a special object designated by 'ap,' distinct from all AEs; and a dump, which is a complete state, i.e. com- prising four components as listed here. We denote a state thus: (S, E, C, D). The environment-part (both of states and of closures) would be unnecessary if A-expressions containing free variables were prohibited. Also the dump would be unnecessary if all A-expressions were prohibited. Each step of evaluation is completely determined by the current state (S, E, C, D) in the following way: 1. If C is null, suppose the current dump D is (S\ E', C, D'). Then the current state is replaced by the state denoted by (hS : S', E', C, £>')• 2. If C is not null, then hC is inspected, and: (2a) If hC is an identifier X (whose value relative to E occupies the position locationEX in E), then S is replaced by locationEXE : 5 and C is replaced by tC. We describe this step as follows: "Scanning X causes locationEXE to be loaded." (2b) If hC is a A-expression X, scanning it causes the closure derived from E and X (as indicated above) to be loaded on to the stack. (2c) If hC is ap, scanning it changes £ as follows: hS is inspected and: (2cl) If hS is a closure, derived from E' and X', then: S is replaced by the nullist, E is replaced by derive(assoc(bvX', 2ndS))E', C is replaced by unitlist(bodyX'), D is replaced by (t(tS), E, tC, D). (2c2) If hS is not a closure, then scanning ap causes S to be replaced by ((1st S)(lnd S) : t(tS)). (2d) If hC is a combination X, C is replaced by randX : (ratorX : (ap : tC)). Formally this transformation of one state into another is Transform(S,E,C,D) = nullC->[hS:S',E',C,D'] where S',E',C,D' = D else-*- identifierX-+ [locationEXE:S, E, tC, D] [constructclosure((E, bvX),unitlist(bodyX)) :S, E, tC, D] X = ap-> closure(hS) -> [(), derive{assoc(J,2ndS)E'), C, (t(tS), E, tC, D)] where E',J = environmentparl(hS) and C" = controlpart(hS) else->[(lstS)(2nd):t(tS), E, tC, D] else-*- [S, E, randX:(ratorX:(ap:tC)), D] where X — hC We assume here that an AE composed of a single identifier is the same object as the identifier itself. This suggests a more general assumption that whenever one of the alternative formats of a structure definition has just one component, the corresponding selector and constructor are both merely the identity function. We also assume that a state is identical to a list of its four components. This suggests a more general assumption that whenever a structure definition allows just one format, the constructor is the identity function. Without these assumptions the above definition would be a bit more 317 Downloaded from https://academic.oup.com/comjnl/article/6/4/308/375725 by guest on 01 October 2021 valEX or a closure representing valEX. (We use the phrase "result of evaluation" to cover both objects and closures. We suppose that the identifier closure designates a predicate that detects whether or not a given result of evaluation is a closure.) A state consists of a stack, which is a list, each of whose items is an intermediate result of evaluation, awaiting subsequent use; and an environment, which is a list-structure made up of name/value pairs; and a control, which is a list, each of whose items is either an AE awaiting evaluation, or a special object designated by 'ap,' distinct from all AEs; and a dump, which is a complete state, i.e. com- prising four components as listed here. We denote a state thus: (S, E, C, D). The environment-part (both of states and of closures) would be unnecessary if A-expressions containing free variables were prohibited. Also the dump would be unnecessary if all A-expressions were prohibited. Each step of evaluation is completely determined by (2d) If hC is a com randX : (rator Formally this transforma Transform(S,E,C,D) = nullC->[hS:S',E',C,D'] where S',E',C,D else-*- identifierX-+ [locatio [constructclosure( E, tC, D] X = ap-> closure(hS [(), der C, (t(tS where E and C else->[(ls else-*- [S, E, randX:( where X — hC We assume here that identifier is the same obje suggests a more general a
  62. Mechanical evaluation the A-expression and the environment relative to which

    it was evaluated. We must therefore arrange that such a bundle is correctly interpreted whenever it has to be applied to some argument. More precisely: a closure has an environment part which is a list whose two items are: (1) an environment (2) an identifier or list of identifiers, and a control part which consists of a list whose sole item is an AE. The value relative to E of a A-expression X is represented by the closure denoted by constructclosure((E, bvX), unitlist(bodyX)). This particular arrangement of the information in a closure has been chosen for our later convenience. We now describe a "mechanization" of evaluation in the following sense. We define a class of COs, called "states," constructed out of AEs and their values; and we define a "transition" rule whose successive application starting at a "state" that contains an environment E and an AE X (in a certain arrangement), leads eventually to a "state" that contains (in a certain position) either valEX or a closure representing valEX. (We use the phrase "result of evaluation" to cover both objects and closures. We suppose that the identifier closure designates a predicate that detects whether or not a given result of evaluation is a closure.) A state consists of a stack, which is a list, each of whose items is an intermediate result of evaluation, awaiting subsequent use; and an environment, which is a list-structure made up of name/value pairs; and a control, which is a list, each of whose items is either an AE awaiting evaluation, or a special object designated by 'ap,' distinct from all AEs; and a dump, which is a complete state, i.e. com- prising four components as listed here. We denote a state thus: (S, E, C, D). The environment-part (both of states and of closures) would be unnecessary if A-expressions containing free variables were prohibited. Also the dump would be unnecessary if all A-expressions were prohibited. Each step of evaluation is completely determined by the current state (S, E, C, D) in the following way: 1. If C is null, suppose the current dump D is (S\ E', C, D'). Then the current state is replaced by the state denoted by (hS : S', E', C, £>')• 2. If C is not null, then hC is inspected, and: (2a) If hC is an identifier X (whose value relative to E occupies the position locationEX in E), then S is replaced by locationEXE : 5 and C is replaced by tC. We describe this step as follows: "Scanning X causes locationEXE to be loaded." (2b) If hC is a A-expression X, scanning it causes the closure derived from E and X (as indicated above) to be loaded on to the stack. (2c) If hC is ap, scanning it changes £ as follows: hS is inspected and: (2cl) If hS is a closure, derived from E' and X', then: S is replaced by the nullist, E is replaced by derive(assoc(bvX', 2ndS))E', C is replaced by unitlist(bodyX'), D is replaced by (t(tS), E, tC, D). (2c2) If hS is not a closure, then scanning ap causes S to be replaced by ((1st S)(lnd S) : t(tS)). (2d) If hC is a combination X, C is replaced by randX : (ratorX : (ap : tC)). Formally this transformation of one state into another is Transform(S,E,C,D) = nullC->[hS:S',E',C,D'] where S',E',C,D' = D else-*- identifierX-+ [locationEXE:S, E, tC, D] [constructclosure((E, bvX),unitlist(bodyX)) :S, E, tC, D] X = ap-> closure(hS) -> [(), derive{assoc(J,2ndS)E'), C, (t(tS), E, tC, D)] where E',J = environmentparl(hS) and C" = controlpart(hS) else->[(lstS)(2nd):t(tS), E, tC, D] else-*- [S, E, randX:(ratorX:(ap:tC)), D] where X — hC We assume here that an AE composed of a single identifier is the same object as the identifier itself. This suggests a more general assumption that whenever one of the alternative formats of a structure definition has just one component, the corresponding selector and constructor are both merely the identity function. We also assume that a state is identical to a list of its four components. This suggests a more general assumption that whenever a structure definition allows just one format, the constructor is the identity function. Without these assumptions the above definition would be a bit more 317 Downloaded from https://academic.oup.com/comjnl/article/6/4/308/375725 by guest on 01 October 2021 Mechanical evaluation the A-expression and the environment relative to which it was evaluated. We must therefore arrange that such a bundle is correctly interpreted whenever it has to be applied to some argument. More precisely: a closure has an environment part which is a list whose two items are: (1) an environment (2) an identifier or list of identifiers, and a control part which consists of a list whose sole item is an AE. The value relative to E of a A-expression X is represented by the closure denoted by constructclosure((E, bvX), unitlist(bodyX)). This particular arrangement of the information in a closure has been chosen for our later convenience. We now describe a "mechanization" of evaluation in the following sense. We define a class of COs, called "states," constructed out of AEs and their values; and we define a "transition" rule whose successive application starting at a "state" that contains an environment E and an AE X (in a certain arrangement), leads eventually to a "state" that contains (in a certain position) either valEX or a closure representing valEX. (We use the phrase "result of evaluation" to cover both objects and closures. We suppose that the identifier closure designates a predicate that detects whether or not a given result of evaluation is a closure.) A state consists of a stack, which is a list, each of whose items is an intermediate result of evaluation, awaiting subsequent use; and an environment, which is a list-structure made up of name/value pairs; and a control, which is a list, each of whose items is either an AE awaiting evaluation, or a special object designated by 'ap,' distinct from all AEs; and a dump, which is a complete state, i.e. com- prising four components as listed here. We denote a state thus: (S, E, C, D). The environment-part (both of states and of closures) would be unnecessary if A-expressions containing free variables were prohibited. Also the dump would be unnecessary if all A-expressions were prohibited. Each step of evaluation is completely determined by the current state (S, E, C, D) in the following way: 1. If C is null, suppose the current dump D is (S\ E', C, D'). Then the current state is replaced by the state denoted by (hS : S', E', C, £>')• 2. If C is not null, then hC is inspected, and: (2a) If hC is an identifier X (whose value relative to E occupies the position locationEX in E), then S is replaced by locationEXE : 5 and C is replaced by tC. We describe this step as follows: "Scanning X causes locationEXE to be loaded." (2b) If hC is a A-expression X, scanning it causes the closure derived from E and X (as indicated above) to be loaded on to the stack. (2c) If hC is ap, scanning it changes £ as follows: hS is inspected and: (2cl) If hS is a closure, derived from E' and X', then: S is replaced by the nullist, E is replaced by derive(assoc(bvX', 2ndS))E', C is replaced by unitlist(bodyX'), D is replaced by (t(tS), E, tC, D). (2c2) If hS is not a closure, then scanning ap causes S to be replaced by ((1st S)(lnd S) : t(tS)). (2d) If hC is a combination X, C is replaced by randX : (ratorX : (ap : tC)). Formally this transformation of one state into another is Transform(S,E,C,D) = nullC->[hS:S',E',C,D'] where S',E',C,D' = D else-*- identifierX-+ [locationEXE:S, E, tC, D] [constructclosure((E, bvX),unitlist(bodyX)) :S, E, tC, D] X = ap-> closure(hS) -> [(), derive{assoc(J,2ndS)E'), C, (t(tS), E, tC, D)] where E',J = environmentparl(hS) and C" = controlpart(hS) else->[(lstS)(2nd):t(tS), E, tC, D] else-*- [S, E, randX:(ratorX:(ap:tC)), D] where X — hC We assume here that an AE composed of a single identifier is the same object as the identifier itself. This suggests a more general assumption that whenever one of the alternative formats of a structure definition has just one component, the corresponding selector and constructor are both merely the identity function. We also assume that a state is identical to a list of its four components. This suggests a more general assumption that whenever a structure definition allows just one format, the constructor is the identity function. Without these assumptions the above definition would be a bit more 317 Downloaded from https://academic.oup.com/comjnl/article/6/4/308/375725 by guest on 01 October 2021 ng valEX. (We use the o cover both objects and t the identifier closure etects whether or not a closure.) which is a list, each of n intermediate result of g subsequent use; hich is a list-structure made airs; a list, each of whose items waiting evaluation, or a ignated by 'ap,' distinct complete state, i.e. com- nents as listed here. D). of states and of closures) xpressions containing free Also the dump would be s were prohibited. completely determined by (2d) If hC is a combination X, C is replaced by randX : (ratorX : (ap : tC)). Formally this transformation of one state into another is Transform(S,E,C,D) = nullC->[hS:S',E',C,D'] where S',E',C,D' = D else-*- identifierX-+ [locationEXE:S, E, tC, D] [constructclosure((E, bvX),unitlist(bodyX)) :S, E, tC, D] X = ap-> closure(hS) -> [(), derive{assoc(J,2ndS)E'), C, (t(tS), E, tC, D)] where E',J = environmentparl(hS) and C" = controlpart(hS) else->[(lstS)(2nd):t(tS), E, tC, D] else-*- [S, E, randX:(ratorX:(ap:tC)), D] where X — hC We assume here that an AE composed of a single identifier is the same object as the identifier itself. This suggests a more general assumption that whenever one m/comjnl/article/6/4/308/375725 by guest on 01 October 2021
  63. evaluate: -> x { ????? }[ ????? ] environment: x

    = ????? body: ????? result: evaluate ????? in environment { x = ????? }
  64. evaluate: -> x { ????? } in environment { ?????

    } environment: { ????? } definition: -> x { ????? } result: closure(-> x { ????? }, { ????? })
  65. Apply = Object.new Closure = Struct.new(:environment, :definition) def evaluate(expression) s,

    e, c, d = [], {}, [expression], nil loop do case { s: s, c: c, d: d } in c: [], d: nil, s: [result, *] return result in c: [], d: { s: s, e: e, c: c, d: d }, s: [result, *] s = [result] + s in c: [Variable(name), *c] s = [e.fetch(name)] + s in c: [Definition => definition, *c] s = [Closure.new(e, definition)] + s in c: [Closure => closure, *c] s = [closure] + s in c: [Constant => constant, *c] s = [constant] + s in c: [Apply, *c], s: [Closure(environment, Definition(parameter, body)), argument, *s] d = { s: s, e: e, c: c, d: d } s, e, c = [], environment.merge(parameter => argument), [body] in c: [Apply, *c], s: [receiver, argument, *s] s = [Call.new(receiver, argument)] + s in c: [Call(receiver, argument), *c] c = [argument, receiver, Apply] + c end end end closures. We suppose that the identifier closure designates a predicate that detects whether or not a given result of evaluation is a closure.) A state consists of a stack, which is a list, each of whose items is an intermediate result of evaluation, awaiting subsequent use; and an environment, which is a list-structure made up of name/value pairs; and a control, which is a list, each of whose items is either an AE awaiting evaluation, or a special object designated by 'ap,' distinct from all AEs; and a dump, which is a complete state, i.e. com- prising four components as listed here. We denote a state thus: (S, E, C, D). The environment-part (both of states and of closures) would be unnecessary if A-expressions containing free variables were prohibited. Also the dump would be unnecessary if all A-expressions were prohibited. Each step of evaluation is completely determined by the current state (S, E, C, D) in the following way: 1. If C is null, suppose the current dump D is (S\ E', C, D'). Then the current state is replaced by the state denoted by (hS : S', E', C, £>')• Formally this transformation of one state into another is Transform(S,E,C,D) = nullC->[hS:S',E',C,D'] where S',E',C,D' = D else-*- identifierX-+ [locationEXE:S, E, tC, D] [constructclosure((E, bvX),unitlist(bodyX)) :S, E, tC, D] X = ap-> closure(hS) -> [(), derive{assoc(J,2ndS)E'), C, (t(tS), E, tC, D)] where E',J = environmentparl(hS) and C" = controlpart(hS) else->[(lstS)(2nd):t(tS), E, tC, D] else-*- [S, E, randX:(ratorX:(ap:tC)), D] where X — hC We assume here that an AE composed of a single identifier is the same object as the identifier itself. This suggests a more general assumption that whenever one of the alternative formats of a structure definition has just one component, the corresponding selector and constructor are both merely the identity function. We also assume that a state is identical to a list of its four components. This suggests a more general assumption that whenever a structure definition allows just one format, the constructor is the identity function. Without these assumptions the above definition would be a bit more 317
  66. def evaluate(expression) s, e, c, d = [], {}, [expression],

    nil loop do if c.empty? result = s.pop return result if d.nil? s, e, c, d = d.values_at(:s, :e, :c, :d) s.push(result) else case c.pop in Variable(name) s.push(e.fetch(name)) in Definition => definition s.push(Closure.new(e, definition)) in Closure => closure s.push(closure) in Constant => constant s.push(constant) in Apply case s.pop in Closure(environment, Definition(parameter, body)) d = { s: s, e: e, c: c, d: d } s, e, c = [], environment.merge(parameter => s.pop), [body] in receiver s.push(Call.new(receiver, s.pop)) end in Call(receiver, argument) c.push(Apply, receiver, argument) end end end end
  67. Could we make this fasterer?

  68. struct Expression { enum { Variable, Call, Definition, Closure, Constant

    } type; union { struct { char *name; } variable, constant; struct { struct Expression *receiver; struct Expression *argument; } call; struct { char *parameter; struct Expression *body; } definition; struct { struct Environment *environment; char *parameter; struct Expression *body; } closure; }; }; struct Stack { struct Expression *expression; struct Stack *rest; }; struct Environment { char *name; struct Expression *expression; struct Environment *rest; }; struct Control { enum { Expression, Apply } type; struct Expression *expression; struct Control *rest; }; struct Dump { struct Stack *s; struct Environment *e; struct Control *c; struct Dump *d; };
  69. struct Expression * evaluate (struct Expression *expression) { struct Stack

    *s = NULL; struct Environment *e = NULL; struct Control *c = push_control(NULL, Expression, expression); struct Dump *d = NULL; while (1) { if (c == NULL) { struct Expression *result = pop_stack(&s); if (d == NULL) return result; pop_dump(&s, &e, &c, &d); s = push_stack(s, result); } else { switch (c->type) { case Expression: { struct Expression *expression = pop_control(&c); switch (expression->type) { case Variable: s = push_stack(s, lookup(e, expression->variable.name)); break; case Definition: s = push_stack(s, build_closure(e, expression->definition.parameter, expression->definition.body)); break;
  70. s = push_stack(s, result); } else { switch (c->type) {

    case Expression: { struct Expression *expression = pop_control(&c); switch (expression->type) { case Variable: s = push_stack(s, lookup(e, expression->variable.name)); break; case Definition: s = push_stack(s, build_closure(e, expression->definition.parameter, expression->definition.body)); break; case Closure: case Constant: s = push_stack(s, expression); break; case Call: c = push_control(c, Apply, NULL); c = push_control(c, Expression, expression->call.receiver); c = push_control(c, Expression, expression->call.argument); break; } } break;
  71. } } break; case Apply: { pop_control(&c); struct Expression *receiver

    = pop_stack(&s); struct Expression *argument = pop_stack(&s); switch (receiver->type) { case Closure: d = push_dump(s, e, c, d); s = NULL; e = push_environment(receiver->closure.environment, receiver->closure.parameter, argument); c = push_control(NULL, Expression, receiver->closure.body); break; default: s = push_stack(s, build_call(receiver, argument)); break; } } break; } } } }
  72. module SECD extend FFI::Library ffi_lib 'secd.so' enum :types, [:variable, :call,

    :definition, :closure, :constant] class Expression < FFI::Struct class Data < FFI::Union class Named < FFI::Struct layout name: :string end class Call < FFI::Struct layout receiver: Expression.ptr, argument: Expression.ptr end class Definition < FFI::Struct layout parameter: :string, body: Expression.ptr end class Closure < FFI::Struct layout environment: :pointer, parameter: :string, body: Expression.ptr end layout variable: Named, call: Call, definition: Definition, closure: Closure, constant: Named end layout type: :types, data: Data end attach_function :evaluate, [Expression.by_ref], Expression.by_ref end
  73. Could we make this fasterer? Yes. Could we make this

    faster? Yes.
  74. Time to run FizzBuzz 0 30m 1h 1h 30m 2h

    Ruby procs AST interpreter SECD in Ruby SECD in C
  75. Time to run FizzBuzz 0 1m 2m 3m 4m Ruby

    procs AST interpreter SECD in Ruby SECD in C
  76. Could we make this fastererer? Not right now… but yes.

  77. WHY

  78. Why?

  79. tomstuart / something

  80. Tom Stuart @ Shopify, RubyConf 2021 Thanks. https://tomstu.art/programming-with-something