[plt-scheme] macros, special forms, and lazy functions

From: Jos Koot (jos.koot at telefonica.net)
Date: Thu Dec 10 14:09:11 EST 2009

----- Original Message ----- 
From: "Stephen Bloch" <sbloch at adelphi.edu>
To: "PLTScheme List" <plt-scheme at list.cs.brown.edu>
Sent: Thursday, December 10, 2009 5:53 PM
Subject: [plt-scheme] macros, special forms, and lazy functions

> As far as my beginning students are concerned, "and" and "or" are  functions with contract
> Boolean Boolean ... -> Boolean
> They happen to be "smart" about their arguments, not bothering to  evaluate the later arguments if the earlier arguments answer 
> the  question.

In fact -> any (including multiple values), for example:
(and #t #t (values 1 2)) --> multiple value 1 2

> But in fact, they're implemented as macros or special forms.  (Is  there a difference between a macro and a special form?)  Which 
> makes  no difference in BSL, BSLLA, or ISL, but once we get to ISLL, it  makes a difference: one cannot pass "or" or "and" as 
> arguments to a  function that expects a function.

I think a special form is a is a definition or expression that starts with a syntactic keyword (an identifier that in its scope is 
recognized as a syntactioc keyword) A macro or transformer is an expansion time procedure that does the expansion of a special form 
(at expansion time)

> Is it feasible for a function in (say) ISLL to refer to a function  whose definition is in a module written in Lazy Scheme?  If 
> so, would  it be reasonable to define "and" and "or" that way, so they could be  passed around as functions?

Imagine you try to use the #%app hook to delay the evaluation of the arguments of and and or. Then write functions <and> and <or> 
that do force their arguments as far as necessary. For this you could make a simple language that exports all of scheme or 
scheme/base except that it exports its own versions of #%app, and and or. However, in this case <and> and <or> have to be recognized 
by #%app at expansion time which means that something like ((if test and or) arg ...) would not work. Mixing eager and lazy code is 
very difficult, I think.

> Failing that, would it be reasonable to define "and" and "or" in such  a way that if they appear other than in function-call 
> position, they  evaluate to a function that does the right thing, so again they could  be passed around as functions?

Something like:

#lang scheme

(provide (rename-out (or* or)))

(define-syntax (or* stx)
 (syntax-case stx (or*)
  ((or* arg ...) #'(or arg ...))
  (or* #'or**)))

(define (or** . args)
  ((null? args) #t)
  ((null? (cdr args)) (car args))
  (else (or (car args) (apply or** (cdr args))))))

((if #t or* list) 1 (write 2) (write 3))
; --> writes 2 and 3, returns 1
(or* 1 (write 2) (write 2))
; does not write, returns 1.

However it seems pretty messy to me <or> sometimes evaluating all <arguments> and sometimes just as many as needed. Why not stick to 
and and or as special forms and use regular functions with slightly different names (like andf and orf) where a function is wanted 
(implying that all their arguments are evaluated)

The same questions can be asked for <if>. In regular scheme it is a syntactic keyword, but in lazy scheme it is a variable bound to 
a procedure.

#lang lazy
(write ((if #t if list) 1 2 3)) --> writes 2
(write ((if #f if list) 1 2 3)) --> writes (1 2 3)


> Stephen Bloch
> sbloch at adelphi.edu
> _________________________________________________
>  For list-related administrative tasks:
>  http://list.cs.brown.edu/mailman/listinfo/plt-scheme

Posted on the users mailing list.