$30 off During Our Annual Pro Sale. View Details »

Programming with Something

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.

Tom Stuart

November 08, 2021
Tweet

More Decks by Tom Stuart

Other Decks in Technology

Transcript

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

    View Slide

  2. Ten years ago…

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  13. Ten years later…

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  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

    View Slide

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

    View Slide

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

    View Slide

  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

    View Slide

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

    View Slide

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

    View Slide

  27. >> 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,

    View Slide

  28. [ 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

    View Slide

  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"

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  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

    View Slide

  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

    View Slide

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

    View Slide

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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

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

    View Slide

  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

    View Slide

  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

    View Slide

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

    View Slide

  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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  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

    View Slide

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

    View Slide

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

    View Slide

  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

    View Slide

  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

    View Slide

  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.

    View Slide

  59. Could we make this faster?

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

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

    View Slide

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

    View Slide

  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

    View Slide

  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

    View Slide

  67. Could we make this fasterer?

    View Slide

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

    View Slide

  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;

    View Slide

  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;

    View Slide

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

    View Slide

  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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  77. WHY

    View Slide

  78. Why?

    View Slide

  79. tomstuart / something

    View Slide

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

    View Slide