Update 2012/tromp

Format and typo fix README.md.

Un-rot13 the how13 and make it how.md. The reversal of rot13 was
discussed on GitHub at Landon's request.

One link was fixed.

Added other links. I was sorely tempted to make two links for garbage
collector, garbage == Windows and collector == the actual garbage
collector :-) but I decided that that's not my place so I didn't do it
as much as I wanted to (and I dearly wanted to!).

In some places there probably should be links again but since they were
linked to earlier in the document I'm going to pass on it for now.

I believe but am not certain that with this commit with the exception of
2012/README.md that 2012 is finished at least with format fixes in
README.md files (unless I come across something when trying out the
entries later on).
This commit is contained in:
Cody Boone Ferguson committed 2023-05-06 06:09:42 -07:00
1 parent 87daf5d056
commit 242726870a
3 files changed
+369 -272

No files matched your search

+303 -227
View File
@@ -1,31 +1,39 @@
# Most functional # Most functional
John Tromp John Tromp
<john.tromp@gmail.com> <john.tromp@gmail.com>
<http://tromp.github.io/> <http://tromp.github.io/>
## To build: ## To build:
make all # On a 64-bit machine (default) ```sh
make all # On a 64-bit machine (default)
make tromp32 # On a 32-bit machine make tromp32 # On a 32-bit machine
```
## To run: ## To run:
./tromp [-b] ```sh
./tromp [-b]
```
NOTE: Substitute ./tromp32 for ./tromp everywhere below if on a 32-bit machine Use `./tromp32` as you would `./tromp` if on a 32-bit machine.
## To run: ## To run:
cat ascii-prog.blc data | ./tromp -b ```sh
cat binary-prog.Blc data | ./tromp cat ascii-prog.blc data | ./tromp -b
cat binary-prog.Blc data | ./tromp
```
## Try: ## Try:
(cat hilbert.Blc; echo -n 1234) | ./tromp ```sh
(cat oddindices.Blc; echo; cat primes.blc | ./tromp -b) | ./tromp (cat hilbert.Blc; echo -n 1234) | ./tromp
cat primes.blc | ./tromp -b | ./primes.pl (cat oddindices.Blc; echo; cat primes.blc | ./tromp -b) | ./tromp
cat primes.blc | ./tromp -b | ./primes.pl
```
### Selected Judges Remarks: ### Selected Judges Remarks:
@@ -35,91 +43,116 @@ are more obfuscated than the entry itself.
## Author's remarks: ## Author's remarks:
This program celebrates the close connection between obfuscation and conciseness, This program celebrates the close connection between obfuscation and conciseness,
by implementing the most concise language known, Binary Lambda Calculus (BLC). by implementing the most concise language known, [Binary Lambda Calculus
(BLC)](https://tromp.github.io/cl/Binary_lambda_calculus.html).
BLC was developed to make Algorithmic Information Theory, the theory of smallest programs, [BLC](https://tromp.github.io/cl/Binary_lambda_calculus.html) was developed to
more concrete. It starts with the simplest model of computation, the lambda calculus, make [Algorithmic Information
and adds the minimum amount of machinery to enable binary input and output. Theory](https://en.wikipedia.org/wiki/Algorithmic_information_theory), the
theory of smallest programs, more concrete. It starts with the simplest model of
computation, the [lambda
calculus](https://en.wikipedia.org/wiki/Lambda_calculus), and adds the minimum
amount of machinery to enable binary input and output.
More specifically, it defines a universal machine, which, from an input stream of bits, More specifically, it defines a universal machine, which, from an input stream
parses the binary encoding of a lambda calculus term, applies that to the remainder of bits, parses the binary encoding of a [lambda
of input (translated to a lazy list of booleans, calculus](https://en.wikipedia.org/wiki/Lambda_calculus) term, applies that to
which have a standard representation in lambda calculus), the remainder of input (translated to a lazy list of
and translates the evaluated result back into a stream of bits to be output. [booleans](https://en.wikipedia.org/wiki/Boolean_algebra), which have a standard
representation in lambda calculus), and translates the evaluated result back
into a stream of bits to be output.
Lambda is encoded as 00, application as 01, and the variable bound by the n'th Lambda is encoded as 00, application as 01, and the variable bound by the `n`th
enclosing lambda (denoted n in so-called De Bruijn notation) as 1^{n}0. enclosing lambda (denoted `n` in so-called [De Bruijn
That's all there is to BLC! notation](https://en.wikipedia.org/wiki/De_Bruijn_notation)) as `1^{n}0`.
That's all there is to
[BLC](https://tromp.github.io/cl/Binary_lambda_calculus.html)!
For example the encoding of lambda term S = \x \y \z (x z) (y z), For example the encoding of lambda term `S = \x \y \z (x z) (y z)`,
with De Bruijn notation \ \ \ (3 1) (2 1), with [De Bruijn notation](https://en.wikipedia.org/wiki/De_Bruijn_notation) `\ \
is 00 00 00 01 01 1110 10 01 110 10 \ (3 1) (2 1)`, is `00 00 00 01 01 1110 10 01 110 10`.
In the closely related BLC8 language, IO is byte oriented, In the closely related
translating between a stream of bytes and a list of length-8 lists of booleans. [BLC8](https://tromp.github.io/cl/Binary_lambda_calculus.html#BLC8:_byte_sized_I.2FO)
language, IO is byte oriented, translating between a stream of bytes and a list
of length-8 lists of [booleans](https://en.wikipedia.org/wiki/Boolean_algebra).
The submission implements the universal machine in the most concise manner conceivable. The submission implements the universal machine in the most concise manner conceivable.
It lacks #defines and #includes, and compiles to a (stripped) executable of under 6K in size. It lacks `#defines` and `#includes`, and compiles to a (stripped) executable of
under 6K in size.
Without arguments, it runs in byte mode, using standard in- and output. Without arguments, it runs in byte mode, using standard input and output.
With one (arbitrary) argument, it runs in bit mode, using only the least significant With one (arbitrary) argument, it runs in bit mode, using only the least significant
bit of input, and using characters '0' and '1' for output. bit of input, and using characters `0` and `1` for output.
The program uses the following exit codes: The program uses the following exit codes:
```
0: OK; result is a finite list 0: OK; result is a finite list
5: Out of term space 5: Out of term space
6: Out of memory 6: Out of memory
1,2,3,4,8,9: result not in list form 1,2,3,4,8,9: result not in list form
```
The size of the term space is fixed at compile time with -DA The size of the term space is fixed at compile time with `-DA`.
A half byte `cat' ### A half byte `cat`
=================
The shortest (closed) lambda calculus term is \x x (\ 1 in De Bruijn notation) The shortest (closed) lambda calculus term is `\x x (\ 1` in [De Bruijn
which is the identity function. When its encoding 0010 is fed notation](https://en.wikipedia.org/wiki/De_Bruijn_notation)) which is the
into the universal machine, it will simply copy the input to the output. identity function. When its encoding `0010` is fed into the universal machine,
(well, not that simply, since each byte is smashed to bits and rebuilt from scratch) it will simply copy the input to the output. (well, not that simply, since each
Voila: a half byte cat: byte is smashed to bits and rebuilt from scratch) Voila: a half byte cat:
echo " Hello, world" | ./tromp ```sh
Hello, world $ echo " Hello, world" | ./tromp
Hello, world
```
Since the least significant 4 bits of the first byte are just arbitrary padding Since the least significant 4 bits of the first byte are just arbitrary padding
that is ignored by the program, that is ignored by the program, any character from ASCII 32 (space) through 47
any character from ASCII 32 (space) through 47 (/) will do, e.g.: (`/`) will do, e.g.:
echo "*Hello, world" | ./tromp ```sh
Hello, world $ echo "*Hello, world" | ./tromp
Hello, world
```
Bad programs
============
### Bad programs
If the input doesn't start with a valid program, that is, If the input doesn't start with a valid program, that is,
if the interpreter reaches end-of-file during program parsing, if the interpreter reaches end-of-file during program parsing,
it will crash in some way: it will crash in some way. E.g. the following might dump core:
echo -n "U" | ./tromp ```sh
Segmentation fault echo -n "U" | ./tromp
```
Furthermore, the interpreter requires the initial encoded lambda term to be closed, Furthermore, the interpreter requires the initial encoded lambda term to be closed,
that is, variable n can only appear within at least n enclosing lambdas. that is, variable `n` can only appear within at least `n` enclosing lambdas.
For instance the term \ 5 is not closed, For instance the term `\ 5` is not closed, causing the interpreter to crash when
causing the interpreter to crash when looking into a null-pointer environment: looking into a null-pointer environment:
echo ">Hello, world" | ./tromp ```sh
Segmentation fault echo ">Hello, world" | ./tromp
Since these properties can be checked when creating BLC programs, ```
will likely dump core.
Since these properties can be checked when creating
[BLC](https://tromp.github.io/cl/Binary_lambda_calculus.html) programs,
the interpreter doesn't bother checking for it. the interpreter doesn't bother checking for it.
A Self Interpreter ### A Self Interpreter
==================
The BLC universal machine may be small at 650 bytes of C The [BLC](https://tromp.github.io/cl/Binary_lambda_calculus.html) universal
(952 bytes including layout), but written machine may be small at 650 bytes of C (952 bytes including layout), but written
as a self interpreter in BLC it is downright minuscule at 232 bits (29 bytes): as a self interpreter in BLC it is downright minuscule at 232 bits (29 bytes):
```
01010001 01010001
10100000 10100000
00010101 00010101
@@ -140,9 +173,11 @@ as a self interpreter in BLC it is downright minuscule at 232 bits (29 bytes):
11110111 11001111 11110111 11001111
01110110 00011001 01110110 00011001
00011010 00011010 00011010 00011010
```
The byte oriented BLC8 version weighs in at 43 bytes (shown in hexadecimal). The byte oriented BLC8 version weighs in at 43 bytes (shown in hexadecimal).
```
19468 19468
05580 05580
05f00 05f00
@@ -156,14 +191,18 @@ The byte oriented BLC8 version weighs in at 43 bytes (shown in hexadecimal).
0b7fb 00cf6 0b7fb 00cf6
7bb03 91a1a 7bb03 91a1a
(cat uni8.Blc; echo " Ni hao") | ./tromp ```
Ni hao
A prime number sieve ```sh
==================== $ (cat uni8.Blc; echo " Ni hao") | ./tromp
Ni hao
```
### A prime number sieve
Even shorter than the self-interpreter is this prime number sieve in 167 bits (under 21 bytes): Even shorter than the self-interpreter is this prime number sieve in 167 bits (under 21 bytes):
```
000100011001100101000110100 000100011001100101000110100
000000101100000100100010101 000000101100000100100010101
11110111 101001000 11110111 101001000
@@ -174,23 +213,30 @@ Even shorter than the self-interpreter is this prime number sieve in 167 bits (u
00010110 00010110
0000110110 0000110110
The n'th bit in the output indicates whether n is prime: ```
cat primes.blc | ./tromp -b | head -c 70 The `n`th bit in the output indicates whether n is prime:
0011010100010100010100010000010100000100010100010000010000010100000100
For those who prefer to digest their primes in decimal, there is oddindices.Blc, ```sh
which will print the indices of all odd characters (with lsb = 1) $ cat primes.blc | ./tromp -b | head -c 70
0011010100010100010100010000010100000100010100010000010000010100000100
```
For those who prefer to digest their primes in decimal, there is `oddindices.Blc`,
which will print the indices of all odd characters (with
[LSB](https://en.wikipedia.org/wiki/Bit_numbering) = 1)
separated by a given character: separated by a given character:
(cat oddindices.Blc; echo -n " "; cat primes.blc | ./tromp -b) | ./tromp | head -c 70 ```
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 $ (cat oddindices.Blc; echo -n " "; cat primes.blc | ./tromp -b) | ./tromp | head -c 70
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97
```
A Space filling program ### A Space filling program
=======================
Program hilbert.Blc, at 143 bytes, is a very twisty "one-liner" (shown in hexadecimal): The program `hilbert.Blc`, at 143 bytes, is a very twisty "one-liner" (shown in hexadecimal):
```
1818181 8111154 6806041 55ff041 1818181 8111154 6806041 55ff041
9d f9 de 16 ff fe 5f 3f 9d f9 de 16 ff fe 5f 3f
ef f615ff9 46 84 058117e 05 ef f615ff9 46 84 058117e 05
@@ -206,245 +252,275 @@ Program hilbert.Blc, at 143 bytes, is a very twisty "one-liner" (shown in hexade
3fe80b2 2c18581 bfe5c10 42ff805 3fe80b2 2c18581 bfe5c10 42ff805
de ec 06 c2 c0 c0 de ec 06 c2 c0 c0
60 8191a00167fb cbcfdf65f7c0 a20 60 8191a00167fb cbcfdf65f7c0 a20
```
It expects n arbitrary characters of input, and draws a space filling Hilbert curve of order n: It expects `n` arbitrary characters of input, and draws a space filling [Hilbert
curve](https://en.wikipedia.org/wiki/Hilbert_curve) of order `n`:
(cat hilbert.Blc; echo -n "1") | ./tromp ```sh
_ $ (cat hilbert.Blc; echo -n "1") | ./tromp
| | _
| |
(cat hilbert.Blc; echo -n "12") | ./tromp $ (cat hilbert.Blc; echo -n "12") | ./tromp
_ _ _ _
| |_| | | |_| |
|_ _| |_ _|
_| |_ _| |_
(cat hilbert.Blc; echo -n "123") | ./tromp $ (cat hilbert.Blc; echo -n "123") | ./tromp
_ _ _ _ _ _ _ _
| |_| | | |_| | | |_| | | |_| |
|_ _| |_ _| |_ _| |_ _|
_| |_____| |_ _| |_____| |_
| ___ ___ | | ___ ___ |
|_| _| |_ |_| |_| _| |_ |_|
_ |_ _| _ _ |_ _| _
| |___| |___| | | |___| |___| |
(cat hilbert.Blc; echo -n "1234") | ./tromp $ (cat hilbert.Blc; echo -n "1234") | ./tromp
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
| |_| | | |_| | | |_| | | |_| | | |_| | | |_| | | |_| | | |_| |
|_ _| |_ _| |_ _| |_ _| |_ _| |_ _| |_ _| |_ _|
_| |_____| |_ _| |_____| |_ _| |_____| |_ _| |_____| |_
| ___ ___ | | ___ ___ | | ___ ___ | | ___ ___ |
|_| _| |_ |_| |_| _| |_ |_| |_| _| |_ |_| |_| _| |_ |_|
_ |_ _| _ _ |_ _| _ _ |_ _| _ _ |_ _| _
| |___| |___| |_| |___| |___| | | |___| |___| |_| |___| |___| |
|_ ___ ___ ___ ___ _| |_ ___ ___ ___ ___ _|
_| |_ |_| _| |_ |_| _| |_ _| |_ |_| _| |_ |_| _| |_
| _ | _ |_ _| _ | _ | | _ | _ |_ _| _ | _ |
|_| |_| | |___| |___| | |_| |_| |_| |_| | |___| |___| | |_| |_|
_ _ | ___ ___ | _ _ _ _ | ___ ___ | _ _
| |_| | |_| _| |_ |_| | |_| | | |_| | |_| _| |_ |_| | |_| |
|_ _| _ |_ _| _ |_ _| |_ _| _ |_ _| _ |_ _|
_| |___| |___| |___| |___| |_ _| |___| |___| |___| |___| |_
A BrainFuck interpreter ```
=======================
The smallest known BF interpreter is written in... you guessed it, BLC, ### A [Brainfuck](https://en.wikipedia.org/wiki/Brainfuck) interpreter
The smallest known BF interpreter is written in... you guessed it,
[BLC](https://tromp.github.io/cl/Binary_lambda_calculus.html),
coming in at 112 bytes (including 3 bits of padding): coming in at 112 bytes (including 3 bits of padding):
od -t x4 bf.Blc ```
0000000 01a15144 02d55584 223070b7 00f032ff $ od -t x4 bf.Blc
0000020 7f85f9bf 956fe15e c0ee7d7f 006854e5 0000000 01a15144 02d55584 223070b7 00f032ff
0000040 fbfd5558 fd5745e0 b6f0fbeb 07d62ff0 0000020 7f85f9bf 956fe15e c0ee7d7f 006854e5
0000060 d7736fe1 c0bc14f1 1f2eff0b 17666fa1 0000040 fbfd5558 fd5745e0 b6f0fbeb 07d62ff0
0000100 2fef5be8 ff13ffcf 2034cae1 0bd0c80a 0000060 d7736fe1 c0bc14f1 1f2eff0b 17666fa1
0000120 e51fee99 6a5a7fff ff0fff1f d0049d87 0000100 2fef5be8 ff13ffcf 2034cae1 0bd0c80a
0000140 db0500ab 3bb74023 b0c0cc28 10740e6c 0000120 e51fee99 6a5a7fff ff0fff1f d0049d87
0000160 0000140 db0500ab 3bb74023 b0c0cc28 10740e6c
0000160
```
It expects its input to consist of a Brainfuck program It expects its input to consist of a
(looking only at bits 0,1,4 to distinguish among ,-.+<>][ ) [Brainfuck](https://en.wikipedia.org/wiki/Brainfuck) program
followed by a ], followed by the input for the Brainfuck program. (looking only at bits `0`, `1` and `4` to distinguish among `,-.+<>][ `)
followed by a `]`, followed by the input for the Brainfuck program.
more hw.bf ```
++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.] $ more hw.bf
cat bf.Blc hw.bf | ./tromp ++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.]
Hello World! $ cat bf.Blc hw.bf | ./tromp
Hello World!
```
Curiously, the interpreter bf.Blc is the exact same size as hw.bf. Curiously, the interpreter `bf.Blc` is the exact same size as `hw.bf`.
A BLC assembler ### A BLC assembler
===============
Writing BLC programs can be made slightly less painful with this parser that Writing BLC programs can be made slightly less painful with this parser that
translates single-letter-variable lambda calculus into BLC: translates single-letter-variable lambda calculus into BLC:
echo "\f\x f (f (f x))" > three ```sh
cat parse.Blc three | ./tromp $ echo "\f\x f (f (f x))" > three
000001110011100111010 $ cat parse.Blc three | ./tromp
000001110011100111010
Converting between bits and bytes ```
=================================
THe program inflate.Blc and its inverse deflate.Blc allow us to translate between ### Converting between bits and bytes
BLC and BLC8.
If you assemble a byte oriented program, you'll need to compact it into BLC8: The program `inflate.Blc` and its inverse `deflate.Blc` allow us to translate between
BLC and BLC8. If you assemble a byte oriented program, you'll need to compact it
into BLC8:
So we could assemble an input reversing program as So we could assemble an input reversing program as
echo "\a a ((\b b b) (\b \c \d \e d (b b) (\f f c e))) (\b \c c)" > reverse ```sh
cat parse.Blc reverse | ./tromp > reverse.blc echo "\a a ((\b b b) (\b \c \d \e d (b b) (\f f c e))) (\b \c c)" > reverse
cat parse.Blc reverse | ./tromp > reverse.blc
```
and change it to BLC8 with and change it to BLC8 with
cat deflate.Blc reverse.blc | ./tromp > rev.Blc ```
wc rev.Blc $ cat deflate.Blc reverse.blc | ./tromp > rev.Blc
0 1 9 rev.Blc $ wc rev.Blc
0 1 9 rev.Blc
```
and then try it out with: and then try it out with:
cat rev.Blc - | ./tromp ```sh
Hello, world! $ cat rev.Blc - | ./tromp
^D Hello, world!
!dlrow ,olleH ^D
!dlrow ,olleH
```
Symbolic Lambda Calculus reduction ### Symbolic Lambda Calculus reduction
==================================
BLC8 program symbolic.Blc shows individual reduction steps on symbolic lambda terms. BLC8 program `symbolic.Blc` shows individual reduction steps on symbolic lambda terms.
Here it is used to show the calculation of 2^3 in Church numerals: Here it is used to show the calculation of 2^3 in Church numerals:
echo "(\f\x f (f (f x))) (\f\x f (f x))" > threetwo ```sh
cat parse.Blc threetwo | ./tromp > threetwo.blc $ echo "(\f\x f (f (f x))) (\f\x f (f x))" > threetwo
cat symbolic.Blc threetwo.blc | ./tromp $ cat parse.Blc threetwo | ./tromp > threetwo.blc
(\a \b a (a (a b))) (\a \b a (a b)) $ cat symbolic.Blc threetwo.blc | ./tromp
\a (\b \c b (b c)) ((\b \c b (b c)) ((\b \c b (b c)) a)) (\a \b a (a (a b))) (\a \b a (a b))
\a \b (\c \d c (c d)) ((\c \d c (c d)) a) ((\c \d c (c d)) ((\c \d c (c d)) a) b) \a (\b \c b (b c)) ((\b \c b (b c)) ((\b \c b (b c)) a))
\a \b (\c (\d \e d (d e)) a ((\d \e d (d e)) a c)) ((\c \d c (c d)) ((\c \d c (c d)) a) b) \a \b (\c \d c (c d)) ((\c \d c (c d)) a) ((\c \d c (c d)) ((\c \d c (c d)) a) b)
\a \b (\c \d c (c d)) a ((\c \d c (c d)) a ((\c \d c (c d)) ((\c \d c (c d)) a) b)) \a \b (\c (\d \e d (d e)) a ((\d \e d (d e)) a c)) ((\c \d c (c d)) ((\c \d c (c d)) a) b)
\a \b (\c a (a c)) ((\c \d c (c d)) a ((\c \d c (c d)) ((\c \d c (c d)) a) b)) \a \b (\c \d c (c d)) a ((\c \d c (c d)) a ((\c \d c (c d)) ((\c \d c (c d)) a) b))
\a \b a (a ((\c \d c (c d)) a ((\c \d c (c d)) ((\c \d c (c d)) a) b))) \a \b (\c a (a c)) ((\c \d c (c d)) a ((\c \d c (c d)) ((\c \d c (c d)) a) b))
\a \b a (a ((\c a (a c)) ((\c \d c (c d)) ((\c \d c (c d)) a) b))) \a \b a (a ((\c \d c (c d)) a ((\c \d c (c d)) ((\c \d c (c d)) a) b)))
\a \b a (a (a (a ((\c \d c (c d)) ((\c \d c (c d)) a) b)))) \a \b a (a ((\c a (a c)) ((\c \d c (c d)) ((\c \d c (c d)) a) b)))
\a \b a (a (a (a ((\c (\d \e d (d e)) a ((\d \e d (d e)) a c)) b)))) \a \b a (a (a (a ((\c \d c (c d)) ((\c \d c (c d)) a) b))))
\a \b a (a (a (a ((\c \d c (c d)) a ((\c \d c (c d)) a b))))) \a \b a (a (a (a ((\c (\d \e d (d e)) a ((\d \e d (d e)) a c)) b))))
\a \b a (a (a (a ((\c a (a c)) ((\c \d c (c d)) a b))))) \a \b a (a (a (a ((\c \d c (c d)) a ((\c \d c (c d)) a b)))))
\a \b a (a (a (a (a (a ((\c \d c (c d)) a b)))))) \a \b a (a (a (a ((\c a (a c)) ((\c \d c (c d)) a b)))))
\a \b a (a (a (a (a (a ((\c a (a c)) b)))))) \a \b a (a (a (a (a (a ((\c \d c (c d)) a b))))))
\a \b a (a (a (a (a (a (a (a b))))))) \a \b a (a (a (a (a (a ((\c a (a c)) b))))))
\a \b a (a (a (a (a (a (a (a b)))))))
```
As expected, the resulting normal form is Church numeral 8. As expected, the resulting normal form is [Church
numeral](https://en.wikipedia.org/wiki/Church_encoding) 8.
Taking only the first line of output gives us a sort of BLC disassembler, Taking only the first line of output gives us a sort of BLC disassembler, an
an exact inverse of the above assembler. The prime number sieve disassembles as follows: exact inverse of the above assembler. The prime number sieve disassembles as
follows:
cat symbolic.Blc primes.blc | ./tromp | head -1 ```sh
\a (\b b (b ((\c c c) (\c \d \e e (\f \g g) ((\f c c f ((\g g g) (\g f (g g)))) (\f \g \h \i i g (h (d f))))) (\c \d \e b (e c))))) (\b \c c (\d \e d) b) $ cat symbolic.Blc primes.blc | ./tromp | head -1
\a (\b b (b ((\c c c) (\c \d \e e (\f \g g) ((\f c c f ((\g g g) (\g f (g g)))) (\f \g \h \i i g (h (d f))))) (\c \d \e b (e c))))) (\b \c c (\d \e d) b)
```
Hardly any less obfuscated... Hardly any less obfuscated...
The last line of The last line of
cat symbolic.Blc primes.blc | ./tromp | head -16
starts out as
\a \b b (\c \d c) (\c c (\d \e d) (\d d (\e \f f) (\e e (\f \g g) ((\f (\g \h \i
The \a is for ignoring the rest of the input (to which the universal machine ```sh
applies the decoded lambda term). The \b b (..) (...) is the list constructor, cat symbolic.Blc primes.blc | ./tromp | head -16
usually called cons, applied to a head (a list element) and a tail (another list). ```
In this case the element is (\c \d c), which represents the boolean true, and
starts out as
```
\a \b b (\c \d c) (\c c (\d \e d) (\d d (\e \f f) (\e e (\f \g g) ((\f (\g \h \i
```
The `\a` is for ignoring the rest of the input (to which the universal machine
applies the decoded lambda term). The `\b b (..) (...)` is the list constructor,
usually called `cons`, applied to a head (a list element) and a tail (another list).
In this case the element is `(\c \d c)`, which represents the boolean true, and
which we use to represent a 0 bit. This is the bit that says 0 is not prime. which we use to represent a 0 bit. This is the bit that says 0 is not prime.
The next list element (following another cons) is (\d \e d). Another 0 bit, The next list element (following another `cons`) is `(\d \e d)`. Another 0 bit,
this time saying that 1 is not prime. The third list element is (\e \f f), this time saying that 1 is not prime. The third list element is `(\e \f f)`,
a 1 bit, confirming our suspicion that 2 is prime. As is the next number, a 1 bit, confirming our suspicion that 2 is prime. As is the next number,
according to (\f \g g). We can see that the tail after the first 4 elements according to `(\f \g g)`. We can see that the tail after the first 4 elements
is still subject to further reduction. The bit for number 4 will show up is still subject to further reduction. The bit for number 4 will show up
for the first time in line 30, as (\g \h g), or 0, as the result of zeroing for the first time in line 30, as `(\g \h g)`, or 0, as the result of zeroing
out all multiples of the first prime, 2. out all multiples of the first prime, 2.
Since my computer reaches swap hell before line 40, we can't see the next bit arriving, Since my computer reaches swap hell before line 40, we can't see the next bit arriving,
at least not in this symbolic reduction. at least not in this symbolic reduction.
Performance ### Performance
===========
Performance is quite decent, and amazingly good for such a tiny implementation, Performance is quite decent, and amazingly good for such a tiny implementation,
being roughly 50% slower than a Haskell implementation of the universal machine being roughly 50% slower than a Haskell implementation of the universal machine
using so-called Higher Order Abstract Syntax which relies on the highly optimized using so-called [Higher Order Abstract
Haskell runtime system for evaluation. Of course individual blc programs running Syntax](https://en.wikipedia.org/wiki/Higher-order_abstract_syntax) which relies on the highly optimized
Haskell runtime system for evaluation. Of course individual BLC programs running
under the interpreter perform much worse than that same program written in Haskell. under the interpreter perform much worse than that same program written in Haskell.
Our interpreter copes well with extra levels of interpretation: Our interpreter copes well with extra levels of interpretation:
time cat primes.blc | ./tromp -b | head -c 210 > /dev/null ```sh
real 0m0.043s $ time cat primes.blc | ./tromp -b | head -c 210 > /dev/null
time cat uni.blc primes.blc | ./tromp -b | head -c 210 > /dev/null real 0m0.043s
real 0m0.191s $ time cat uni.blc primes.blc | ./tromp -b | head -c 210 > /dev/null
time cat uni.blc uni.blc primes.blc | ./tromp -b | head -c 210 > /dev/null real 0m0.191s
real 0m1.919s $ time cat uni.blc uni.blc primes.blc | ./tromp -b | head -c 210 > /dev/null
time cat uni.blc uni.blc uni.blc primes.blc | ./tromp -b | head -c 210 > /dev/null real 0m1.919s
real 0m23.514s $ time cat uni.blc uni.blc uni.blc primes.blc | ./tromp -b | head -c 210 > /dev/null
time cat uni.blc uni.blc uni.blc uni.blc primes.blc | ./tromp -b | head -c 210 > /dev/null real 0m23.514s
real 4m52.700s $ time cat uni.blc uni.blc uni.blc uni.blc primes.blc | ./tromp -b | head -c 210 > /dev/null
real 4m52.700s
```
Obfuscation ### Obfuscation
===========
Obfuscation is due entirely to conciseness. Some questions to ponder: Obfuscation is due entirely to conciseness. Some questions to ponder:
Which of the term space codes 0,1,2,3 serves multiple purposes? Which of the term space codes `0`, `1`, `2`, `3` serve multiple purposes?
Why is the environment pointer pointing into the term space? Why is the environment pointer pointing into the term space?
What does the test u+m&1? do? What does the test `u+m&1?` do?
How does the program reach exit code 0? How does the program reach exit code 0?
And how do any of those blc programs work? And how do any of those BLC programs work?
Portability ### Portability
===========
The program freely (without casting) converts between int and int\*, causing The program freely (without casting) converts between int and `int *`, causing
many warnings; many warnings;
note: expected ‘int *’ but argument is of type ‘int’
```
note: expected 'int *' but argument is of type 'int'
warning: assignment from incompatible pointer type warning: assignment from incompatible pointer type
warning: assignment makes integer from pointer without a cast warning: assignment makes integer from pointer without a cast
warning: assignment makes pointer from integer without a cast warning: assignment makes pointer from integer without a cast
warning: incompatible implicit declaration of built-in function ‘calloc’ warning: incompatible implicit declaration of built-in function 'calloc'
warning: incompatible implicit declaration of built-in function ‘exit’ warning: incompatible implicit declaration of built-in function 'exit'
warning: passing argument 1 of ‘d’ makes pointer from integer without a cast warning: passing argument 1 of 'd' makes pointer from integer without a cast
warning: passing argument 1 of ‘p’ makes pointer from integer without a cast warning: passing argument 1 of 'p' makes pointer from integer without a cast
warning: pointer/integer type mismatch in conditional expression warning: pointer/integer type mismatch in conditional expression
```
Avoiding these would make the program substantially longer, Avoiding these would make the program substantially longer,
and detract from its single minded focus on conciseness. and detract from its single minded focus on conciseness.
It implicitly declares functions read, write, exit and calloc, the latter two incompatibly. It implicitly declares functions `read()`, `write()`, `exit()` and `calloc()`, the latter two incompatibly.
32 bit and 64 bit executables are separate Makefile targets, involving a change 32 bit and 64 bit executables are separate [Makefile](Makefile) targets, involving a change
from int to long and from a hardcoded sizeof of 4 to 8. from `int` to `long` and from a hardcoded sizeof of 4 to 8.
The program has been tested to work correctly on Linux/Solaris/MacOSX both in 32 and 64 bits. The program has been tested to work correctly on Linux/Solaris/MacOSX both in 32 and 64 bits.
How the program works ### How the program works
=====================
See the file how13. See the file [how.md](how.md).
Acknowledgements ### Acknowledgements
================
Christopher Hendrie, Bertram Felgenhauer, Alex Stangl, Seong-hoon Kang, Christopher Hendrie, Bertram Felgenhauer, Alex Stangl, Seong-hoon Kang,
and Yusuke Endoh have contributed ideas and suggestions for improvement. and [Yusuke Endoh](/winners.html#Yusuke_Endoh) have contributed ideas and
suggestions for improvement.
References ### References
==========
Binary Lambda Calculus Binary Lambda Calculus -
<https://tromp.github.io/cl/Binary_lambda_calculus.html> <https://tromp.github.io/cl/Binary_lambda_calculus.html>
G J Chaitin, Algorithmic information theory, Volume I, G J Chaitin, Algorithmic information theory, Volume I,
Cambridge Tracts in Theoretical Computer Science, Cambridge University Press, October 1987. Cambridge Tracts in Theoretical Computer Science, Cambridge University Press, October 1987.
<http://www.cs.auckland.ac.nz/~chaitin/cup.html> <https://web.archive.org/web/20121125233450/https://www.cs.auckland.ac.nz/~chaitin/cup.html>
Jean-Louis Krivine. 2007. Jean-Louis Krivine. 2007.
A call-by-name lambda-calculus machine A call-by-name lambda-calculus machine
+66
View File
@@ -0,0 +1,66 @@
# Spoiler
The program implements a so called [Krivine
machine](https://en.wikipedia.org/wiki/Krivine_machine), enhanced with a [basic
input/output system](https://en.wikipedia.org/wiki/BIOS) and a reference
counting [garbage collector](https://en.wikipedia.org/wiki/Waste_collector). The
Krivine machine is a stepwise transformer of a global state consisting of the
current term, the current environment (a list of closures), and a stack of
continuations (see the 3rd reference for details).
The term space holds [lambda
calculus](https://en.wikipedia.org/wiki/Lambda_calculus) terms in the following
format. 0 denotes some form of IO; the only four occurrences are at:
```
C=13: recognizes end of a byte
C=20: recognize output of 0 bit
C=21: recognize output of 1 bit
C=end: input list, expanded lazily
```
`1` denotes a variable, with next entry its de [Bruijn
index](https://en.wikipedia.org/wiki/De_Bruijn_index).
`2` denotes application with next entry the size of the term being applied.
`3` denotes lambda abstraction.
A closure consists of the following items:
0. pointer to the next closure (as part of an environment), or next record on
free list.
1. reference count
2. pointer to environment
3. lambda term (index in term space)
Here's what each variable do:
```
L Lambda term space
m mode: 0 for bits and 7 for bytes
b bits remaining unread in I, -1 on EOF
D Desirable temporary
c continuation context
a active environment pointer
C Current term index
U Ultimate term pointer
u utility entry
B Born to be free-list of closures
I Input character
O Output character
e entry of current term
```
Here's what each of the 6 auxiliary functions do:
```
s variable lookup in active environment with de Bruijn index u
S gets one bit of input, setting b to -1 on EOF or to remaining number of bits in current byte
k copy fragment from string literal holding lambda terms xor 46 into current end of term space
x expand input, adding 11 (resp. 99) entries to term space for bit (resp. byte) mode
p parses BLC-encoded lambda term using S(), stores results in term space and returns length
d decrease reference counter, add record to free list on reaching zero
```
-45
View File
@@ -1,45 +0,0 @@
Gur cebtenz vzcyrzragf n fb pnyyrq Xevivar znpuvar,
raunaprq jvgu n onfvp vachg/bhgchg flfgrz
naq n ersrerapr pbhagvat tneontr pbyyrpgbe.
Gur Xevivar znpuvar vf n fgrcjvfr genafsbezre bs n tybony fgngr pbafvfgvat bs
gur pheerag grez, gur pheerag raivebazrag (n yvfg bs pybfherf), naq n fgnpx bs pbagvahngvbaf
(Frr gur 3eq ersrerapr sbe qrgnvyf.)
Gur grez fcnpr ubyqf ynzoqn pnyphyhf grezf va gur sbyybjvat sbezng
0 qrabgrf fbzr sbez bs VB; gur bayl sbhe bpphenaprf ner ng
P=13: erpbtavmrf raq bs n olgr
P=20: erpbtavmr bhgchg bs 0 ovg
P=21: erpbtavmr bhgchg bs 1 ovg
P=raq: vachg yvfg, rkcnaqrq ynmvyl
1 qrabgrf n inevnoyr, jvgu arkg ragel vgf qr Oehvwa vaqrk
2 qrabgrf nccyvpngvba jvgu arkg ragel gur fvmr bs gur grez orvat nccyvrq
3 qrabgrf ynzoqn nofgenpgvba
N pybfher pbafvfgf bs gur sbyybjvat vgrzf
0 cbvagre gb gur arkg pybfher (nf cneg bs na raivebazrag), be arkg erpbeq ba serr yvfg
1 ersrerapr pbhag
2 cbvagre gb raivebazrag
3 ynzoqn grez (vaqrk va grez fcnpr)
Urer'f jung rnpu inevnoyr qbrf:
Y Ynzoqn grez fcnpr
z zbqr; 0 sbe ovgf naq 7 sbe olgrf
o ovgf erznvavat haernq va V, -1 ba RBS
Q Qrfvenoyr grzcbenel
p pbagvahngvba pbagrkg
n npgvir raivebazrag cbvagre
P Pheerag grez vaqrk
H Hygvzngr grez cbvagre
h hgvyvgl ragel
O Obea gb or serr-yvfg bs pybfherf
V Vachg punenpgre
B Bhgchg punenpgre
r ragel bs pheerag grez
Urer'f jung rnpu bs gur 6 nhkvyvnel shapgvbaf qbrf:
f: inevnoyr ybbxhc va npgvir raivebazrag jvgu qr Oehvwa vaqrk h
F: trgf bar ovg bs vachg, frggvat o gb -1 ba RBS be gb erznvavat ahzore bs ovgf va pheerag olgr
x: xbcl sentzrag sebz fgevat yvgreny ubyqvat ynzoqn grezf kbe 46 vagb pheerag raq bs grez fcnpr
k: kcnaq vachg, nqqvat 11 (erfc. 99) ragevrf gb grez fcnpr sbe ovg (erfc. olgr) zbqr
c: cnefrf oyp-rapbqrq ynzoqn grez hfvat F(), fgberf erfhygf va grez fcnpr naq ergheaf yratgu
q: qrpernfr ersrerapr pbhagre, nqq erpbeq gb serr yvfg ba ernpuvat mreb