~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                                                                                
a:: #→#→#       / Ackermann's function.                                         
                                                                                
    a 0    n    = +n                                                            
    a (+m) 0    = a m 1                                                         
    a (+m) (+n) = a m (a (+m) n)                                                
                                                                                
    a 2 2                                                                       
7
                                                                                
b:: #→#→#       / Ackermann's function (tail-recursive)                         
                                                                                
    b m n = a[n,m]                                                              
    .   a ( 0:  []) = 0                                                         
    .   a ( 0: 0:s) = a(1:s)                                                    
    .   a ( 0:+m:s) = a(1:m:s)                                                  
    .   a (+n:  []) = +n                                                        
    .   a (+n: 0:s) = a(+(+n):s)                                                
    .   a (+n:+m:s) = a(n:+m:m:s)                                               
                                                                                
    b 2 2                                                                       
7
                                                                                
c:: #→#→#→#     / Ackermann's other function:                                   
                                                                                
    c 0 m   0  = m                  / sum                                       
    c 0 m (+n) = +(c 0 m n)                                                     
                                                                                
    c 1 m   0  = 0                  / product                                   
    c 1 m (+n) = c 0 m (c 1 m n )                                               
                                                                                
    c (+(+k)) m   0  = 1            / exponent and beyond ···                   
    c (+(+k)) m (+n) = c (+k) m (c (+(+k)) m n)                                 
                                                                                
    / Then, using partial application (currying):                               
                                                                                
    s = c 0     / sum                                                           
    p = c 1     / product                                                       
    e = c 2     / exponent                                                      
    / ...       / ... and beyond.                                               
                                                                                
    s 3 2   / sum         3+2   1(+⍣⍵)⍺                                         
5
    p 3 2   / product     3×2 \ ⍺(+⍣⍵)0                                         
6
    e 3 2   / exponent    3*2 \ ⍺(×⍣⍵)1                                         
9
    c 3 2 2 / and beyond  ... \ ⍺(*⍣⍵)1                                         
4
                                                                                
