Man Or Boy

Test proposed by DonaldKnuth to separate the men (AlgolLanguage compilers that correctly implemented CallByName) from the boys (those that do not).

   begin real procedure A(k, x1, x2, x3, x4, x5);
     value k; integer k;
     begin real procedure B;
        begin k := k - 1;
              B := A := A(k, B, x1, x2, x3, x4)
        end;
        if k <= 0 then A := x4 + x5 else B
     end;
     outreal(A(10, 1, -1, -1, 1, 0))
   end;

The correct answer is -67, but I haven't figured out why yet.

-- DavidBrantley

This creates a tree of B call frames that refer to each other and to the containing A call frames, each of which has its own copy of k that changes every time the associated B is called. Trying to work it through on paper is probably fruitless, but here's some equivalent C++ code you could trace through:

 #include <iostream>
 #include <ostream>

// Functor template class supporting names - name-of-T becomes // name<T> &. template<typename T> class name { public: virtual T operator()() = 0; };

// Template class for passing constants by name. template<typename T> class constant : public name<T> { public: constant(T value) : value(value) {} virtual T operator()() { return value; }

private: T value; };

double A(int k, name<double> & x1, name<double> & x2, name<double> & x3, name<double> & x4, name<double> & x5);

class B : public name<double> { public: B(int & k, name<double> & x1, name<double> & x2, name<double> & x3, name<double> & x4, name<double> & x5) : k(k), x1(x1), x2(x2), x3(x3), x4(x4), x5(x5) { } virtual double operator()() { --k; return A(k, *this, x1, x2, x3, x4); }

private: int & k; name<double> & x1, & x2, & x3, & x4, & x5; };

double A(int k, name<double> & x1, name<double> & x2, name<double> & x3, name<double> & x4, name<double> & x5) { if (k <= 0) { // Force evaluation of x4 before x5. double temp = x4(); return temp + x5(); } else return B(k, x1, x2, x3, x4, x5)(); }

int main() { std::cout << A(10, constant<double>(1), constant<double>(-1), constant<double>(-1), constant<double>(1), constant<double>(0)) << std::endl; }


EditText of this page (last edited October 24, 2003) or FindPage with title or text search