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 @ Shopify, RubyConf 2021
Programming with Something
https://tomstu.art/programming-with-something
Ten years ago…
https://tomstu.art/programming-with-nothing
PROGRAMMING
@tomstuart — RU3Y MANOR — 2011-10-29
WITH
NOTHING
create procs
call procs
(abbreviate with constants)
https://tomstu.art/programming-with-nothing
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]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]
]]]]]]]]]]]]]]]]]]]]]]]]]]]]] } }
>> THREE[-> n { n + 1 }][0]
=> 3
>> HUNDRED[-> n { n + 1 }][0]
=> 100
>> ZERO[-> n { n + 1 }][0]
=> 0
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] } }
>> EIGHT = ADD[FIVE][THREE]
=> #
>> EIGHT[-> n { n + 1 }][0]
=> 8
>> POWER[TWO][EIGHT][-> n { n + 1 }][0]
=> 256
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]] }
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]] } }
]
} }
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]
]]]
}]
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]]]] }]
Ten years later…
Could we represent these
encoded values ourselves?
Could we evaluate these
encoded values ourselves?
Could we decode these
encoded values ourselves?
-> p { -> x { p[p[p[x]]] } }
-> p { -> x { p[p[p[x]]] } }
-> p { -> x { p[p[p[x]]] } }
-> p { -> x { p[p[p[x]]] } }
-> p { -> x { p[p[p[x]]] } }
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]]]] }]
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
>> variable = Variable.new(:x)
=> x
>> call = Call.new(variable, variable)
=> x[x]
>> definition = Definition.new(:x, call)
=> -> x { x[x] }
>> 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)
)
)
)
)
)
: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
-> 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)
)
)
)
)
)
>> 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]]]
>> 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,
[ 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
$ 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"
>> 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]]]]]]]]]
>> THREE = -> p { -> x { p[p[p[x]]] } }
=> #
>> THREE.parameters
=> [[:req, :p]]
>> parameter = THREE.parameters[0][1]
=> :p
>> body = # ???
>> IDENTITY = -> x { x }
=> #
>> variable = Variable.new(IDENTITY.parameters[0][1])
=> x
>> body = IDENTITY.call(variable)
=> x
>> 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]
>> 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]]]
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
[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
>> 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
Could we represent these
encoded values ourselves?
Could we evaluate these
encoded values ourselves?
Could we decode these
encoded values ourselves?
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
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
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
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
>> p = -> greeting { -> name { "#{greeting}, #{name}!" } }
=> #
>> p['Hello'] # -> name { "Hello, #{name}!" }
=> #
>> p['Hello']['RubyConf']
=> "Hello, RubyConf!"
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
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
>> 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 }]
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
>> 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)
def evaluate(expression)
loop do
expression = reduce(expression)
rescue NoMatchingPatternError
return expression
end
end
>> 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]] } }
Could we represent these
encoded values ourselves?
Could we evaluate these
encoded values ourselves?
Could we decode these
encoded values ourselves?
>> 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]]] } }
!
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
def value?(expression)
case expression
in Definition | Constant
true
in Call(Constant, argument) if value?(argument)
true
else
false
end
end
>> 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]]]
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
>> 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
Could we represent these
encoded values ourselves? Yes.
Could we evaluate these
encoded values ourselves? Yes.
Could we decode these
encoded values ourselves? Yes.
Could we make this faster?
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
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
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
evaluate: -> x { ????? }[ ????? ]
environment: x = ?????
body: ?????
result: evaluate ????? in environment { x = ????? }
evaluate: -> x { ????? } in environment { ????? }
environment: { ????? }
definition: -> x { ????? }
result: closure(-> x { ????? }, { ????? })
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
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
Could we make this fasterer?
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;
};
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;
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;
}
}
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;
}
}
}
}
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
Could we make this fasterer? Yes.
Could we make this faster? Yes.
Time to run FizzBuzz
0
30m
1h
1h 30m
2h
Ruby procs AST interpreter SECD in Ruby SECD in C
Time to run FizzBuzz
0
1m
2m
3m
4m
Ruby procs AST interpreter SECD in Ruby SECD in C
Could we make this fastererer?
Not right now… but yes.
WHY
Why?
tomstuart / something
Tom Stuart @ Shopify, RubyConf 2021
Thanks.
https://tomstu.art/programming-with-something