[taos-glug] Re: my progress report

  • From: Jonathan Bartlett <johnnyb@xxxxxxxxxx>
  • To: taos-glug@xxxxxxxxxxxxx
  • Date: Mon, 4 Aug 2003 12:06:49 -0700 (PDT)

One thing I find missing in most Scheme texts is the usefulness of being
able to combine functions.

Let's say I have a sort function that can be called like this: (sort
comparator list), where comparator is a function that compares items a and
b.  The nice thing about this is that it is both very modular and very
easy to use.  For example, if I wanted to sort numbers in ascending order,
I could just do:

(sort (lambda (a b) (if (> a b) #t #f)) '(1 6 2 3 6 5 7 5 3))

And get the result.  If I do this often, I can make a function for this
particular case:

(define numeric-comparator (lambda (a b) (if (> a b) #t #f)))

so I can do

(sort numeric-comparator '(32 25 25 23 352 25 235235))

and get an answer.  Let's say I want to do something more complicated.
Let's say I want to count the number of comparisons that occur.  I can
create a function that counts each comparison:

(define counter 0)
(define counting-comparator (lambda (a b) (set! counter (+ counter 1) )
(numeric-comparator a b))

Now, this isn't very good, because it uses a global variable.  So we can
transform it into one that generates a function that uses local-variables:

(define make-counting-comparator (lambda ()
        (let
                (
                        (count 0)
                )
                (list
                        (lambda (a b)
                                (set! count (+ count 1))
                                (numeric-comparator a b)
                        )
                        (lambda ()
                                count
                        )
                )
        )
))

Calling make-counting-comparator will return two functions - the first one
is the comparing function, and the second one will tell the current value
of count.  Every time you run make-counting-comparator, the functions
created will be using their own local copy of count.

So, to use this in a function, we would do:

(let
        (
                (funcs (make-counting-comparator))
        )
        (sort (car funcs) the-list)
        ( (car (cdr funcs) ) )
)

Which would result in the number of comparisons used to sort the list.

However, there's still a problem - make-counting-comparator only works for
numbers!  We would have to build a new one for every type of record we
wanted to sort.  Luckily, scheme is good at building functions!  We simply
need an argument to make-counting-comparator to say which comparison
function we want to use.

So, if we redefine it as this:

(define make-counting-comparator (lambda (my-comparator)
        (let
                (
                        (count 0)
                )
                (list
                        (lambda (a b)
                                (set! count (+ count 1))
                                (my-comparator a b)
                        )
                        (lambda ()
                                count
                        )
                )
        )
))

Now, I have separated the comparison operation from the counting
operation, but they are combinable in any combination I choose!  And, we
never had to deviate from the standard sort function!

You can make it even more interesting by using continuations to stop the
sorting if it is taking too long (i.e. - after N comparisons), or to
prompt the user if they want to wait or cancel the operation.

Anyway, the possibilities go on and on with functional abstraction.
However, functional abstraction requires the use of closures and
continuations.  While you can fake closures with objects (and the other
way around), continuations are blatantly missing from modern programming
languages.  However, using objects to implement closures usually makes
your code really, really complicated and long-winded.

Jon


Other related posts: