[plt-scheme] 202.2

From: Eli Barzilay (eli at barzilay.org)
Date: Wed Sep 11 13:22:22 EDT 2002

On Sep  9, Matthew Flatt wrote:
> 202.2 supports structure types whose instances act as procedures.

Just a wild idea: what if for *every* bad application, instead of
throwing an exception, some special-application parameter would be
consulted first allowing it to pull out a function?  You could hack
all those tricks that allow using any primitive container as a
function:

  > (require "special-apply.ss")
  > (define a '(1 2 3 4 5))
  > (a 1)
  procedure application: expected procedure, given: (1 2 3 4 5);
  arguments were: 1
  > (current-special-application-handler
     (let ((old (current-special-application-handler)))
       (lambda (x)
         (if (list? x)
           (lambda (n) (list-ref x n))
           (old x)))))
  > (a 1)
  2

or:

  > (current-special-application-handler
     (let ((old (current-special-application-handler)))
       (lambda (x)
         (if (regexp? x)
           (lambda args
             (case (length args)
               ((1) (apply regexp-match x args))
               ((2) (apply regexp-replace x args))
               (else (error 'regexp
                            "~e: wrong number of arguments" x))))
           (old x)))))
  > ((regexp "oo") "foo")
  ("oo")
  > ((regexp "oo") "foo" "u")
  "fu"

or even cute things like:

  > (current-special-application-handler
     (let ((old (current-special-application-handler)))
       (lambda (x)
         (if (number? x)
           (lambda args
             (cond ((null? args) x)
                   ((or (null? (cdr args)) (null? (cddr args)))
                    (apply (car args) x (cdr args)))
                   (else (error 'number
                                "~e: wrong number of arguments" x))))
           (old x)))))
  > (1)
  1
  > (1 -)
  -1
  > (let ((plus +)) (5 plus 6))
  11
  > (define (squared x) (x * x))
  > (4 squared)
  16

(It's nice to show that you can do infix without macros -- of course
for anything more "real" the weight should be shifted to a
transformer.  BTW, this is not another "I have a bright idea for
improving the prefix syntax" things, just a nice demonstration...)

Adding this to the implementation wouldn't slow normal execution since
it only does stuff when an exception should occur.  And given that if
it is there, then there is no price paid for the handler setup, just
the call to return the actual function...

Here is a quick hack that almost does it (couldn't find a way to
distinguish an exception caused by a bad function and a bad argument):

----------------------------------------------------------------------
(module special-apply mzscheme
  (provide (all-from-except mzscheme #%app apply)
           current-special-application-handler
           (rename special-app #%app) (rename special-apply apply))
  (define current-special-application-handler
    (make-parameter (lambda (x) #f)))
  (define (exn-handler exn func . args)
    (cond ((and (eq? func (exn:application-value exn))
                ((current-special-application-handler) func)) =>
           (lambda (new-func) (special-apply new-func args)))
          (else (raise exn))))
  (define (special-apply func . args)
    (let ((args (apply list* args)))
      (with-handlers
          ((exn:application:type?
            (lambda (exn) (apply exn-handler exn func args))))
        (apply func args))))
  (define-syntax special-app
    (syntax-rules ()
      ((_) ())
      ((_ func . args)
       (let ((f func))
         (with-handlers ((exn:application:type?
                          (lambda (exn) (exn-handler exn f . args))))
           (#%app f . args)))))))
----------------------------------------------------------------------

Well, if nobody takes this seriously, it's at least another demo of
the wonderful hacks you can do when you have those special syntaxes...

-- 
          ((lambda (x) (x x)) (lambda (x) (x x)))          Eli Barzilay:
                  http://www.barzilay.org/                 Maze is Life!



Posted on the users mailing list.