This commit is contained in:
Ingy döt Net 2013-04-10 21:29:02 -07:00
parent 764da6cbbb
commit db842d013d
19005 changed files with 197040 additions and 7 deletions

View file

@ -0,0 +1,222 @@
{{Template:clarify task}}
[[Category:Recursion]]
'''Background''': The '''man or boy test''' was proposed by computer scientist [[wp:Donald_Knuth|Donald Knuth]] as a means of evaluating implementations of the [[:Category:ALGOL 60|ALGOL 60]] programming language. The aim of the test was to distinguish compilers that correctly implemented "recursion and non-local references" from those that did not.
<blockquote style="font-style:italic">
I have written the following simple routine, which may separate the 'man-compilers' from the 'boy-compilers'<br> &mdash; <span style="font-style:normal">Donald Knuth</span></blockquote>
'''Task''': Imitate Knuth's example in Algol 60 in another language, as far as possible.
'''Details''': Local variables of routines are often kept in [http://c2.com/cgi/wiki?ActivationRecord ''activation records''] (also ''call frames''). In many languages, these records are kept on a [[System stack|call stack]]. In Algol (and e.g. in [[Smalltalk]]), they are allocated on a [[heap]] instead. Hence it is possible to pass references to routines that still can use and update variables from their call environment, even if the routine where those variables are declared already returned. This difference in implementations is sometimes called the [[wp:Funarg_problem|Funarg Problem]].
In Knuth's example, each call to ''A'' allocates an activation record for the variable ''A''. When ''B'' is called from ''A'', any access to ''k'' now refers to this activation record. Now ''B'' in turn calls ''A'', but passes itself as an argument. This argument remains bound to the activation record. This call to ''A'' also "shifts" the variables ''x<sub>i</sub>'' by one place, so eventually the argument ''B'' (still bound to its particular
activation record) will appear as ''x4'' or ''x5'' in a call to ''A''. If this happens when the expression ''x4 + x5'' is evaluated, then this will again call ''B'', which in turn will update ''k'' in the activation record it was originally bound to. As this activation record is shared with other instances of calls to ''A'' and ''B'', it will influence the whole computation.
So all the example does is to set up a convoluted calling structure, where updates to ''k'' can influence the behavior
in completely different parts of the call tree.
Knuth used this to test the correctness of the compiler, but one can of course also use it to test that other languages can emulate the Algol behavior correctly. If the handling of activation records is correct, the computed value will be &minus;67.
'''Performance and Memory''': Man or Boy is intense and can be pushed to challenge any machine. Memory not CPU time is the constraining resource as the recursion creates a proliferation activation records which will quickly exhaust memory and present itself through a stack error. Each language may have ways of adjusting the amount of memory or increasing the recursion depth. Optionally, show how you would make such adjustments.
The table below shows the result, call depths, and total calls for a range of k:
{| class="wikitable"
! k
! 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
! 29
! 30
|-
! A
|align="right"| 1
|align="right"| 0
|align="right"| -2
|align="right"| 0
|align="right"| 1
|align="right"| 0
|align="right"| 1
|align="right"| -1
|align="right"| -10
|align="right"| -30
|align="right"| -67
|align="right"| -138
|align="right"| -291
|align="right"| -642
|align="right"| -1,446
|align="right"| -3,250
|align="right"| -7,244
|align="right"| -16,065
|align="right"| -35,601
|align="right"| -78,985
|align="right"| -175,416
|align="right"| -389,695
|align="right"| -865,609
|align="right"| -1,922,362
|align="right"| -4,268,854
|align="right"| -9,479,595
|align="right"| -21,051,458
|align="right"| -46,750,171
|align="right"| -103,821,058
|align="right"| -230,560,902
|align="right"| -512,016,658
|-
! A called
|align="right"| 1
|align="right"| 2
|align="right"| 3
|align="right"| 4
|align="right"| 8
|align="right"| 18
|align="right"| 38
|align="right"| 80
|align="right"| 167
|align="right"| 347
|align="right"| 722
|align="right"| 1,509
|align="right"| 3,168
|align="right"| 6,673
|align="right"| 14,091
|align="right"| 29,825
|align="right"| 63,287
|align="right"| 134,652
|align="right"| 287,264
|align="right"| 614,442
|align="right"| 1,317,533
|align="right"| 2,831,900
|align="right"| 6,100,852
|align="right"| 13,172,239
|align="right"| 28,499,827
|&nbsp;
|&nbsp;
|&nbsp;
|&nbsp;
|&nbsp;
|&nbsp;
|-
! A depth
|align="right"| 1
|align="right"| 2
|align="right"| 3
|align="right"| 4
|align="right"| 8
|align="right"| 16
|align="right"| 32
|align="right"| 64
|align="right"| 128
|align="right"| 256
|align="right"| 512
|align="right"| 1,024
|align="right"| 2,048
|align="right"| 4,096
|align="right"| 8,192
|align="right"| 16,384
|align="right"| 32,768
|align="right"| 65,536
|align="right"| 131,072
|align="right"| 262,144
|align="right"| 524,288
|align="right"| 1,048,576
|align="right"| 2,097,152
|align="right"| 4,194,304
|align="right"| 8,388,608
|&nbsp;
|&nbsp;
|&nbsp;
|&nbsp;
|&nbsp;
|&nbsp;
|-
! B called
|align="right"| 0
|align="right"| 1
|align="right"| 2
|align="right"| 3
|align="right"| 7
|align="right"| 17
|align="right"| 37
|align="right"| 79
|align="right"| 166
|align="right"| 346
|align="right"| 721
|align="right"| 1,508
|align="right"| 3,167
|align="right"| 6,672
|align="right"| 14,090
|align="right"| 29,824
|align="right"| 63,286
|align="right"| 134,651
|align="right"| 287,263
|align="right"| 614,441
|align="right"| 1,317,532
|align="right"| 2,831,899
|align="right"| 6,100,851
|align="right"| 13,172,238
|align="right"| 28,499,826
|&nbsp;
|&nbsp;
|&nbsp;
|&nbsp;
|&nbsp;
|&nbsp;
|-
! B depth
|align="right"| 0
|align="right"| 1
|align="right"| 2
|align="right"| 3
|align="right"| 7
|align="right"| 15
|align="right"| 31
|align="right"| 63
|align="right"| 127
|align="right"| 255
|align="right"| 511
|align="right"| 1,023
|align="right"| 2,047
|align="right"| 4,095
|align="right"| 8,191
|align="right"| 16,383
|align="right"| 32,767
|align="right"| 65,535
|align="right"| 131,071
|align="right"| 262,143
|align="right"| 524,287
|align="right"| 1,048,575
|align="right"| 2,097,151
|align="right"| 4,194,303
|align="right"| 8,388,607
|&nbsp;
|&nbsp;
|&nbsp;
|&nbsp;
|&nbsp;
|&nbsp;
|}