// For more on these functions, search for "Ackermann" in min.dws/Background.   
                                                                                
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                                                                                
/ This is a Brainfuck interpreter,                                              
/   written in a max interpreter,                                               
/       written in an APL interpreter.                                          
/           written in C.                                                       
/                                                                               
/ Consequently, it is a little slow.                                            
/                                                                               
/ See: dfns.dws/notes.bf for a description of the language.                     
/                                                                               
/ As Brainfuck is known to be Turing-complete, the ability to write Brainfuck   
/ in max proves that max is also Turing-complete.                               
/                                                                               
/ As max deals only in numbers, we translate BF opcodes into tokens 0-7:        
/                                                                               
/   [ ] < > + - . ,                                                             
/   0 1 2 3 4 5 6 7                                                             
/                                                                               
/ The token-stream and memory-tape are each implemented as a pair of lists,     
/ with the current token or memory-cell being the head item of the right-       
/ most of the pair.                                                             
/                                                                               
/ To move along the token-stream or memory-tape to the right (say) we simply    
/ pop an item from its right list and push it onto its left list, thus making   
/ current the original cell's right neighbour.                                  
/                                                                               
/    .. a b [c] d e .. → .. b c [d] e f ..      / moving along stream to right  
/                     ≡≡≡                       / is equivalent to transferring 
/   (b:a:..)(c:d:e:..) → (c:b:..)(d:e:f:..)     / current item (c) to left.     
/                                                                               
/ Ditto moving left, mutatis mutandis.                                          
/                                                                               
/ The memory-tape is extended rightwards on demand by consing a 0 to an empty   
/ right-list (substituting [0] for []).                                         
/                                                                               
/   a x(3:y) p(r:[]) i = a (3:x)y (r:p)[0] i    / > extend tape.                
/                                                                               
/ This Brainfuck interpreter takes a list of number-tokens, translated as above,
/ and a second list from which input numbers are drawn. It returns a list of    
/ output numbers. Therefore, b:: [#]→[#]→[#]                                    
/                                                                               
/ Inner function "a", where most of the action takes place, is of type:         
/                                                                               
/   a:: [#][#] [#][#] [#] → [#]                                                 
/        ├──┘   ├──┘   │     └── output list.                                   
/        │      │      └──────── input list.                                    
/        │      └─────────────── memory-tape lists.                             
/        └────────────────────── token-stream lists.                            
/                                                                               
/ Local subfuctions of "a":                                                     
/                                                                               
/   r skip Right from [ to find matching ].                                     
/   l skip Left to find matching [ from ].                                      
/                                                                               
/ l and r ignore inner nested [] pairs by maintaining a depth parameter "d".    
                                                                                
    b t i = a  []t [][0] i                                      / brainfuck     
    .   a x[] pq i = []                                         / no more toks: 
    .   a x(0:y) p(+q:r) i = a (0:x)y   p(+q:r) i               / +p [ cont     
    .   a x(0:y) p( 0:q) i = r (0:x)y 0 p( 0:q) i               /  0 [ skip fwd 
    .   .   r x(   1 :y)   0  pq i = a (   1 :x)y      pq i     /    ] ≡        
    .   .   r x(   0 :y)   d  pq i = r (   0 :x)y (+d) pq i     /     [[ →      
    .   .   r x(   1 :y) (+d) pq i = r (   1 :x)y   d  pq i     /     ]] →      
    .   .   r x(+(+t):y)   d  pq i = r (+(+t):x)y   d  pq i     /     * →       
    .   a x(1:y) p( 0:q) i = a (1:x)y   p( 0:q) i               /  0 ] cont     
    .   a x(1:y) p(+q:r) i = l x(1:y) 0 p(+q:r) i               / +p ] skip back
    .   .   l (x:y)(0:z)     1   pq i = a (0:x:y)z        pq i  /    [ ≡        
    .   .   l (x:y)(0:z) (+(+d)) pq i = l y(x:0:z)   (+d) pq i  /     [[ ←      
    .   .   l (x:y)(1:z)     d   pq i = l y(x:1:z)   (+d) pq i  /     ]] ←      
    .   .   l (x:y)(+(+t):z) d   pq i = l y(x:+(+t):z) d  pq i  /     * ←       
    .   a x(2:y) (p:q)r   i    =   a (2:x)y q(p:r)     i        / < tape left.  
    .   a x(3:y) p(r:[] ) i    =   a (3:x)y (r:p)[0]   i        / > extend tape.
    .   a x(3:y) p(r:s:t) i    =   a (3:x)y (r:p)(s:t) i        / > tape right. 
    .   a x(4:y) p( q:r)  i    =   a (4:x)y p(+q:r)    i        / + incr.       
    .   a x(5:y) p(+q:r)  i    =   a (5:x)y p( q:r)    i        / - decr.       
    .   a x(6:y) p( q:r)  i    = q:a (6:x)y p( q:r)    i        / . output.     
    .   a x(7:y) p( q:r) (i:j) =   a (7:x)y p(i:r)     j        / , input,      
                                                                                
    b::                                                                         
[#]→[#]→[#]
                                                                                
/ Standard bf code is shown commented to the right of the following examples:   
                                                                                
    b [4,6, 4,6, 4,6] []        / +. +. +.                                      
[1,2,3]
                                                                                
    b [7,3,7, 6,2,6] [8,9]      / ,>, .<. reverse of 2-item input list.         
[9,8]
                                                                                
    s = b [                     / sum of two input digits                       
        7,                      / ,                 0: input m                  
        3,7,                    / >,                1: input n                  
        0,                      / [                 1: n ×                      
            2,4,                /   <+              0: incr m                   
            3,5,                /   >-              1: decr n                   
        1,2,6                   / ]<.               0: output m+n               
    ], s::                      / display type of sum function:                 
[#]→[#]
                                                                                
    s [5,8]                     / sum: 5+8 → 13                                 
[13]
                                                                                
    t = b [                     / total of 0-terminated input list              
        3,7,                    /   >,              1: first input              
        0,                      /   [               1: loop until 0 input       
            0,                  /       [           1: next value               
                2,4,            /           <+      0: incr total               
                3,5,            /           >-      1: decr input               
            1,                  /       ]           1: 0                        
            7,                  /       ,           1: next input               
        1,                      /   ]               1: 0                        
        2,6                     /   <.              0: output total             
    ], t::                      / type of total function.                       
[#]→[#]
                                                                                
    t [1,2,3,4,0]               / +/1 2 3 4                                     
[10]
                                                                                
    t [0]                       / +/⍬                                           
[0]
                                                                                
    p = b [                     / product of two input digits (Wikipedia).      
        7,                      /   ,               0: input m                  
        3,7,                    /   >,              1: input n                  
        2,0,                    /   <[              0: m ×                      
            3,0,                /       >[          1: n ×                      
                3,4,            /           >+      2: incr total               
                3,4,            /           >+      3: incr copy                
                2,2,5,          /           <<-     1: decr loop n              
            1,                  /       ]           1: 0                        
            3,3,0,              /       >>[         3: copy ×                   
                2,2,4,          /           <<+     1: copy to n                
                3,3,5,          /           >>-     3: decr loop                
            1,                  /       ]           3: 0                        
            2,2,2,5,            /       <<<-        0: decr loop m              
        1,                      /   ]               0: 0                        
        3,3,6                   /   >>.             2: output m×n               
    ]                                                                           
                                                                                
    p [2,3]                     / product: 2×3 → 6                              
[6]
                                                                                
    b [6,4, 0, 6,4, 1] []       /   .+ [ .+ ]   infinite sequence               
[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,2
                                                                                
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                                                                                
r:: #→[#]→#     / radix-decode:                                                 
                                                                                
    r n = d                                 / auxiliary decode function.        
    .   d [ 0] =  0                         / decode [0] → 0.                   
    .   d [+i] = +i                         / decode [i] → i.                   
    .   d ( 0:j:k) = d (j:k)                / ignore leading 0.                 
    .   d (+i:j:k) = c n (i:j:k)            / carry base to next column.        
    .   .   c   0  (i:j:k) = d (i:j:k)      / carry 0: done.                    
    .   .   c (+m) (i:j:k) = c m (i:+j:k)   / carry 1 → next col + base.        
                                                                                
// examples:                                                                    
                                                                                
    r 1 [1,0,1,0,1,0]   / unary decode (tally)                                  
3
    r 2 [1,0,1,0,1,0]   / binary decode                                         
42
    r (+9) [1,2,3]      / decimal decode                                        
123
                                                                                
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                                                                                
r:: (⍺→⍵→⍵)→⍵→[⍺]→⍵             / fold (reduce) right:                          
                                                                                
    r f i []    = i                                                             
    r f i (x:y) = f x (r f i y)                                                 
                                                                                
l:: (⍺→⍵→⍺)→⍺→[⍵]→⍺             / fold (reduce) left:                           
                                                                                
    l f i [] = i                                                                
    l f i (x:y) = l f (f i x) y                                                 
                                                                                
// examples:                                                                    
                                                                                
    r s 0 [1,2,3]               / sum-reduce                                    
    .   s 0 j = j                                                               
    .   s (+i) j = +(s i j)                                                     
6
                                                                                
    l d 0 [1,2,3]               / decimal-decode                                
    .   d 0 u = u                                                               
    .   d (+t) u = d t (+(+(+(+(+(+(+(+(+(+u))))))))))                          
123
                                                                                
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                                                                                
g:: #→#→#       / greatest-common-divisor:                                      
                                                                                
    g m n = h m n m n                                                           
    .   h   0    0    i    j  = 0                                               
    .   h   0  (+n)   i    j  = +n                                              
    .   h (+m)   0    i    j  = +m                                              
    .   h (+m) (+n)   0    0  = +m                                              
    .   h (+m) (+n)   0  (+j) = h (+m) (+j) m j                                 
    .   h (+m) (+n) (+i)   0  = h (+i) (+n) i n                                 
    .   h (+m) (+n) (+i) (+j) = h (+m) (+n) i j                                 
                                                                                
// examples:                                                                    
                                                                                
    [                                                                           
        g 6 9,  / → 3                                                           
        g 3 5,  / → 1                                                           
        g 0 3,  / → 3                                                           
        g 3 0,  / → 3                                                           
        g 3 3   / → 3                                                           
    ]                                                                           
[3,1,3,3,3]
                                                                                
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                                                                                
m:: (⍺→⍵)→[⍺]→[⍵]       / map (each):                                           
                                                                                
    m f   []  = []                                                              
    m f (x:y) = f x : m f y                                                     
                                                                                
// examples:                                                                    
                                                                                
    m + [0,1,2]         / map successor                                         
[1,2,3]
                                                                                
    m (m+) [            / map map ..                                            
        [],             / → []                                                  
        [0],            / → [1]                                                 
        [1,2],          / → [2,3]                                               
        [3,4,5]         / → [4,5,6]                                             
    ]                                                                           
[[],[1],[2,3],[4,5,6]]
                                                                                
    m r [               / map reverse                                           
        [],             / → []                                                  
        [0],            / → [0]                                                 
        [1,2],          / → [2,1]                                               
        [3,4,5]         / → [5,4,3]                                             
    ]                                                                           
    .   r = f []                                                                
    .   .   f x []    = x                                                       
    .   .   f x (y:z) = f (y:x) z                                               
[[],[0],[2,1],[5,4,3]]
                                                                                
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                                                                                
p:: [#]         / prime numbers:                                                
                                                                                
    p = s (i 2)                         / sieve primes from [2,3,4, ...         
    .   s  (0:y) = s y                  / skip multiple of prime.               
    .   s (+i:y) = +i : s (z i y)       / prime with zeros for multiples.       
    .   .   z   0  (x:y) = 0 : z i y    / multiple: zero for head.              
    .   .   z (+j) (x:y) = x : z j y    / otherwise: prime for head.            
    .   i j = j : i (+j)                / nums [j, +j, +(+j), ...               
                                                                                
// example:                                                                     
                                                                                
    t p . t(a:b:c:x) = [a,b,c]          / first three prime numbers.            
[2,3,5]
                                                                                
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                                                                                
r:: #→#→#       / residue (modulus):                                            
                                                                                
    r   0    0  = 0                                                             
    r (+m)   0  = 0                                                             
    r   0  (+n) = +n                                                            
    r (+m) (+n) = s (+m) (+n) m n                                               
    .   s m n   0    0  = 0                                                     
    .   s m n (+i)   0  = n                                                     
    .   s m n   0  (+j) = s m (+j) m (+j)                                       
    .   s m n (+i) (+j) = s m n i j                                             
                                                                                
// examples:                                                                    
                                                                                
    [                                                                           
        r 0 0,  / → 0                                                           
        r 0 3,  / → 3                                                           
        r 3 0,  / → 0                                                           
        r 3 6,  / → 0                                                           
        r 3 7,  / → 1                                                           
        r 3 8   / → 2                                                           
    ]                                                                           
[0,3,0,0,1,2]
                                                                                
    )                                                                           


Back to: contents