kkenny@wind.nrtc.northrop.com (Kevin B. Kenny KE9TV) (02/13/91)
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; }
bliss@sp64.csrd.uiuc.edu (Brian Bliss) (02/14/91)
>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. 1) i agree with. 2) say you have two functions, int f (int x); int g (int x); what's so hard about writing: int fg (int x) { return (f(g(x)); } ??????????????????? bb
sw@smds.UUCP (Stephen E. Witham) (02/15/91)
In article <17621@gremlin.nrtc.northrop.com>, kkenny@wind.nrtc.northrop.com (Kevin B. Kenny KE9TV) writes: > 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. I don't agree with number two. I think composing functions in C is pretty easy and useful. In fact, I think quite a few others either know this or would grudgingly admit it, or suspect that it's true. But the religious fervor is concentrated on the "first-classness" issue. The problems with doing it in C center around: o Composing functions that take and return more than one type. o The impossibility of using composed functions interchangeably with regular C functions. o The fact that you have to take care of deallocating things. My impression from your posting is that C++ can do this stuff a little more easily than C, but that it still has these problems. But I can't read C++, so could you comment on these particular thorns? --Steve Witham Not-the-fault-of: SMDS, Inc., Concord, MA
ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe) (02/15/91)
In article <1991Feb13.212250.27437@csrd.uiuc.edu>, bliss@sp64.csrd.uiuc.edu (Brian Bliss) writes: > (2) Composition is a difficult notion to express in C. > 2) > say you have two functions, > int f (int x); int g (int x); > what's so hard about writing: > int fg (int x) { return (f(g(x)); } There's nothing hard about it, but it answers the wrong question. The question was: how do I write a function typedef int i2ifn(int); i2ifn compose(i2ifn f, i2ifn g) { /* fill this in */ } so that compose(f,g)(x) == f(g(x)). In Scheme, it's trivial: (define (compose f g) (lambda (x) (f (g x)) )) The answer is that there isn't any way of doing it portably in C where i2ifns are plain ordinary C functions of the indicated type. There are various kludges that let you work with things that are not *C* functions, and there are some machine-specific hacks, but portable plain C, no. (The best answer is probably to use Scheme->C.) -- Professional programming is paranoid programming