Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

Ten years ago…

Slide 3

Slide 3 text

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

Slide 4

Slide 4 text

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

Slide 5

Slide 5 text

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]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]] ]]]]]]]]]]]]]]]]]]]]]]]]]]]]] } }

Slide 6

Slide 6 text

>> THREE[-> n { n + 1 }][0] => 3 >> HUNDRED[-> n { n + 1 }][0] => 100 >> ZERO[-> n { n + 1 }][0] => 0

Slide 7

Slide 7 text

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] } }

Slide 8

Slide 8 text

>> EIGHT = ADD[FIVE][THREE] => # >> EIGHT[-> n { n + 1 }][0] => 8 >> POWER[TWO][EIGHT][-> n { n + 1 }][0] => 256

Slide 9

Slide 9 text

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]] }

Slide 10

Slide 10 text

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]] } } ] } }

Slide 11

Slide 11 text

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] ]]] }]

Slide 12

Slide 12 text

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]]]] }]

Slide 13

Slide 13 text

Ten years later…

Slide 14

Slide 14 text

Could we represent these encoded values ourselves? Could we evaluate these encoded values ourselves? Could we decode these encoded values ourselves?

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

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]]]] }]

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

>> variable = Variable.new(:x) => x >> call = Call.new(variable, variable) => x[x] >> definition = Definition.new(:x, call) => -> x { x[x] }

Slide 23

Slide 23 text

>> 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) ) ) ) ) )

Slide 24

Slide 24 text

: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

Slide 25

Slide 25 text

-> 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) ) ) ) ) )

Slide 26

Slide 26 text

>> instructions = RubyVM::InstructionSequence.of(-> p { -> x { p[p[p[x]]] } }) => @(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 ", "(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 ", "(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]]]

Slide 27

Slide 27 text

>> instructions = RubyVM::InstructionSequence.of(-> p { -> x { p[p[p[x]]] } }) => @(irb):1> >> puts instructions.disassemble == disasm: #@(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 0000 nop ( 1)[Bc] 0001 putspecialobject 1[Li] 0003 send , block (2 levels) in 0006 nop 0007 leave ( 1)[Br] == disasm: #@(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,

Slide 28

Slide 28 text

[ 1] p@0 0000 nop ( 1)[Bc] 0001 putspecialobject 1[Li] 0003 send , block (2 levels) in 0006 nop 0007 leave ( 1)[Br] == disasm: #@(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 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 0011 opt_aref 0013 opt_aref 0015 nop 0016 leave ( 1)[Br] => nil

Slide 29

Slide 29 text

$ 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"

Slide 30

Slide 30 text

>> 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]]]]]]]]]

Slide 31

Slide 31 text

>> THREE = -> p { -> x { p[p[p[x]]] } } => # >> THREE.parameters => [[:req, :p]] >> parameter = THREE.parameters[0][1] => :p >> body = # ???

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

>> OMEGA = -> x { x[x] } => # >> 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]

Slide 34

Slide 34 text

>> THREE = -> p { -> x { p[p[p[x]]] } } => # >> variable = Variable.new(THREE.parameters[0][1]) => p >> body = THREE.call(variable) => # >> variable = Variable.new(body.parameters[0][1]) => x >> body.call(variable) => p[p[p[x]]]

Slide 35

Slide 35 text

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

Slide 36

Slide 36 text

[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

Slide 37

Slide 37 text

>> THREE => # >> from_proc(THREE) => -> p { -> x { p[p[p[x]]] } } >> from_proc(THREE).class => Definition >> FIZZBUZZ => # >> 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

Slide 38

Slide 38 text

Could we represent these encoded values ourselves? Could we evaluate these encoded values ourselves? Could we decode these encoded values ourselves?

Slide 39

Slide 39 text

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

Slide 40

Slide 40 text

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

Slide 41

Slide 41 text

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

Slide 42

Slide 42 text

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

Slide 43

Slide 43 text

>> p = -> greeting { -> name { "#{greeting}, #{name}!" } } => # >> p['Hello'] # -> name { "Hello, #{name}!" } => # >> p['Hello']['RubyConf'] => "Hello, RubyConf!"

Slide 44

Slide 44 text

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

Slide 45

Slide 45 text

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

Slide 46

Slide 46 text

>> 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 }]

Slide 47

Slide 47 text

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

Slide 48

Slide 48 text

>> 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': # (NoMatchingPatternError)

Slide 49

Slide 49 text

def evaluate(expression) loop do expression = reduce(expression) rescue NoMatchingPatternError return expression end end

Slide 50

Slide 50 text

>> 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]] } }

Slide 51

Slide 51 text

Could we represent these encoded values ourselves? Could we evaluate these encoded values ourselves? Could we decode these encoded values ourselves?

Slide 52

Slide 52 text

>> 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]]] } } !

Slide 53

Slide 53 text

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

Slide 54

Slide 54 text

def value?(expression) case expression in Definition | Constant true in Call(Constant, argument) if value?(argument) true else false end end

Slide 55

Slide 55 text

>> 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]]]

Slide 56

Slide 56 text

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

Slide 57

Slide 57 text

>> 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

Slide 58

Slide 58 text

Could we represent these encoded values ourselves? Yes. Could we evaluate these encoded values ourselves? Yes. Could we decode these encoded values ourselves? Yes.

Slide 59

Slide 59 text

Could we make this faster?

Slide 60

Slide 60 text

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

Slide 61

Slide 61 text

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

Slide 62

Slide 62 text

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

Slide 63

Slide 63 text

evaluate: -> x { ????? }[ ????? ] environment: x = ????? body: ????? result: evaluate ????? in environment { x = ????? }

Slide 64

Slide 64 text

evaluate: -> x { ????? } in environment { ????? } environment: { ????? } definition: -> x { ????? } result: closure(-> x { ????? }, { ????? })

Slide 65

Slide 65 text

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

Slide 66

Slide 66 text

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

Slide 67

Slide 67 text

Could we make this fasterer?

Slide 68

Slide 68 text

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; };

Slide 69

Slide 69 text

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;

Slide 70

Slide 70 text

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;

Slide 71

Slide 71 text

} } 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; } } } }

Slide 72

Slide 72 text

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

Slide 73

Slide 73 text

Could we make this fasterer? Yes. Could we make this faster? Yes.

Slide 74

Slide 74 text

Time to run FizzBuzz 0 30m 1h 1h 30m 2h Ruby procs AST interpreter SECD in Ruby SECD in C

Slide 75

Slide 75 text

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

Slide 76

Slide 76 text

Could we make this fastererer? Not right now… but yes.

Slide 77

Slide 77 text

WHY

Slide 78

Slide 78 text

Why?

Slide 79

Slide 79 text

tomstuart / something

Slide 80

Slide 80 text

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