[comp.lang.scheme] Normal order

STCS8004%IRUCCVAX.UCC.IE@mitvma.mit.EDU (05/08/91)

In response to my question:

    ... *WHY NOT ALLOW THE USER* to specify normal evaluation
    when required?

John Gateley responds <GATELEY.91May3125853@datura.rice.edu>:

   Just out of curiosity, how would you compile the following function:
   (define foo
     (lambda (f x y z)
       (f z y x)))
   Consider (foo + 1 2 3) and (foo if else then pred)?
   The arguments to ANY application must be assumed to be passed in
   normal order unless you can prove otherwise. Is this what you really
   want?

No, and I hope that that isn't the unavoidable consequence! As I understand
your  point, when  the evaluator  encounters (foo  ... )  it will  not know
whether to evaluate the arguments or  not, since in the definition of 'foo'
there is nothing  to indicate what is to  be done. In the one  case all the
arguments to (f ...) need to be strict  and in the other not. But if, as in
Pascal, Algol 60, ... one is allowed  to specify the calling style for each
parameter at definition time is there still a problem? Thus couldn't

    (define f
       (lambda (x #!normal y)
           (... x  ... y ...)))

be compiled as though we had written

    (define f
        (lambda (x y)
           (... x ... (y) ...)))

and the decision whether or not to pass <arg2> by value or as a thunk in
(f <arg1> <arg2>) be made when checking that 'f' has been given two
arguments - whether compiling or interpreting?

Gordon Oulsnam                              stcs8004@iruccvax.ucc.hea.ie

PS to all readers:

  I will be incommunicado from 1600 GMT 91/05/08 to 91/05/23 so cannot
  respond immediately to messages *received* in that period (Digest 211
  and later) but will reply/summarize as appropriate on return.    G.O.

jinx@zurich.ai.mit.edu (Guillermo J. Rozas) (05/09/91)

    No, and I hope that that isn't the unavoidable consequence! As I understand
    your  point, when  the evaluator  encounters (foo  ... )  it will  not know
    whether to evaluate the arguments or  not, since in the definition of 'foo'
    there is nothing  to indicate what is to  be done. In the one  case all the
    arguments to (f ...) need to be strict  and in the other not. But if, as in
    Pascal, Algol 60, ... one is allowed  to specify the calling style for each
    parameter at definition time is there still a problem? Thus couldn't

	(define f
	   (lambda (x #!normal y)
	       (... x  ... y ...)))

    be compiled as though we had written

	(define f
	    (lambda (x y)
	       (... x ... (y) ...)))

    and the decision whether or not to pass <arg2> by value or as a thunk in
    (f <arg1> <arg2>) be made when checking that 'f' has been given two
    arguments - whether compiling or interpreting?

The problem is that f may be separately compiled (ie. in another
module), not visible to the compiler.  The compiler must assume the
worst in order to be correct, and either compile two versions of the
code (for every call), or compile arguments as if they were thunks,
and then invoke them if f is found not to expect normal-order
parameters.

Even in the case of non-separately compiled programs, how are we
supposed to handle things like the following?

  ((vector-ref some-vector 23) (+ x y) (foo x))

or even

(define (map-2 f l1 l2)
  (cond ((and (pair? l1)
	      (pair? l2))
	 (cons (f (car l) (car l2))
	       (map-2 f (cdr l1) (cdr l2))))
	((or (null? l1)
	     (null? l2))
	 '())
	(else
	 (error "map-2: Bad arguments" l1 l2))))

When the system was built, neither the compiler nor even the system
designer can know the range of values that might be passed to map-2
(or map, or for-each, etc.), so the worst case must be assumed.
But that means that everyone pays the cost, not only those people
using normal-order parameter-passing.

I'm afraid that it IS the unavoidable consequence, and that is why not
many implement systems with both normal order and applicative order
parameters.