composition of functions

Kevin B. Kenny KE9TV kkenny at wind.nrtc.northrop.com
Wed Feb 13 10:07:35 AEST 1991


Reading all the flamage about composable functions, I am forced to
note that everyone appears to agree:
	(1) Functions are not first-class objects in C
	(2) Composition is a difficult notion to express in C.
The disagreements are on the subject of whether this problem is a
major failing in the language.

With the advent of C++, the question is (almost) moot, as compositions
*are* trivial in the latter language.  The trick is to represent
functions explicitly and use operator() as the means of evaluating
them.  Will all of the arguing parties agree that the following short
program (almost) does the right thing?

[NOTE: The (almost) above is included because I can't define new
operators that act on the existing basic types.  Which is the reason
for the #ifdef NEVER, and the kludge of composing everything with the
`id' function.

It's also somewhat awkward that you can't extract a
`pointer-to-function' out of a Function, but it should be obvious why
not.  A `pointer-to-Function' is ALMOST as useful.]

Anyone for working these into an existing class library? A
Smalltalk-flavored one like NIHCL would be a better choice, since the
functionals could work with the type Object (&) (const Object &const),
and the Function class wuldn't have to be replicated for each
combination of parameter type and return type.  Templates would be
ALMOST as suitable.

Kevin Kenny, KE9TV
   cur           w        d      dis     and p
a     sed f iend  rought   eath     ease      ain.
  bles     r     b       br     and         ag

// -*- C++ -*-

#include <stream.h>

// Base class of composable function

class Function {
public:
  virtual int operator () (int) = 0;
};

// The ordinary composable function: construct around a
// reference-to-function-returning-int.


class OrdinaryFunction : public Function {
private:
  int (&f) (int);
public:
  OrdinaryFunction (int (&fn) (int)) : f (fn) {}
  virtual int operator () (int x) { return f (x); }
};

// A composition (functional form) -- construct around two composable functions

class Composition : public Function {
private:
  Function& first;
  Function& second;
public:
  Composition (Function& two, Function& one) 
    : first (one), second (two) {}
  virtual operator () (int x) { return second (first (x)); }
};

#ifdef NEVER
// I'd like to do this....
Function& operator * (int (&two) (int), int (&one) (int))
{
  return *new Composition (*new OrdinaryFunction (two),
			   *new OrdinaryFunction (one));
}
#endif

// The identity function

static int idem (int x) { return x; }

OrdinaryFunction id (idem);

// Syntactic sugar for compositions

Function& operator * (Function& two, int (&one) (int))
{
  return *new Composition (two, *new OrdinaryFunction (one));
}

Function& operator * (int (&two) (int), Function& one)
{
  return *new Composition (*new OrdinaryFunction (two), one);
}

Function& operator * (Function& two,
				Function& one)
{
  return *new Composition (two, one);
}

// The square function

int square (int x)
{
  return x * x;
}

// Let's test some things out.

int main (int, char **)
{
  // Make some compositions

  Function& sqsq = id * square * square;
  Function& sqsqsq = id * square * square * square;

  // Try functions and compositions

  cout << "square (2) = " << square (2) << "\n";
  cout << "sqsq (2)   = " << sqsq (2)   << "\n";
  cout << "sqsqsq (2) = " << sqsqsq (2) << "\n";

  // Try creating a composition on the fly.

  cout << "(square * square) (3) = " << (id * square * square) (3) << "\n";
  return 0;
}



More information about the Comp.lang.c mailing list