Metaprogramming#
Bruijn has a homoiconic meta encoding inspired by Lisp's quoting feature.
Blog post with more details: Metaprogramming and self-interpretation.
Encoding#
`X ⤳ [[[2 (+Xu)]]]
`(M N) ⤳ [[[1 `M `N]]]
`[M] ⤳ [[[0 `M]]]
Any quoted term gets converted to this encoding:
# example quotations
:test (`0) ([[[2 (+0u)]]])
:test (`[0]) ([[[0 [[[2 (+0u)]]]]]])
:test (`'0') ([[[0 [[[0 [[[0 [[[1 [[[2 (+0u)]]] [[[1 [[[2 (+0u)]]] [[[1 [[[2 (+0u)]]] [[[1 [[[2 (+0u)]]] [[[1 [[[2 (+1u)]]] [[[1 [[[2 (+1u)]]] [[[1 [[[2 (+0u)]]] [[[1 [[[2 (+0u)]]] [[[2 (+2u)]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]])
# quotes are nestable!
:test (``0) ([[[0 [[[0 [[[0 [[[1 [[[2 (+2u)]]] [[[0 [[[0 [[[2 (+0u)]]]]]]]]]]]]]]]]]]]]])
:test (`[0 `0]) ([[[0 [[[1 [[[2 (+0u)]]] [[[0 [[[0 [[[0 [[[1 [[[2 (+2u)]]] [[[0 [[[0 [[[2 (+0u)]]]]]]]]]]]]]]]]]]]]]]]]]]])
Quasiquotation#
Quoted terms can be escaped (unquoted) using the comma symbol. Unquoted terms will be fully evaluated first before getting quoted again.
:test (```,[0]) (``[0])
:test (`,`,[0]) ([0])
:test (`[0 `,[0]]) (`[0 [0]])
Unquoted de Bruijn indices will get bound to the respective abstraction outside of its meta encoding.
# adds two using normal quotation
add-two `[0 + (+2u)]
:test (!add-two (+2u)) ((+4u))
# adds two using a reaching de Bruijn index
add-two* [`(,0 + (+2u))]
:test (!(add-two* `(+2u))) ((+4u))
Self-interpretation#
Using a metacircular self-interpreter, bruijn can reduce the meta encoding to its normal form. A 194 bit interpreter in the form of bruijn's logo:
01010001 00011100
11010000 ###### 11100110
10000 ############ 00001
01011 ##### ##### 00001
11100 #### #### 00101
01110 #### ##### 00011
00000 #### ###### 10100
00011 #### ### #### 00111
10000 #### ## #### 11111
00001 #### ### #### 11110
00010 ###### #### 11110
10011 ##### #### 10100
11110 #### #### 00011
11000 ##### ##### 00011
11000 ############ 01011
01101110 ###### 00011001
00011010 00011010
The code can also be found in the eval
/!‣
function
of the meta library:
:test (!`"tacocat".reverse) ("tacocat")
Meta library std/Meta
#
The meta library enables simple interaction with the meta encoding.
Examples:
# testing equivalence
:test (α-eq? `[0 0] `[0 0]) (true)
:test (α-eq? `α-eq? `α-eq?) (true)
# BLC length of meta term
:test (length `[0]) ((+4u))
:test (length `[[1 1]]) ((+12u))
# self-modification
:test (lhs `(1 0) `0) (`(0 0))
:test (rhs `(0 1) `0) (`(0 0))
:test (swap `(1 0)) (`(0 1))
:test (map inc `0) (`1)
:test (map (map inc) `[0]) (`[1])
:test (map swap `[0 1]) (`[1 0])
# encoding terms as numbers
:test ((encode `(0 0)) =? (+3)) (true)
:test ((encode `[0]) =? (+8)) (true)
# decoding numbers to terms
:test (decode (+3)) (`(0 0))
:test (decode (+8)) (`[0])