View file

@ -0,0 +1,2 @@
---
note: Classic CS problems and programs

View file

@ -0,0 +1,9 @@
PROC a = (INT in k, PROC INT xl, x2, x3, x4, x5) INT:(
INT k := in k;
PROC b = INT: a(k-:=1, b, xl, x2, x3, x4);
( k<=0 | x4 + x5 | b )
);
test:(
printf(($gl$,a(10, INT:1, INT:-1, INT:-1, INT:1, INT:0)))
)

View file

@ -0,0 +1,36 @@
with Ada.Text_IO; use Ada.Text_IO;
procedure Man_Or_Boy is
function Zero return Integer is begin return 0; end Zero;
function One return Integer is begin return 1; end One;
function Neg return Integer is begin return -1; end Neg;
function A
( K : Integer;
X1, X2, X3, X4, X5 : access function return Integer
) return Integer is
M : Integer := K; -- K is read-only in Ada. Here is a mutable copy of
function B return Integer is
begin
M := M - 1;
return A (M, B'Access, X1, X2, X3, X4);
end B;
begin
if M <= 0 then
return X4.all + X5.all;
else
return B;
end if;
end A;
begin
Put_Line
( Integer'Image
( A
( 10,
One'Access, -- Returns 1
Neg'Access, -- Returns -1
Neg'Access, -- Returns -1
One'Access, -- Returns 1
Zero'Access -- Returns 0
) ) );
end Man_Or_Boy;

View file

@ -0,0 +1,30 @@
with Ada.Text_IO; use Ada.Text_IO;
procedure Man_Or_Boy is
function Zero return Integer is (0);
function One return Integer is (1);
function Neg return Integer is (-1);
function A
(K : Integer;
X1, X2, X3, X4, X5 : access function return Integer)
return Integer is
M : Integer := K; -- K is read-only in Ada. Here is a mutable copy of
function B return Integer is
begin
M := M - 1;
return A (M, B'Access, X1, X2, X3, X4);
end B;
begin
return (if M <= 0 then X4.all + X5.all else B);
end A;
begin
Put_Line
(Integer'Image
(A (K => 10,
X1 => One'Access,
X2 => Neg'Access,
X3 => Neg'Access,
X4 => One'Access,
X5 => Zero'Access)));
end Man_Or_Boy;

View file

@ -0,0 +1,81 @@
integer
F(list l)
{
return l_q_integer(l, 1);
}
integer (*type(integer (*f) (list))) (list)
{
return f;
}
integer
eval(list l)
{
return type(l_query(l, 0))(l);
}
integer A(list);
integer
B(list l)
{
integer x;
list a;
x = l_q_integer(l, 1);
x -= 1;
l_r_integer(l, 1, x);
l_append(a, B);
l_append(a, x);
l_l_list(a, -1, l);
l_l_list(a, -1, l_query(l, -5));
l_l_list(a, -1, l_query(l, -4));
l_l_list(a, -1, l_query(l, -3));
l_l_list(a, -1, l_query(l, -2));
return A(a);
}
integer
A(list l)
{
integer x;
if (l_q_integer(l, 1) < 1) {
x = eval(l_q_list(l, -2)) + eval(l_q_list(l, -1));
} else {
x = B(l);
}
return x;
}
integer
main(void)
{
list a, f1, f0, fn1;
l_append(f1, F);
l_append(f1, 1);
l_append(f0, F);
l_append(f0, 0);
l_append(fn1, F);
l_append(fn1, -1);
l_append(a, B);
l_append(a, 10);
l_l_list(a, -1, f1);
l_l_list(a, -1, fn1);
l_l_list(a, -1, fn1);
l_l_list(a, -1, f1);
l_l_list(a, -1, f0);
o_integer(A(a));
o_byte('\n');
return 0;
}

View file

@ -0,0 +1,20 @@
on a(k, x1, x2, x3, x4, x5)
script b
set k to k - 1
return a(k, b, x1, x2, x3, x4)
end script
if k 0 then
return (run x4) + (run x5)
else
return (run b)
end if
end a
on int(x)
script s
return x
end script
return s
end int
a(10, int(1), int(-1), int(-1), int(1), int(0))

View file

@ -0,0 +1,25 @@
HIMEM = PAGE + 200000000 : REM Increase recursion depth
FOR k% = 0 TO 20
PRINT FNA(k%, ^FN1(), ^FN_1(), ^FN_1(), ^FN1(), ^FN0())
NEXT
END
DEF FNA(k%, x1%, x2%, x3%, x4%, x5%)
IF k% <= 0 THEN = FN(x4%)(x4%) + FN(x5%)(x5%)
LOCAL b{}
DIM b{fn%, k%, x1%, x2%, x3%, x4%, x5%}
b.fn% = !^FNB()
b.k% = k%
b.x1% = x1%
b.x2% = x2%
b.x3% = x3%
b.x4% = x4%
b.x5% = x5%
DEF FNB(!(^b{}+4))
b.k% -= 1
= FNA(b.k%, b{}, b.x1%, b.x2%, b.x3%, b.x4%)
DEF FN0(d%) = 0
DEF FN1(d%) = 1
DEF FN_1(d%) = -1

View file

@ -0,0 +1,53 @@
#include <iostream>
#include <tr1/memory>
using std::tr1::shared_ptr;
using std::tr1::enable_shared_from_this;
struct Arg {
virtual int run() = 0;
virtual ~Arg() { };
};
int A(int, shared_ptr<Arg>, shared_ptr<Arg>, shared_ptr<Arg>,
shared_ptr<Arg>, shared_ptr<Arg>);
class B : public Arg, public enable_shared_from_this<B> {
private:
int k;
const shared_ptr<Arg> x1, x2, x3, x4;
public:
B(int _k, shared_ptr<Arg> _x1, shared_ptr<Arg> _x2, shared_ptr<Arg> _x3,
shared_ptr<Arg> _x4)
: k(_k), x1(_x1), x2(_x2), x3(_x3), x4(_x4) { }
int run() {
return A(--k, shared_from_this(), x1, x2, x3, x4);
}
};
class Const : public Arg {
private:
const int x;
public:
Const(int _x) : x(_x) { }
int run () { return x; }
};
int A(int k, shared_ptr<Arg> x1, shared_ptr<Arg> x2, shared_ptr<Arg> x3,
shared_ptr<Arg> x4, shared_ptr<Arg> x5) {
if (k <= 0)
return x4->run() + x5->run();
else {
shared_ptr<Arg> b(new B(k, x1, x2, x3, x4));
return b->run();
}
}
int main() {
std::cout << A(10, shared_ptr<Arg>(new Const(1)),
shared_ptr<Arg>(new Const(-1)),
shared_ptr<Arg>(new Const(-1)),
shared_ptr<Arg>(new Const(1)),
shared_ptr<Arg>(new Const(0))) << std::endl;
return 0;
}

View file

@ -0,0 +1,25 @@
#include <functional>
#include <iostream>
typedef std::function<int()> F;
static int A(int k, const F &x1, const F &x2, const F &x3, const F &x4, const F &x5)
{
F B = [=, &k, &B]
{
return A(--k, B, x1, x2, x3, x4);
};
return k <= 0 ? x4() + x5() : B();
}
static F L(int n)
{
return [n] { return n; };
}
int main()
{
std::cout << A(10, L(1), L(-1), L(-1), L(1), L(0)) << std::endl;
return 0;
}

View file

@ -0,0 +1,32 @@
#include <tr1/functional>
#include <iostream>
typedef std::tr1::function<int()> F;
static int A(int k, const F &x1, const F &x2, const F &x3, const F &x4, const F &x5);
struct B_class {
int &k;
const F x1, x2, x3, x4;
B_class(int &_k, const F &_x1, const F &_x2, const F &_x3, const F &_x4) :
k(_k), x1(_x1), x2(_x2), x3(_x3), x4(_x4) { }
int operator()() const { return A(--k, *this, x1, x2, x3, x4); }
};
static int A(int k, const F &x1, const F &x2, const F &x3, const F &x4, const F &x5)
{
F B = B_class(k, x1, x2, x3, x4);
return k <= 0 ? x4() + x5() : B();
}
struct L {
const int n;
L(int _n) : n(_n) { }
int operator()() const { return n; }
};
int main()
{
std::cout << A(10, L(1), L(-1), L(-1), L(1), L(0)) << std::endl;
return 0;
}

View file

@ -0,0 +1,43 @@
/* man-or-boy.c */
#include <stdio.h>
#include <stdlib.h>
// --- thunks
typedef struct arg
{
int (*fn)(struct arg*);
int *k;
struct arg *x1, *x2, *x3, *x4, *x5;
} ARG;
// --- lambdas
int f_1 (ARG* _) { return -1; }
int f0 (ARG* _) { return 0; }
int f1 (ARG* _) { return 1; }
// --- helper
int eval(ARG* a) { return a->fn(a); }
#define MAKE_ARG(...) (&(ARG){__VA_ARGS__})
#define FUN(...) MAKE_ARG(B, &k, __VA_ARGS__)
int A(ARG*);
// --- functions
int B(ARG* a)
{
int k = *a->k -= 1;
return A(FUN(a, a->x1, a->x2, a->x3, a->x4));
}
int A(ARG* a)
{
return *a->k <= 0 ? eval(a->x4) + eval(a->x5) : B(a);
}
int main(int argc, char **argv)
{
int k = argc == 2 ? strtol(argv[1], 0, 0) : 10;
printf("%d\n", A(FUN(MAKE_ARG(f1), MAKE_ARG(f_1), MAKE_ARG(f_1),
MAKE_ARG(f1), MAKE_ARG(f0))));
return 0;
}

View file

@ -0,0 +1,11 @@
#include <stdio.h>
#define INT(body) ({ int lambda(){ body; }; lambda; })
main(){
int a(int k, int xl(), int x2(), int x3(), int x4(), int x5()){
int b(){
return a(--k, b, xl, x2, x3, x4);
}
return k<=0 ? x4() + x5() : b();
}
printf(" %d\n",a(10, INT(return 1), INT(return -1), INT(return -1), INT(return 1), INT(return 0)));
}

View file

@ -0,0 +1,47 @@
#include <stdio.h>
#include <stdlib.h>
typedef struct frame
{
int (*fn)(struct frame*);
union { int constant; int* k; } u;
struct frame *x1, *x2, *x3, *x4, *x5;
} FRAME;
FRAME* Frame(FRAME* f, int* k, FRAME* x1, FRAME* x2, FRAME *x3, FRAME *x4, FRAME *x5)
{
f->u.k = k;
f->x1 = x1;
f->x2 = x2;
f->x3 = x3;
f->x4 = x4;
f->x5 = x5;
return f;
}
int F(FRAME* a) { return a->u.constant; }
int eval(FRAME* a) { return a->fn(a); }
int A(FRAME*);
int B(FRAME* a)
{
int k = (*a->u.k -= 1);
FRAME b = { B };
return A(Frame(&b, &k, a, a->x1, a->x2, a->x3, a->x4));
}
int A(FRAME* a)
{
return *a->u.k <= 0 ? eval(a->x4) + eval(a->x5) : B(a);
}
int main(int argc, char** argv)
{
int k = argc == 2 ? strtol(argv[1], 0, 0) : 10;
FRAME a = { B }, f1 = { F, { 1 } }, f0 = { F, { 0 } }, fn1 = { F, { -1 } };
printf("%d\n", A(Frame(&a, &k, &f1, &fn1, &fn1, &f1, &f0)));
return 0;
}

View file

@ -0,0 +1,25 @@
Procedure Main()
Local k
For k := 0 to 20
? "A(", k, ", 1, -1, -1, 1, 0) =", A(k, 1, -1, -1, 1, 0)
Next
Return
Static Function A(k, x1, x2, x3, x4, x5)
Local ARetVal
Local B := {|| --k, ARetVal := A(k, B, x1, x2, x3, x4) }
If k <= 0
ARetVal := Evaluate(x4) + Evaluate(x5)
Else
B:Eval()
Endif
Return ARetVal
Static Function Evaluate(x)
Local xVal
If ValType(x) == "B"
xVal := x:Eval()
Else
xVal := x
Endif
Return xVal

View file

@ -0,0 +1,24 @@
(declare a)
(defn man-or-boy
"Man or boy test for Clojure"
[k]
(let [k (atom k)]
(a k
(fn [] 1)
(fn [] -1)
(fn [] -1)
(fn [] 1)
(fn [] 0))))
(defn a
[k x1 x2 x3 x4 x5]
(let [k (atom @k)]
(letfn [(b []
(swap! k dec)
(a k b x1 x2 x3 x4))]
(if (<= @k 0)
(+ (x4) (x5))
(b)))))
(man-or-boy 10)

View file

@ -0,0 +1,16 @@
(defun man-or-boy (x)
(a x (lambda () 1)
(lambda () -1)
(lambda () -1)
(lambda () 1)
(lambda () 0)))
(defun a (k x1 x2 x3 x4 x5)
(labels ((b ()
(decf k)
(a k #'b x1 x2 x3 x4)))
(if (<= k 0)
(+ (funcall x4) (funcall x5))
(b))))
(man-or-boy 10)

View file

@ -0,0 +1,14 @@
import core.stdc.stdio: printf;
int a(int k, const lazy int x1, const lazy int x2, const lazy int x3,
const lazy int x4, const lazy int x5) pure {
int b() {
k--;
return a(k, b(), x1, x2, x3, x4);
}
return k <= 0 ? x4 + x5 : b();
}
void main() {
printf("%d\n", a(10, 1, -1, -1, 1, 0));
}

View file

@ -0,0 +1,14 @@
import std.stdio;
int A(int k, int delegate()[] x ...) {
int b() {
k--;
return A(k, &b, x[0], x[1], x[2], x[3]);
}
return (k <= 0) ? x[3]() + x[4]() : b();
}
void main() {
writeln(A(10, 1, -1, -1, 1, 0));
}

View file

@ -0,0 +1,28 @@
import std.stdio;
int delegate() mb(T)(T mob) { // embeding function
int b() {
static if (is(T == int))
return mob;
else
return mob();
}
return &b;
}
int A(T)(int k, T x1, T x2, T x3, T x4, T x5) {
static if (is(T == int)) {
return A(k, mb(x1), mb(x2), mb(x3), mb(x4), mb(x5));
} else {
int b() {
k--;
return A(k, &b, x1, x2, x3, x4);
}
return (k <= 0) ? x4() + x5() : b();
}
}
void main() {
writeln(A(10, 1, -1, -1, 1, 0));
}

View file

@ -0,0 +1,40 @@
import std.stdio;
interface B {
int run();
}
int A(int k, int x1, int x2, int x3, int x4, int x5) {
B mb(int a) {
return new class() B {
int run() {
return a;
}
};
}
return A(k, mb(x1), mb(x2), mb(x3), mb(x4), mb(x5));
}
int A(int k, B x1, B x2, B x3, B x4, B x5) {
if (k <= 0) {
return x4.run() + x5.run();
} else {
return (new class() B {
int m;
this() {
this.m = k;
}
int run() {
m--;
return A(m, this, x1, x2, x3, x4);
}
}).run();
}
}
void main() {
writeln(A(10, 1, -1, -1, 1, 0));
}

View file

@ -0,0 +1,76 @@
import std.bigint, std.functional;
// Adapted from C code by Goran Weinholt, adapted from Knuth code.
BigInt A(in int k, in int x1, in int x2, in int x3,
in int x4, in int x5) {
static struct Inner {
static BigInt _c1(in int k) {
switch (k) {
case 0: return BigInt(0);
case 1: return BigInt(0);
case 2: return BigInt(0);
case 3: return BigInt(1);
case 4: return BigInt(2);
case 5: return BigInt(3);
default: return c1(k - 1) + c2(k - 1);
}
}
alias memoize!_c1 c1;
static BigInt _c2(in int k) {
switch (k) {
case 0: return BigInt(0);
case 1: return BigInt(0);
case 2: return BigInt(1);
case 3: return BigInt(1);
case 4: return BigInt(1);
case 5: return BigInt(2);
default: return c2(k - 1) + c3(k - 1);
}
}
alias memoize!_c2 c2;
static BigInt _c3(in int k) {
switch (k) {
case 0: return BigInt(0);
case 1: return BigInt(1);
case 2: return BigInt(1);
case 3: return BigInt(0);
case 4: return BigInt(0);
case 5: return BigInt(1);
default: return c3(k - 1) + c4(k);
}
}
alias memoize!_c3 c3;
static BigInt _c4(in int k) {
switch (k) {
case 0: return BigInt(1);
case 1: return BigInt(1);
case 2: return BigInt(0);
case 3: return BigInt(0);
case 4: return BigInt(0);
case 5: return BigInt(0);
default: return c1(k - 1) + c4(k - 1) - 1;
}
}
alias memoize!_c4 c4;
static int c5(in int k) pure nothrow {
return !!k;
}
}
with (Inner)
return c1(k) * x1 + c2(k) * x2 + c3(k) * x3 +
c4(k) * x4 + c5(k) * x5;
}
void main() {
import std.stdio, std.conv, std.range;
foreach (i; 0 .. 40)
writeln(i, " ", A(i, 1, -1, -1, 1, 0));
writefln("...\n500 %-(%s\\\n %)",
std.range.chunks(dtext(A(500, 1, -1, -1, 1, 0)), 60));
}

View file

@ -0,0 +1,29 @@
type
TFunc<T> = reference to function: T;
function C(x: Integer): TFunc<Integer>;
begin
Result := function: Integer
begin
Result := x;
end;
end;
function A(k: Integer; x1, x2, x3, x4, x5: TFunc<Integer>): Integer;
var
b: TFunc<Integer>;
begin
b := function: Integer
begin
Dec(k);
Result := A(k, b, x1, x2, x3, x4);
end;
if k <= 0 then
Result := x4 + x5
else
Result := b;
end;
begin
Writeln(A(10, C(1), C(-1), C(-1), C(1), C(0))); // -67 output
end.

View file

@ -0,0 +1,15 @@
def a(var k, &x1, &x2, &x3, &x4, &x5) {
def bS; def &b := bS
bind bS {
to get() {
k -= 1
return a(k, &b, &x1, &x2, &x3, &x4)
}
}
return if (k <= 0) { x4 + x5 } else { b }
}
def p := 1
def n := -1
def z := 0
println(a(10, &p, &n, &n, &p, &z))

View file

@ -0,0 +1,9 @@
open list cell console
a k x1 x2 x3 x4 x5 | k <= 0 = x4! + x5!
| else = b!
where b () = m-- $ a (valueof m) b x1 x2 x3 x4
m = ref k
m-- = m |> mutate (valueof m - 1)
a 10 (\() -> 1) (\() -> --1) (\() -> --1) (\() -> 1) (\() -> 0)

View file

@ -0,0 +1,14 @@
class ManOrBoy
{
Void main()
{
echo(A(10, |->Int|{1}, |->Int|{-1}, |->Int|{-1}, |->Int|{1}, |->Int|{0}));
}
static Int A(Int k, |->Int| x1, |->Int| x2, |->Int| x3, |->Int| x4, |->Int| x5)
{
|->Int|? b
b = |->Int| { k--; return A(k, b, x1, x2, x3, x4) }
return k <= 0 ? x4() + x5() : b()
}
}

View file

@ -0,0 +1,56 @@
module man_or_boy
implicit none
contains
recursive integer function A(k,x1,x2,x3,x4,x5) result(res)
integer, intent(in) :: k
interface
recursive integer function x1()
end function
recursive integer function x2()
end function
recursive integer function x3()
end function
recursive integer function x4()
end function
recursive integer function x5()
end function
end interface
integer :: m
if ( k <= 0 ) then
res = x4()+x5()
else
m = k
res = B()
end if
contains
recursive integer function B() result(res)
m = m-1
res = A(m,B,x1,x2,x3,x4)
end function B
end function A
recursive integer function one() result(res)
res = 1
end function
recursive integer function minus_one() result(res)
res = -1
end function
recursive integer function zero() result(res)
res = 0
end function
end module man_or_boy
program test
use man_or_boy
write (*,*) A(10,one,minus_one,minus_one,one,zero)
end program test

View file

@ -0,0 +1,19 @@
package main
import "fmt"
func a(k int, x1, x2, x3, x4, x5 func() int) int {
var b func() int
b = func() int {
k--
return a(k, b, x1, x2, x3, x4)
}
if k <= 0 {
return x4() + x5()
}
return b()
}
func main() {
x := func(i int) func() int { return func() int { return i } }
fmt.Println(a(10, x(1), x(-1), x(-1), x(1), x(0)))
}

View file

@ -0,0 +1,24 @@
package main
import "fmt"
func A(k int, x1, x2, x3, x4, x5 func() int) (a int) {
var B func() int
B = func() (b int) {
k--
a = A(k, B, x1, x2, x3, x4)
b = a
return
}
if k <= 0 {
a = x4() + x5()
} else {
B()
}
return
}
func main() {
K := func(x int) func() int { return func() int { return x } }
fmt.Println(A(10, K(1), K(-1), K(-1), K(1), K(0)))
}

View file

@ -0,0 +1,11 @@
import Control.Monad
import Data.IORef
a k x1 x2 x3 x4 x5 = do r <- newIORef k
let b = do k <- pred !r
a k b x1 x2 x3 x4
if k <= 0 then liftM2 (+) x4 x5 else b
where f !r = modifyIORef r f >> readIORef r
main = a 10 #1 #(-1) #(-1) #1 #0 >>= print
where (#) f = f . return

View file

@ -0,0 +1,23 @@
record mutable(value) # we need mutable integers
# ... be obvious when we break normal scope rules
procedure main(arglist) # supply the initial k value
k := integer(arglist[1])|10 # .. or default to 10=default
write("Man or Boy = ", A( k, 1, -1, -1, 1, 0 ) )
end
procedure eval(ref) # evaluator to distinguish between a simple value and a code reference
return if type(ref) == "co-expression" then @ref else ref
end
procedure A(k,x1,x2,x3,x4,x5) # Knuth's A
k := mutable(k) # make k mutable for B
return if k.value <= 0 then # -> boy compilers may recurse and die here
eval(x4) + eval(x5) # the crux of separating man .v. boy compilers
else # -> boy compilers can run into trouble at k=5+
B(k,x1,x2,x3,x4,x5)
end
procedure B(k,x1,x2,x3,x4,x5) # Knuth's B
k.value -:= 1 # diddle A's copy of k
return A(k.value, create |B(k,x1,x2,x3,x4,x5),x1,x2,x3,x4) # call A with a new k and 5 x's
end

View file

@ -0,0 +1,10 @@
record defercall(proc,arglist) # light weight alternative to co-expr for MoB
procedure eval(ref) # evaluator to distinguish between a simple value and a code reference
return if type(ref) == "defercall" then ref.proc!ref.arglist else ref
end
procedure B(k,x1,x2,x3,x4,x5) # Knuth's B
k.value -:= 1 # diddle A's copy of k
return A(k.value, defercall(B,[k,x1,x2,x3,x4,x5]),x1,x2,x3,x4)# call A with a new k and 5 x's
end

View file

@ -0,0 +1,13 @@
A=:4 :0
L=.cocreate'' NB. L is context where names are defined.
k__L=:x
'`x1__L x2__L x3__L x4__L x5__L'=:y
if.k__L<:0 do.a__L=:(x4__L + x5__L)f.'' else. L B '' end.
(coerase L)]]]a__L
)
B=:4 :0
L=.x
k__L=:k__L-1
a__L=:k__L A L&B`(x1__L f.)`(x2__L f.)`(x3__L f.)`(x4__L f.)
)

View file

@ -0,0 +1,2 @@
10 A 1:`_1:`_1:`1:`0:
_67

View file

@ -0,0 +1,27 @@
public class ManOrBoy {
interface Arg {
public int run();
}
public static int A(final int k, final Arg x1, final Arg x2,
final Arg x3, final Arg x4, final Arg x5) {
if (k <= 0)
return x4.run() + x5.run();
return new Arg() {
int m = k;
public int run() {
m--;
return A(m, this, x1, x2, x3, x4);
}
}.run();
}
public static Arg C(final int i) {
return new Arg() {
public int run() { return i; }
};
}
public static void main(String[] args) {
System.out.println(A(10, C(1), C(-1), C(-1), C(1), C(0)));
}
}

View file

@ -0,0 +1,8 @@
function A(k, x1, x2, x3, x4, x5) {
function B() A(--k, B, x1, x2, x3, x4);
return k <= 0 ? x4() + x5() : B();
}
function K(n) function() n;
alert(A(10, K(1), K(-1), K(-1), K(1), K(0)));

View file

@ -0,0 +1,15 @@
function a(k,x1,x2,x3,x4,x5)
local function b()
k = k - 1
return a(k,b,x1,x2,x3,x4)
end
if k <= 0 then return x4() + x5() else return b() end
end
function K(n)
return function()
return n
end
end
print(a(10, K(1), K(-1), K(-1), K(1), K(0)))

View file

@ -0,0 +1,29 @@
MODULE Main;
IMPORT IO;
TYPE Function = PROCEDURE ():INTEGER;
PROCEDURE A(k: INTEGER; x1, x2, x3, x4, x5: Function): INTEGER =
PROCEDURE B(): INTEGER =
BEGIN
DEC(k);
RETURN A(k, B, x1, x2, x3, x4);
END B;
BEGIN
IF k <= 0 THEN
RETURN x4() + x5();
ELSE
RETURN B();
END;
END A;
PROCEDURE F0(): INTEGER = BEGIN RETURN 0; END F0;
PROCEDURE F1(): INTEGER = BEGIN RETURN 1; END F1;
PROCEDURE Fn1(): INTEGER = BEGIN RETURN -1; END Fn1;
BEGIN
IO.PutInt(A(10, F1, Fn1, Fn1, F1, F0));
IO.Put("\n");
END Main.

View file

@ -0,0 +1,14 @@
<?php
function A($k,$x1,$x2,$x3,$x4,$x5) {
$b = function () use (&$b,&$k,$x1,$x2,$x3,$x4) {
return A(--$k,$b,$x1,$x2,$x3,$x4);
};
return $k <= 0 ? $x4() + $x5() : $b();
}
echo A(10, function () { return 1; },
function () { return -1; },
function () { return -1; },
function () { return 1; },
function () { return 0; }) . "\n";
?>

View file

@ -0,0 +1,22 @@
<?php
function A($k,$x1,$x2,$x3,$x4,$x5) {
static $i = 0;
$b = "myfunction_$i";
$i++;
eval('function '.$b.'() {
static $k = '.$k.';
return A(--$k, '.var_export($b,true).',
'.var_export($x1,true).',
'.var_export($x2,true).',
'.var_export($x3,true).',
'.var_export($x4,true).');
}');
return $k <= 0 ? $x4() + $x5() : $b();
}
echo A(10, create_function('', 'return 1;'),
create_function('', 'return -1;'),
create_function('', 'return -1;'),
create_function('', 'return 1;'),
create_function('', 'return 0;')) . "\n";
?>

View file

@ -0,0 +1,8 @@
sub A {
my ($k, $x1, $x2, $x3, $x4, $x5) = @_;
my($B);
$B = sub { A(--$k, $B, $x1, $x2, $x3, $x4) };
$k <= 0 ? &$x4 + &$x5 : &$B;
}
print A(10, sub{1}, sub {-1}, sub{-1}, sub{1}, sub{0} ), "\n";

View file

@ -0,0 +1,8 @@
(de a (K X1 X2 X3 X4 X5)
(let (@K (cons K) B (cons)) # Explicit frame
(set B
(curry (@K B X1 X2 X3 X4) ()
(a (dec @K) (car B) X1 X2 X3 X4) ) )
(if (gt0 (car @K)) ((car B)) (+ (X4) (X5))) ) )
(a 10 '(() 1) '(() -1) '(() -1) '(() 1) '(() 0))

View file

@ -0,0 +1,13 @@
#!/usr/bin/env python
import sys
sys.setrecursionlimit(1025)
def a(in_k, x1, x2, x3, x4, x5):
k = [in_k]
def b():
k[0] -= 1
return a(k[0], b, x1, x2, x3, x4)
return x4() + x5() if k[0] <= 0 else b()
x = lambda i: lambda: i
print(a(10, x(1), x(-1), x(-1), x(1), x(0)))

View file

@ -0,0 +1,13 @@
#!/usr/bin/env python
import sys
sys.setrecursionlimit(1025)
def a(k, x1, x2, x3, x4, x5):
def b():
b.k -= 1
return a(b.k, b, x1, x2, x3, x4)
b.k = k
return x4() + x5() if b.k <= 0 else b()
x = lambda i: lambda: i
print(a(10, x(1), x(-1), x(-1), x(1), x(0)))

View file

@ -0,0 +1,12 @@
#!/usr/bin/env python
import sys
sys.setrecursionlimit(1025)
def A(k, x1, x2, x3, x4, x5):
def B():
nonlocal k
k -= 1
return A(k, B, x1, x2, x3, x4)
return x4() + x5() if k <= 0 else B()
print(A(10, lambda: 1, lambda: -1, lambda: -1, lambda: 1, lambda: 0))

View file

@ -0,0 +1,8 @@
n <- function(x) function()x
A <- function(k, x1, x2, x3, x4, x5) {
B <- function() A(k <<- k-1, B, x1, x2, x3, x4)
if (k <= 0) x4() + x5() else B()
}
A(10, n(1), n(-1), n(-1), n(1), n(0))

View file

@ -0,0 +1,15 @@
call.by.name <- function(...) {
cl <- as.list(match.call())
sublist <- lapply(cl[2:(length(cl)-1)],
function(name) substitute(substitute(evalq(.,.caller),
list(.=substitute(name))),
list(name=name)))
names(sublist) <- enquote(cl[2:(length(cl)-1)])
subcall <- do.call("call", c("list", lapply(sublist, enquote)))
fndef <- cl[[length(cl)]]
fndef[[3]] <- substitute({
.caller <- parent.frame()
eval(substitute(body, subcall))
}, list(body=fndef[[3]], subcall=subcall))
eval.parent(fndef)
}

View file

@ -0,0 +1,11 @@
A <- call.by.name(x1, x2, x3, x4, x5,
function(k, x1, x2, x3, x4, x5) {
Aout <- NULL
B <- function() {
k <<- k - 1
Bout <- Aout <<- A(k, B(), x1, x2, x3, x4)
}
if (k <= 0) Aout <- x4 + x5 else B()
Aout
}
)

View file

@ -0,0 +1,3 @@
> options(expressions=10000)
> mapply(A, 0:10, 1, -1, -1, 1, 0)
[1] 1 0 -2 0 1 0 1 -1 -10 -30 -67

View file

@ -0,0 +1,18 @@
> print(A, useSource=FALSE)
function (k, x1, x2, x3, x4, x5)
{
.caller <- parent.frame()
eval(substitute({
Aout <- NULL
B <- function() {
k <<- k - 1
Bout <- Aout <<- A(k, B(), x1, x2, x3, x4)
}
if (k <= 0) Aout <- x4 + x5 else B()
Aout
}, list(x1 = substitute(evalq(., .caller), list(. = substitute(x1))),
x2 = substitute(evalq(., .caller), list(. = substitute(x2))),
x3 = substitute(evalq(., .caller), list(. = substitute(x3))),
x4 = substitute(evalq(., .caller), list(. = substitute(x4))),
x5 = substitute(evalq(., .caller), list(. = substitute(x5))))))
}

View file

@ -0,0 +1,11 @@
#lang racket
(define (A k x1 x2 x3 x4 x5)
(define (B)
(set! k (- k 1))
(A k B x1 x2 x3 x4))
(if (<= k 0)
(+ (x4) (x5))
(B)))
(A 10 (lambda () 1) (lambda () -1) (lambda () -1) (lambda () 1) (lambda () 0))

View file

@ -0,0 +1,6 @@
def a(k, x1, x2, x3, x4, x5)
b = lambda { k -= 1; a(k, b, x1, x2, x3, x4) }
k <= 0 ? x4[] + x5[] : b[]
end
puts a(10, lambda {1}, lambda {-1}, lambda {-1}, lambda {1}, lambda {0})

View file

@ -0,0 +1,9 @@
def A(in_k: Int, x1: =>Int, x2: =>Int, x3: =>Int, x4: =>Int, x5: =>Int): Int = {
var k = in_k
def B: Int = {
k = k-1
A(k, B, x1, x2, x3, x4)
}
if (k<=0) x4+x5 else B
}
println(A(10, 1, -1, -1, 1, 0))

View file

@ -0,0 +1,9 @@
(define (A k x1 x2 x3 x4 x5)
(define (B)
(set! k (- k 1))
(A k B x1 x2 x3 x4))
(if (<= k 0)
(+ (x4) (x5))
(B)))
(A 10 (lambda () 1) (lambda () -1) (lambda () -1) (lambda () 1) (lambda () 0))

View file

@ -0,0 +1,11 @@
proc A {k x1 x2 x3 x4 x5} {
expr {$k<=0 ? [eval $x4]+[eval $x5] : [B \#[info level]]}
}
proc B {level} {
upvar $level k k x1 x1 x2 x2 x3 x3 x4 x4
incr k -1
A $k [info level 0] $x1 $x2 $x3 $x4
}
proc C {val} {return $val}
interp recursionlimit {} 1157
A 10 {C 1} {C -1} {C -1} {C 1} {C 0}

View file

@ -0,0 +1,5 @@
proc AP {k x1 x2 x3 x4 x5} {expr {$k<=0 ? [eval $x4]+[eval $x5] : [BP \#[info level] $x1 $x2 $x3 $x4]}}
proc BP {level x1 x2 x3 x4} {AP [uplevel $level {incr k -1}] [info level 0] $x1 $x2 $x3 $x4}
proc C {val} {return $val}
interp recursionlimit {} 1157
AP 10 {C 1} {C -1} {C -1} {C 1} {C 0}