From: Adam Warner
Subject: Scheme closures
Date: 
Message-ID: <pan.2004.04.17.12.09.43.302030@consulting.net.nz>
Hi all,

Please try your best to translate this Common Lisp code to Scheme:

(let ((state 0))
  (defun inc ()
    (incf state))
  (defun dec ()
    (decf state))
  (defun reset ()
    (setf state 0)))

`state' is only accessible through the (inc), (dec) and (reset) API. A
Scheme solution must provide no other access to the `state' variable.

I believe a Scheme translation could demonstrate the costs of no specially
defined compilation semantics, but I'll reserve judgement until I can see
how a Scheme expert would translate the above code. For Common Lispers:
`define' appears to no longer create globally accessible definitions in
the three implementations I have tested (Kawa, Bigloo and SISC) when it's
not a top-level form. Of course in Common Lisp all the above function
definitions are still treated as top-level forms even though they are
wrapped in a `let'.

Thanks for your help,
Adam

From: Matthias Felleisen
Subject: Re: Scheme closures
Date: 
Message-ID: <c5rc1m$2md$1@camelot.ccs.neu.edu>
Adam Warner wrote:

> Hi all,
> 
> Please try your best to translate this Common Lisp code to Scheme:
> 
> (let ((state 0))
>   (defun inc ()
>     (incf state))
>   (defun dec ()
>     (decf state))
>   (defun reset ()
>     (setf state 0)))

PLT Scheme:

(define-values (inc dec reset)
   (let ([state 0])
     (values (lambda () (set! state (+ state 1)))
             (lambda () (set! state (- state 1)))
             (lambda () (set! state 0))))

-- Matthias
From: Christophe Rhodes
Subject: Re: Scheme closures
Date: 
Message-ID: <sq3c72wza5.fsf@lambda.dyndns.org>
Adam Warner <······@consulting.net.nz> writes:

> Hi all,
>
> Please try your best to translate this Common Lisp code to Scheme:
>
> (let ((state 0))
>   (defun inc ()
>     (incf state))
>   (defun dec ()
>     (decf state))
>   (defun reset ()
>     (setf state 0)))

I am far from a scheme expert.

(begin
  (define inc)
  (define dec)
  (define reset)
  (let ((state 0))
    (set! inc (lambda () (set! state (+ state 1)) state))
    (set! dec (lambda () (set! state (- state 1)) state))
    (set! reset (lambda () (set! state 0) state))))

> Of course in Common Lisp all the above function
> definitions are still treated as top-level forms even though they are
> wrapped in a `let'.

No they're not.  The difference lies in the differing semantics of
scheme's define at top-level and not, not the toplevelness of the
DEFUN forms.

Christophe
-- 
http://www-jcsu.jesus.cam.ac.uk/~csr21/       +44 1223 510 299/+44 7729 383 757
(set-pprint-dispatch 'number (lambda (s o) (declare (special b)) (format s b)))
(defvar b "~&Just another Lisp hacker~%")    (pprint #36rJesusCollegeCambridge)
From: Grzegorz =?UTF-8?B?Q2hydXBhxYJh?=
Subject: Re: Scheme closures
Date: 
Message-ID: <c5r9bk$sqt$1@news.ya.com>
Adam Warner wrote:

> Hi all,
> 
> Please try your best to translate this Common Lisp code to Scheme:
> 
> (let ((state 0))
>   (defun inc ()
>     (incf state))
>   (defun dec ()
>     (decf state))
>   (defun reset ()
>     (setf state 0)))
> 
> `state' is only accessible through the (inc), (dec) and (reset) API. A
> Scheme solution must provide no other access to the `state' variable.
> 
> I believe a Scheme translation could demonstrate the costs of no specially
> defined compilation semantics

I don't think I understand what you mean by that, but here is one of the
possible translations, FWIW:

(define-values (inc! dec! reset!)
  (let ((state 0))
    (values
     (lambda () (set! state (+ state 1)))
     (lambda () (set! state (- state 1)))
     (lambda () (set! state 0)))))


> For Common Lispers:
> `define' appears to no longer create globally accessible definitions in
                      ^^ ^^^^^^
Was it different in the past?

-- 
Grzegorz Chrupała | http://pithekos.net | ·········@jabber.org
It seems that most major problems in the world, from Northern Ireland
to the Middle East, have arisen because people know too much history.
                           -- John D. Barrow
From: Marco Antoniotti
Subject: Re: Scheme closures
Date: 
Message-ID: <Caggc.42$a5.8618@typhoon.nyu.edu>
Grzegorz Chrupała wrote:

> Adam Warner wrote:
> 
> 
>>Hi all,
>>
>>Please try your best to translate this Common Lisp code to Scheme:
>>
>>(let ((state 0))
>>  (defun inc ()
>>    (incf state))
>>  (defun dec ()
>>    (decf state))
>>  (defun reset ()
>>    (setf state 0)))
>>
>>`state' is only accessible through the (inc), (dec) and (reset) API. A
>>Scheme solution must provide no other access to the `state' variable.
>>
>>I believe a Scheme translation could demonstrate the costs of no specially
>>defined compilation semantics
> 
> 
> I don't think I understand what you mean by that, but here is one of the
> possible translations, FWIW:
> 
> (define-values (inc! dec! reset!)
>   (let ((state 0))
>     (values
>      (lambda () (set! state (+ state 1)))
>      (lambda () (set! state (- state 1)))
>      (lambda () (set! state 0)))))


`define-values' is not Scheme (at least in R^nRS).

Cheers
--
Marco
From: Marco Antoniotti
Subject: Re: Scheme closures
Date: 
Message-ID: <%3ggc.41$a5.8618@typhoon.nyu.edu>
I'll give it a shot.

(define inc (lambda () ()))  ; Not strictly necessary.
(define dec (lambda () ()))
(define reset (lambda () ()))

(let ((state 0))
   (set! inc
      (lambda ()
      ;; Ooops: there is no INCF in Scheme, I need to load some CL
      ;; compatibility library.
        (set! state (+ 1 state))
        state
      ))
   (set! dec
      (lambda ()
      ;; Ooops: there is no DECF in Scheme, I need to load some CL
      ;; compatibility library.
        (set! state (- state 1))
        state
      ))
   (set! reset
      (lambda ()
        (set! state 0))))

That pretty much sums it up, doesn't it? :)

Cheers

Marco






Adam Warner wrote:

> Hi all,
> 
> Please try your best to translate this Common Lisp code to Scheme:
> 
> (let ((state 0))
>   (defun inc ()
>     (incf state))
>   (defun dec ()
>     (decf state))
>   (defun reset ()
>     (setf state 0)))
> 
> `state' is only accessible through the (inc), (dec) and (reset) API. A
> Scheme solution must provide no other access to the `state' variable.
> 
> I believe a Scheme translation could demonstrate the costs of no specially
> defined compilation semantics, but I'll reserve judgement until I can see
> how a Scheme expert would translate the above code. For Common Lispers:
> `define' appears to no longer create globally accessible definitions in
> the three implementations I have tested (Kawa, Bigloo and SISC) when it's
> not a top-level form. Of course in Common Lisp all the above function
> definitions are still treated as top-level forms even though they are
> wrapped in a `let'.
> 
> Thanks for your help,
> Adam
From: Adam Warner
Subject: Re: Scheme closures
Date: 
Message-ID: <pan.2004.04.17.22.52.52.91675@consulting.net.nz>
Hi Marco Antoniotti,

> I'll give it a shot.
> 
> (define inc (lambda () ()))  ; Not strictly necessary.
> (define dec (lambda () ()))
> (define reset (lambda () ()))
> 
> (let ((state 0))
>    (set! inc
>       (lambda ()
>       ;; Ooops: there is no INCF in Scheme, I need to load some CL
>       ;; compatibility library.
>         (set! state (+ 1 state))
>         state
>       ))
>    (set! dec
>       (lambda ()
>       ;; Ooops: there is no DECF in Scheme, I need to load some CL
>       ;; compatibility library.
>         (set! state (- state 1))
>         state
>       ))
>    (set! reset
>       (lambda ()
>         (set! state 0))))
> 
> That pretty much sums it up, doesn't it? :)

It does. You join a growing number of posters who created non-portable
code through depending upon set! having a defined return value :-)
Methinks there is an opportunity to fix this in R6RS.

Have fun,
Adam
From: =?UTF-8?B?SmVucyBBeGVsIFPDuGdhYXJk?=
Subject: Re: Scheme closures
Date: 
Message-ID: <4081b72d$0$222$edfadb0f@dread11.news.tele.dk>
Adam Warner wrote:
>>I'll give it a shot.
>>      (lambda ()
>>        (set! state (+ 1 state))
>>        state
>>      )

> You join a growing number of posters who created non-portable
> code through depending upon set! having a defined return value :-)

That's why he returns STATE in the end. The code is portable.

-- 
Jens Axel Søgaard
From: Adam Warner
Subject: Re: Scheme closures
Date: 
Message-ID: <pan.2004.04.17.23.10.41.656001@consulting.net.nz>
Hi Jens Axel Søgaard,

> Adam Warner wrote:
>>>I'll give it a shot.
>>>      (lambda ()
>>>        (set! state (+ 1 state))
>>>        state
>>>      )
> 
>> You join a growing number of posters who created non-portable
>> code through depending upon set! having a defined return value :-)
> 
> That's why he returns STATE in the end. The code is portable.

Care to reevaluate your position? Here's a hint:

>    (set! reset
>       (lambda ()
>         (set! state 0))))

Regards,
Adam
From: =?UTF-8?B?SmVucyBBeGVsIFPDuGdhYXJk?=
Subject: Re: Scheme closures
Date: 
Message-ID: <40824f84$0$218$edfadb0f@dread11.news.tele.dk>
Adam Warner wrote:
 > Jens Axek Søgaard wrote:
 >> Adam Warner wrote:

>>>You join a growing number of posters who created non-portable
>>>code through depending upon set! having a defined return value :-)
>>
>>That's why he returns STATE in the end. The code is portable.

> Care to reevaluate your position? Here's a hint:

>>   (set! reset
>>      (lambda ()
>>        (set! state 0))))

Ah. I think I'll call it a bug in stead of non-portable code ;-)

-- 
Jens Axel Søgaard
From: Boris Schaefer
Subject: Re: Scheme closures
Date: 
Message-ID: <87d665k357.fsf@qiwi.uncommon-sense.net>
* Adam Warner <······@consulting.net.nz> wrote:
| 
| >> You join a growing number of posters who created non-portable
| >> code through depending upon set! having a defined return value
| >> :-)

* The Code
| 
| >    (set! reset
| >       (lambda ()
| >         (set! state 0))))


How is this non-portable?  It sets RESET to the lambda.  This, of
course, is portable, as is the lambda expression.  It sets STATE to 0.

Calling RESET and depending on the value it returns is non-portable.
Also, depending on the value of the enclosing let expression would be
non-portable, because its value is that of the above (set! reset ...)
expression and thus unspecified.

However, nothing of the above sort is done in the above code.

Regards,
Boris

-- 
·····@uncommon-sense.net - <http://www.uncommon-sense.net/>

Chism's Law of Completion:
	The amount of time required to complete a government project is
	precisely equal to the length of time already spent on it.
From: Rahul Jain
Subject: Re: Scheme closures
Date: 
Message-ID: <87pta5wu1h.fsf@nyct.net>
Boris Schaefer <·····@uncommon-sense.net> writes:

> Calling RESET and depending on the value it returns is non-portable.
> Also, depending on the value of the enclosing let expression would be
> non-portable, because its value is that of the above (set! reset ...)
> expression and thus unspecified.
>
> However, nothing of the above sort is done in the above code.

Which is exactly why the code is not a proper translation of the
original code.

-- 
Rahul Jain
·····@nyct.net
Professional Software Developer, Amateur Quantum Mechanicist
From: Marco Antoniotti
Subject: Re: Scheme closures
Date: 
Message-ID: <%jRgc.58$a5.11387@typhoon.nyu.edu>
Rahul Jain wrote:

> Boris Schaefer <·····@uncommon-sense.net> writes:
> 
> 
>>Calling RESET and depending on the value it returns is non-portable.
>>Also, depending on the value of the enclosing let expression would be
>>non-portable, because its value is that of the above (set! reset ...)
>>expression and thus unspecified.
>>
>>However, nothing of the above sort is done in the above code.
> 
> 
> Which is exactly why the code is not a proper translation of the
> original code.
> 
Ok.

... (set! reset (lambda () (begin (set! state 0) state)))  ...

Gimme a break.

Cheers
--
marco
From: Marco Antoniotti
Subject: Re: Scheme closures
Date: 
Message-ID: <AgRgc.57$a5.11387@typhoon.nyu.edu>
Adam Warner wrote:

> Hi Marco Antoniotti,
> 
> 
>>I'll give it a shot.
>>
>>(define inc (lambda () ()))  ; Not strictly necessary.
>>(define dec (lambda () ()))
>>(define reset (lambda () ()))
>>
>>(let ((state 0))
>>   (set! inc
>>      (lambda ()
>>      ;; Ooops: there is no INCF in Scheme, I need to load some CL
>>      ;; compatibility library.
>>        (set! state (+ 1 state))
>>        state
>>      ))
>>   (set! dec
>>      (lambda ()
>>      ;; Ooops: there is no DECF in Scheme, I need to load some CL
>>      ;; compatibility library.
>>        (set! state (- state 1))
>>        state
>>      ))
>>   (set! reset
>>      (lambda ()
>>        (set! state 0))))
>>
>>That pretty much sums it up, doesn't it? :)
> 
> 
> It does. You join a growing number of posters who created non-portable
> code through depending upon set! having a defined return value :-)
> Methinks there is an opportunity to fix this in R6RS.
> 
> Have fun,
> Adam

Sorry.  But I do not feel all that bad, given that most interesting 
things done in Scheme are not portable anyway. (Cfr. `define-values') :)

Apart from that I cite:

===============
R^5RS

4.1.6. Assignments

(set! variable expression) syntax

Expression is evaluated, and the resulting value is stored
in the location to which variable is bound. Variable must be bound 
either in some region enclosing the set!
expression or at top level. The result of the set! expression
is unspecifed.

(define x 2)
(+ x 1) => 3
(set! x 4) => unspecifed
(+ x 1) => 5


===============

My interpretation is that maybe you can do without the top level 
DEFINEs,  but I do not see how this in unportable.  Unless you really 
really want to surprise the programmer by stating that Scheme has some 
weird Python 1.x binding rules. :)

Cheers
--
Marco
From: Kalle Olavi Niemitalo
Subject: Re: Scheme closures
Date: 
Message-ID: <87brlqoi7a.fsf@Astalo.kon.iki.fi>
Adam Warner <······@consulting.net.nz> writes:

> Please try your best to translate this Common Lisp code to Scheme:
>
> (let ((state 0))
>   (defun inc ()
>     (incf state))
>   (defun dec ()
>     (decf state))
>   (defun reset ()
>     (setf state 0)))

(define inc #f)
(define dec #f)
(define reset #f)
(let ((state 0))
  (set! inc (lambda () (set! state (+ state 1)) state))
  (set! dec (lambda () (set! state (- state 1)) state))
  (set! reset (lambda () (set! state 0) state)))

> `state' is only accessible through the (inc), (dec) and (reset) API. A
> Scheme solution must provide no other access to the `state' variable.

Fulfilled.

> I believe a Scheme translation could demonstrate the costs of no specially
> defined compilation semantics, but I'll reserve judgement until I can see
> how a Scheme expert would translate the above code.

I'm not a Scheme expert.

> Of course in Common Lisp all the above function definitions are
> still treated as top-level forms even though they are wrapped
> in a `let'.

Not in the sense of CLHS section 3.2.3.1.
From: Adam Warner
Subject: Re: Scheme closures
Date: 
Message-ID: <pan.2004.04.17.14.21.08.813049@consulting.net.nz>
Hi Kalle Olavi Niemitalo,

To summarise. ANSI Common Lisp:

(let ((state 0))
  (defun inc () (incf state))
  (defun dec () (decf state))
  (defun reset () (setf state 0)))

R5RS:

(define inc #f)
(define dec #f)
(define reset #f)
(let ((state 0))
  (set! inc (lambda () (set! state (+ state 1)) state))
  (set! dec (lambda () (set! state (- state 1)) state))
  (set! reset (lambda () (set! state 0) state)))

Along with Christophe thanks for posting an example that can be evaluated
in plain R5RS implementations. I was surprised to discover the other
examples employed an extension, define-values (it's not indexed in R5RS).

The Scheme version suffers from duplication of variable names and
assignments and the inability to rely upon a defined return value from
set! assignments. But overall it's not too bad even though I can see why
the translation wasn't immediately obvious.

Regards,
Adam
From: Bradd W. Szonye
Subject: Re: Scheme closures
Date: 
Message-ID: <slrnc82ke2.7ph.bradd+news@szonye.com>
Adam Warner <······@consulting.net.nz> wrote:
> To summarise. ANSI Common Lisp:
> 
> (let ((state 0))
>   (defun inc () (incf state))
>   (defun dec () (decf state))
>   (defun reset () (setf state 0)))
> 
> R5RS:
> 
> (define inc #f)
> (define dec #f)
> (define reset #f)
> (let ((state 0))
>   (set! inc (lambda () (set! state (+ state 1)) state))
>   (set! dec (lambda () (set! state (- state 1)) state))
>   (set! reset (lambda () (set! state 0) state)))

Yes, that's one way to do it, probably the simplest way. You could also
box the lambdas in a list or vector, return that, and unbox it to define
the top-level functions.

> Along with Christophe thanks for posting an example that can be
> evaluated in plain R5RS implementations. I was surprised to discover
> the other examples employed an extension, define-values (it's not
> indexed in R5RS).

As others have noted, define-values is a common extension implemented as
a macro. I'm surprised that it hasn't been standardized in a SRFI.

> The Scheme version suffers from duplication of variable names and
> assignments and the inability to rely upon a defined return value from
> set! assignments.

On the other hand, it does not break the scope of the LET to define the
function names at top level. I personally prefer the Scheme approach.

> But overall it's not too bad even though I can see why the translation
> wasn't immediately obvious.

FWIW, it was immediately obvious to me, but I can see why it might not
be obvious to everyone.
-- 
Bradd W. Szonye
http://www.szonye.com/bradd
From: Rahul Jain
Subject: Re: Scheme closures
Date: 
Message-ID: <87y8ouyp80.fsf@nyct.net>
"Bradd W. Szonye" <··········@szonye.com> writes:

> On the other hand, it does not break the scope of the LET to define the
> function names at top level. I personally prefer the Scheme approach.

FWIW, the concept of having a function name defined at top-level is
rather irrelevant to breaking scope. The issue is that CL has multiple
scoping mechanisms. DEFUN is defined to set the global function
definition. FLET establishes a definitions with lexical scope. Pascal
Costanza has developed a library (ok, a page of code) to establish
function definitions with dynamic scope.

-- 
Rahul Jain
·····@nyct.net
Professional Software Developer, Amateur Quantum Mechanicist
From: Bradd W. Szonye
Subject: Re: Scheme closures
Date: 
Message-ID: <slrnc8564m.7ph.bradd+news@szonye.com>
> "Bradd W. Szonye" <··········@szonye.com> writes:
>> On the other hand, it does not break the scope of the LET to define the
>> function names at top level. I personally prefer the Scheme approach.

Rahul Jain <·····@nyct.net> wrote:
> FWIW, the concept of having a function name defined at top-level is
> rather irrelevant to breaking scope. The issue is that CL has multiple
> scoping mechanisms. DEFUN is defined to set the global function
> definition. FLET establishes a definitions with lexical scope ....

Right, I understand that. I personally find it much easier to deal with
a single kind of scoping. On the one hand, DEFUN does not "break" the
scope of LET, because according to the language it's not subject to
LET's scope in the first place. On the other hand, that kind of
overlapping scope sets up a situation where scope is seemingly "broken"
all over the place.

I currently prefer languages where all lexical scoping strictly nests. I
don't mind multiple namespaces, but I'd rather have them all obey the
same scoping rules.
-- 
Bradd W. Szonye
http://www.szonye.com/bradd
From: Grzegorz =?UTF-8?B?Q2hydXBhxYJh?=
Subject: Re: Scheme closures
Date: 
Message-ID: <c5rf3n$jo6$1@news.ya.com>
Adam Warner wrote:

> Along with Christophe thanks for posting an example that can be evaluated
> in plain R5RS implementations. I was surprised to discover the other
> examples employed an extension, define-values (it's not indexed in R5RS).

For the record: this common extension can be easily written as a
syntax-rules macro.
Cheers,
-- 
Grzegorz Chrupała | http://pithekos.net | ·········@jabber.org
[My] rule of perl was (until i stopped using it): if it involves
arrays of arrays, use something better ;)
                           -- forcer on IRC
From: =?UTF-8?B?SmVucyBBeGVsIFPDuGdhYXJk?=
Subject: Re: Scheme closures
Date: 
Message-ID: <40814434$0$222$edfadb0f@dread11.news.tele.dk>
Grzegorz Chrupała wrote:

> For the record: this common extension can be easily written as a
> syntax-rules macro.

This is the definition used in Gauche.

; Copyright (c) 2000-2003 Shiro Kawai

(define-syntax define-values
   (syntax-rules ()
     ((_ (var  ...) expr)
      (define-values-sub () (var ...) (var ...) expr))
     ((_ . else)
      (syntax-error "malformed define-values" (define-values . else)))
     ))

(define-syntax define-values-sub
   (syntax-rules ()
     ((_ (tmp ...) () (var ...) expr)
      (begin (define var (undefined)) ...
             (receive (tmp ...) expr
               (set! var tmp) ...
               (undefined))))
     ((_ (tmp ...) (v v2 ...) (var ...) expr)
      (define-values-sub (tmp ... tmp1) (v2 ...) (var ...) expr))
     ))

-- 
Jens Axel Søgaard
From: =?UTF-8?B?SmVucyBBeGVsIFPDuGdhYXJk?=
Subject: Re: Scheme closures
Date: 
Message-ID: <40814635$0$222$edfadb0f@dread11.news.tele.dk>
Jens Axel Søgaard wrote:

> This is the definition used in Gauche.


And here is one by Dybvig:
     <http://zurich.csail.mit.edu/pipermail/rrrs-authors/1994-February/001696.html>

(define-syntax DEFINE-VALUES
  (syntax-rules ()
   ((define-values (<name> ...) <body> ...)
    ; =>
    (define-values helper (<name> ...) () (<name> ...) <body> ...)
   )
   ((define-values helper () (<temp> ...) (<name> ...) <body> ...)
    ; =>
    (begin
      (define <name> #f) ...
      (call-with-values
         (lambda () <body> ...)
         (lambda (<temp> ...)
           (set! <name> <temp>) ...
      )  )
   ))
   ((define-values helper (<var1> <var2> ...) <temp>s
                          (<name> ...) <body> ...)
    ; =>
    (define-values helper (<var2> ...) (<temp> . <temp>s)
                          (<name> ...) <body> ...)
   )
))


-- 
Jens Axel Søgaard
From: =?UTF-8?B?SmVucyBBeGVsIFPDuGdhYXJk?=
Subject: Re: Scheme closures
Date: 
Message-ID: <40814ce5$0$286$edfadb0f@dread11.news.tele.dk>
Jens Axel Søgaard wrote:

> And here is one by Dybvig:

Oops. It was the other Ken, namely Ken Dickey.

-- 
Jens Axel Søgaard
From: Jeff Dalton
Subject: Re: Scheme closures
Date: 
Message-ID: <fx4y8on3lhf.fsf@todday.inf.ed.ac.uk>
Jens Axel Søgaard <······@soegaard.net> writes:

> Grzegorz Chrupała wrote:
> 
> > For the record: this common extension can be easily written as a
> > syntax-rules macro.
> 
> This is the definition used in Gauche.
> 
> ; Copyright (c) 2000-2003 Shiro Kawai
> 
> (define-syntax define-values
>    (syntax-rules ()
>      ((_ (var  ...) expr)
>       (define-values-sub () (var ...) (var ...) expr))
>      ((_ . else)
>       (syntax-error "malformed define-values" (define-values . else)))
>      ))
> 
> (define-syntax define-values-sub
>    (syntax-rules ()
>      ((_ (tmp ...) () (var ...) expr)
>       (begin (define var (undefined)) ...
>              (receive (tmp ...) expr
>                (set! var tmp) ...
>                (undefined))))
>      ((_ (tmp ...) (v v2 ...) (var ...) expr)
>       (define-values-sub (tmp ... tmp1) (v2 ...) (var ...) expr))
>      ))

Oh - my - god.

I take back what I said about the perceived complexity of
Scheme macros being mostly about the internals.  :(

I'm surprised that such a simple macro is so hard to read. :(

Part of the problem is that patterns are positional - no names
for the elements.  As opposed to procedures where you get
to see the argument names.  So, sure, there's "var ..."
and there's "tmp ...", but the middle parameter of
define-values-sub is just "()".  In the other clause,
it's "(v v2 ...)".  Not enlightening.

-- jd
From: Joe Marshall
Subject: Re: Scheme closures
Date: 
Message-ID: <brljltmu.fsf@ccs.neu.edu>
Jeff Dalton <····@todday.inf.ed.ac.uk> writes:

>> ; Copyright (c) 2000-2003 Shiro Kawai
>> 
>> (define-syntax define-values
>>    (syntax-rules ()
>>      ((_ (var  ...) expr)
>>       (define-values-sub () (var ...) (var ...) expr))
>>      ((_ . else)
>>       (syntax-error "malformed define-values" (define-values . else)))
>>      ))
>> 
>> (define-syntax define-values-sub
>>    (syntax-rules ()
>>      ((_ (tmp ...) () (var ...) expr)
>>       (begin (define var (undefined)) ...
>>              (receive (tmp ...) expr
>>                (set! var tmp) ...
>>                (undefined))))
>>      ((_ (tmp ...) (v v2 ...) (var ...) expr)
>>       (define-values-sub (tmp ... tmp1) (v2 ...) (var ...) expr))
>>      ))
>
> Oh - my - god.

For the simple things like this:

  (define-syntax multiple-value-bind
    (syntax-rules ()
      ((multiple-value-bind bindings values-producer body-form ...)
       (call-with-values
        (lambda () values-producer)
        (lambda bindings body-form ...)))))

  (define-syntax multiple-value-list
    (syntax-rules ()
      ((multiple-value-list values-producer)
       (call-with-values (lambda () values-producer) list))))

Scheme macros are pretty straightforward.

Unfortunately, for anything even *slightly* complicated they turn into
a mess real quick.  The definition of Oleg's assert macro demonstrates
this:

; assert the truth of an expression (or of a sequence of expressions)
;
; syntax: assert ?expr ?expr ... [report: ?r-exp ?r-exp ...]
;
; If (and ?expr ?expr ...) evaluates to anything but #f, the result
; is the value of that expression.
; If (and ?expr ?expr ...) evaluates to #f, an error is reported.
; The error message will show the failed expressions, as well
; as the values of selected variables (or expressions, in general).
; The user may explicitly specify the expressions whose
; values are to be printed upon assertion failure -- as ?r-exp that
; follow the identifier 'report:'
; Typically, ?r-exp is either a variable or a string constant.
; If the user specified no ?r-exp, the values of variables that are
; referenced in ?expr will be printed upon the assertion failure.


(define-syntax assert
  (syntax-rules ()
    ((assert _expr . _others)
     (letrec-syntax
       ((write-report
	  (syntax-rules ()
			; given the list of expressions or vars,
			; create a cerr form
	    ((_ exprs prologue)
	      (k!reverse () (cerr . prologue)
		(write-report* ! exprs #\newline)))))
	 (write-report*
	   (syntax-rules ()
	     ((_ rev-prologue () prefix)
	       (k!reverse () (nl . rev-prologue) (k!id !)))
	     ((_ rev-prologue (x . rest) prefix)
	       (symbol?? x
		 (write-report* (x ": " 'x #\newline . rev-prologue) 
		   rest #\newline)
		 (write-report* (x prefix . rev-prologue) rest "")))))
	  
			; return the list of all unique "interesting"
			; variables in the expr. Variables that are certain
			; to be bound to procedures are not interesting.
	 (vars-of 
	   (syntax-rules (!)
	     ((_ vars (op . args) (k-head ! . k-args))
	       (id-memv?? op 
		 (quote let let* letrec let*-values lambda cond quasiquote
		   case define do assert)
		 (k-head vars . k-args) ; won't go inside
				; ignore the head of the application
		 (vars-of* vars args (k-head ! . k-args))))
		  ; not an application -- ignore
	     ((_ vars non-app (k-head ! . k-args)) (k-head vars . k-args))
	     ))
	 (vars-of*
	   (syntax-rules (!)
	     ((_ vars () (k-head ! . k-args)) (k-head vars . k-args))
	     ((_ vars (x . rest) k)
	       (symbol?? x
		 (id-memv?? x vars
		   (vars-of* vars rest k)
		   (vars-of* (x . vars) rest k))
		 (vars-of vars x (vars-of* ! rest k))))))

	 (do-assert
	   (syntax-rules (report:)
	     ((_ () expr)			; the most common case
	       (do-assert-c expr))
	     ((_ () expr report: . others) ; another common case
	       (do-assert-c expr others))
	     ((_ () expr . others) (do-assert (expr and) . others))
	     ((_ exprs)
	       (k!reverse () exprs (do-assert-c !)))
	     ((_ exprs report: . others)
	       (k!reverse () exprs (do-assert-c ! others)))
	     ((_ exprs x . others) (do-assert (x . exprs) . others))))

	 (do-assert-c
	   (syntax-rules ()
	     ((_ exprs)
	       (or exprs
		 (begin (vars-of () exprs
			  (write-report ! 
			    ("failed assertion: " 'exprs nl "bindings")))
		   (error "assertion failure"))))
	     ((_ exprs others)
	       (or exprs
		 (begin (write-report others
			  ("failed assertion: " 'exprs))
		   (error "assertion failure"))))))
	 )
       (do-assert () _expr . _others)
       ))))
From: David Van Horn
Subject: Re: Scheme closures
Date: 
Message-ID: <c695n8$2qbrk$1@swen.emba.uvm.edu>
Jeff Dalton wrote:
> Oh - my - god.
> 
> I take back what I said about the perceived complexity of
> Scheme macros being mostly about the internals.  :(

There is a simpler way of writing define-values given in the Scheme FAQ:

    ;; http://schemers.org/Documents/FAQ/#multidefine

    (define-syntax define-values
       (syntax-rules ()
         ((define-values () exp)
          (call-with-values (lambda () exp) (lambda () 'unspecified)))
         ((define-values (var . vars) exp)
          (begin
            (define var (call-with-values (lambda () exp) list))
            (define-values vars (apply values (cdr var)))
            (define var (car var))))
         ((define-values var exp)
          (define var (call-with-values (lambda () exp) list)))))

David
From: Jeff Dalton
Subject: Re: Scheme closures
Date: 
Message-ID: <fx4y8om33up.fsf@todday.inf.ed.ac.uk>
David Van Horn <········@cs.uvm.edu> writes:

> Jeff Dalton wrote:

> > Oh - my - god.

> > I take back what I said about the perceived complexity of
> > Scheme macros being mostly about the internals.  :(

> There is a simpler way of writing define-values given in the Scheme FAQ:

>     ;; http://schemers.org/Documents/FAQ/#multidefine

>     (define-syntax define-values
>        (syntax-rules ()
>          ((define-values () exp)
>           (call-with-values (lambda () exp) (lambda () 'unspecified)))
>          ((define-values (var . vars) exp)
>           (begin
>             (define var (call-with-values (lambda () exp) list))
>             (define-values vars (apply values (cdr var)))
>             (define var (car var))))
>          ((define-values var exp)
>           (define var (call-with-values (lambda () exp) list)))))

That's better, but it's still pretty hard to follow.

"(define var (car var))", for instance.  What is that doing?

I'm sure programmers eventually become used to the way
recursion, for example, is used in rules.  They'll easily be
able to see that a list is being mapped to another list, and
so on.

But it's not written as a call to map, and the
pattern has to be recognized in all its variations.

The promise of the rule language, like the promise of
backquote and quasiquote, was that you'd see a nice
picture of the result in the macro definition, thus
making it easy to understand.

But when in rules it is broken down into a number of smaller
pictures, it can be hard to see what they all add up to.

So the promise is often broken.

Also, I don't understand why _this_ macro is so hard.

It had seemed like it ought to be one of the really
straightforward ones.

Elsewhere under this topic, Anton van Straaten posted some
quite readable macros in response to the original question,
which makes me wonder why define-values gets much trickier
definitions.

For example, here's one of Anton's:

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
To complement the other replies, if you're feeling homesick, you could
write
something like:

(top-let ((state 0))
  (defun inc () (inc! state))
  (defun dec () (dec! state))
  (defun reset () (set! state 0) 0))

...given the following macro:

(define-syntax top-let
  (syntax-rules (defun)
    ((_ ((var val) ...)
        (defun name (formal ...) fn-body ...)
        ...)
     (begin
       (define name #f)
       ...
       (let ((var val) ...)
         (set! name (lambda (formal ...) fn-body ...))
         ...)))))

...plus macros for inc! and dec!, which are common but not
standardized in R5RS, e.g.:

(define-syntax inc! (syntax-rules () ((_ x) (begin (set! x (+ x 1)) x))))
(define-syntax dec! (syntax-rules () ((_ x) (begin (set! x (- x 1)) x))))
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Despite the always confusing use of "_" (which breaks the picture
model), I find it easy to understand.

The other of his macros, make-state-wrapper, was also easy.

-- jd
From: William D Clinger
Subject: Re: Scheme closures
Date: 
Message-ID: <fb74251e.0404231935.68615dbf@posting.google.com>
Speaking of DEFINE-VALUES, Jeff Dalton <····@todday.inf.ed.ac.uk> wrote:
> Also, I don't understand why _this_ macro is so hard.

It's hard because R5RS Scheme doesn't allow a macro to expand
into a mixture of expressions and definitions.  For DEFINE-VALUES,
the expansion must contain definitions, so it must consist entirely
of definitions.

I don't believe there is any portable way to write a DEFINE-VALUES
macro that is guaranteed to work both at top level and in a context
that permits internal definitions.

This has to do with inconsistencies between the semantics of
top-level and internal definitions, not with inherent limits
of the macro system per se.

Will
From: Anton van Straaten
Subject: Re: Scheme closures
Date: 
Message-ID: <j6kic.8245$gH6.567@newsread3.news.atl.earthlink.net>
Jeff Dalton wrote:
> The promise of the rule language, like the promise of
> backquote and quasiquote, was that you'd see a nice
> picture of the result in the macro definition, thus
> making it easy to understand.

One of the promises, yes.  Another goal for syntax-rules in particular was
to deliberately restrict the sort of computation the compiler has to deal
with at compile time, and/or to limit the bad things the programmer could do
with it.  It's these latter considerations that really limit syntax-rules.
I demonstrate this below with a comparison to syntax-case.

> But when in rules it is broken down into a number of smaller
> pictures, it can be hard to see what they all add up to.

I think a lot can depend on how well they're written, how descriptive the
names are, whether they're written to be easy to understand or to meet some
other constraint, etc.

> Also, I don't understand why _this_ macro is so hard.
>
> It had seemed like it ought to be one of the really
> straightforward ones.
>
> Elsewhere under this topic, Anton van Straaten posted some
> quite readable macros in response to the original question,
> which makes me wonder why define-values gets much trickier
> definitions.

Probably the biggest limitation is the lack of a shortcut to define
temporary variables in syntax-rules.  For define-values, it would be nice to
be able to write something like this:

(define-syntax define-values
  (syntax-rules ()
    ((define-values (var ...) expr)
     (begin
       (define var (if #f #f)) ...
       (call-with-values
        (lambda () expr)
        (lambda (var ...) (set! var var) ...))))))

But in syntax-rules, there's no way to disambiguate the two uses of 'var' in
the last lambda, and no way - without using additional rules or macros - to
generate temporaries corresponding to the vars.  We can easily do this with
syntax-case, though:

(define-syntax (define-values stx)
  (syntax-case stx ()
    ((define-values (var ...) expr)
     (with-syntax (((tmp ...) (generate-temporaries (syntax (var ...)))))
       (syntax
        (begin
          (define var (if #f #f)) ...
          (call-with-values
           (lambda () expr)
           (lambda (tmp ...) (set! var tmp) ...))))))))

This does the trick.

> Despite the always confusing use of "_" (which breaks the picture
> model), I find it easy to understand.

You probably know that the "_" is an optional shorthand - you can use the
name of the macro if you like.  I think this is one of those shortcuts which
which may look confusing at first, but which experienced users tend to
quickly adopt, because its benefits soon become obvious.  The benefit is
that you're not repeating the name of the macro over and over in the
patterns.

Re an earlier point about positional arguments, where e.g. an unnamed () may
appear in a pattern argument list: I think that's pretty familiar to anyone
who uses argument pattern matching, not just in macros.  You also see it in
functional languages like ML & Haskell.  When you see something like that,
you know it's a base case, and you look to one of the other patterns for a
name for it.  It's not something I'm usually consciously aware of.

Anton
From: Jeff Dalton
Subject: Re: Scheme closures
Date: 
Message-ID: <fx465bp495p.fsf@todday.inf.ed.ac.uk>
"Anton van Straaten" <·····@appsolutions.com> writes:

> Jeff Dalton wrote:
> > The promise of the rule language, like the promise of
> > backquote and quasiquote, was that you'd see a nice
> > picture of the result in the macro definition, thus
> > making it easy to understand.
> 
> One of the promises, yes.  Another goal for syntax-rules in particular was
> to deliberately restrict the sort of computation the compiler has to deal
> with at compile time, and/or to limit the bad things the programmer could do
> with it.  It's these latter considerations that really limit syntax-rules.
> I demonstrate this below with a comparison to syntax-case.

Ok, but I wasn't trying to talk specifically about syntax-rules.

> > But when in rules it is broken down into a number of smaller
> > pictures, it can be hard to see what they all add up to.
> 
> I think a lot can depend on how well they're written, how descriptive the
> names are, whether they're written to be easy to understand or to meet some
> other constraint, etc.

Absolutely right.  However, none of the posted definitions
were easy to read, yet presumably their authors thought they
were writing the macro in a good way.  That suggests that
there is a problem with the language.

Later you wrote:

> Re an earlier point about positional arguments, where e.g. an unnamed () may
> appear in a pattern argument list: I think that's pretty familiar to anyone
> who uses argument pattern matching, not just in macros.  You also see it in
> functional languages like ML & Haskell.

I like the sort of pattern-matching used in functional languages
enough that I wrote macros to provide it in Lisp.  Nonetheless,
I think it has some serious problems.

For instance, you see code that presents a picture of a data structure
(a constructor call) in which what goes with what is determined only
by position.  In simple cases, it's nice.

But if you later change the data structure, such as by adding
a field, you have to go around and change all the patters.

There's the same problem in Prolog; and usually someone will
defend those languages by saying something about what good
code would do.  Nonetheless, one still sees lots of code full of
positional patterns, written by good programmers, published
in well-regarded books, and so on.

These days, "refactoring" tools may be available.  But people
wrote such code even when such tools did not exist.

(Perhaps someone will make a point about procedures having
positional parameters and so they can't really be so bad.
But the existence of a case that isn't too troublesome
does not show there's no problem in any case.  Pattern-
matching tends to be used for things that would otherwise
be non-positional, such as saying "obj.field".)

> When you see something like that,
> you know it's a base case, and you look to one of the other patterns
> for a name for it.  It's not something I'm usually consciously aware
> of.

Sure, and as I mentioned people can also get used to recognizing the
constructs that do the equivalent of calling map; but it's kind of
like saying map isn't a benefit, because programmers could develop
the ability to recognize the pattern.  They still have to at least
look at more text; and that's a cost.

> > Also, I don't understand why _this_ macro is so hard.
> >
> > It had seemed like it ought to be one of the really
> > straightforward ones.

> Probably the biggest limitation is the lack of a shortcut to define
> temporary variables in syntax-rules.  For define-values, it would be
> nice to be able to write something like this:
> 
> (define-syntax define-values
>   (syntax-rules ()
>     ((define-values (var ...) expr)
>      (begin
>        (define var (if #f #f)) ...
>        (call-with-values
>         (lambda () expr)
>         (lambda (var ...) (set! var var) ...))))))
> 
> But in syntax-rules, there's no way to disambiguate the two uses of 'var' in
> the last lambda, and no way - without using additional rules or macros - to
> generate temporaries corresponding to the vars.

Why do you have (define var (if #f #f)) instead of, say
(define var #f)?

> We can easily do this with syntax-case, though:
> 
> (define-syntax (define-values stx)
>   (syntax-case stx ()
>     ((define-values (var ...) expr)
>      (with-syntax (((tmp ...) (generate-temporaries (syntax (var ...)))))
>        (syntax
>         (begin
>           (define var (if #f #f)) ...
>           (call-with-values
>            (lambda () expr)
>            (lambda (tmp ...) (set! var tmp) ...))))))))
> 
> This does the trick.

That's much nicer, though I wonder about the "stx" and the
"(if #f #f)".

> > Despite the always confusing use of "_" (which breaks the picture
> > model), I find it easy to understand.
> 
> You probably know that the "_" is an optional shorthand - you can use the
> name of the macro if you like.

Yes.  

> I think this is one of those shortcuts which
> which may look confusing at first, but which experienced users tend to
> quickly adopt, because its benefits soon become obvious.  The benefit is
> that you're not repeating the name of the macro over and over in the
> patterns.

What happens in nested definitions?  Also, I'm more concerned
about reading.  That the name would be repeatedly typed doesn't
seem like much of a cost, especially since editors will
typically be able to complete it when only partially typed.

It might be a benefit when reading, but it's not clear.  In some
cases, it would be, because it would be easier to pick out the "_"s
than to pick out the instances of the macro name.

A similar abbreviation hasn't been defined for procedures,
though it might also be useful.  Though procedures are a
different case, it still suggests that the benefits are
not large.

-- jd
From: Jens Axel Søgaard
Subject: Re: Scheme closures
Date: 
Message-ID: <408a9e3c$0$302$edfadb0f@dread11.news.tele.dk>
Jeff Dalton wrote:

> "Anton van Straaten" <·····@appsolutions.com> writes:

>>I think a lot can depend on how well they're written, how descriptive the
>>names are, whether they're written to be easy to understand or to meet some
>>other constraint, etc.

> Absolutely right.  However, none of the posted definitions
> were easy to read, yet presumably their authors thought they
> were writing the macro in a good way.  That suggests that
> there is a problem with the language.

*Other* constraint than readability. Since DEFINE-VALUES often
are defined by the compiler writer as part of the system as a whole,
it is quite possible that non-obvious way of writing it is chosen,
because he knows that the expansion has better chances of getting
optimizes.

-- 
Jens Axel S�gaard
From: Jeff Dalton
Subject: Re: Scheme closures
Date: 
Message-ID: <fx4y8okc6t2.fsf@todday.inf.ed.ac.uk>
Jens Axel S�gaard <······@soegaard.net> writes:

> Jeff Dalton wrote:
> 
> > "Anton van Straaten" <·····@appsolutions.com> writes:
> 
> >>I think a lot can depend on how well they're written, how descriptive the
> >>names are, whether they're written to be easy to understand or to meet some
> >>other constraint, etc.
> 
> > Absolutely right.  However, none of the posted definitions
> > were easy to read, yet presumably their authors thought they
> > were writing the macro in a good way.  That suggests that
> > there is a problem with the language.
> 
> *Other* constraint than readability. Since DEFINE-VALUES often
> are defined by the compiler writer as part of the system as a whole,
> it is quite possible that non-obvious way of writing it is chosen,
> because he knows that the expansion has better chances of getting
> optimizes.

System code should still be readable, and if something non-obvious
is needed for efficiency, it should be explained in comments.

Besides, one of the definitions was from an FAQ list, where it
should be clear that readability is important.

-- jd
From: Anton van Straaten
Subject: Re: Scheme closures
Date: 
Message-ID: <FQTic.10873$gH6.9855@newsread3.news.atl.earthlink.net>
Jeff Dalton wrote:
> "Anton van Straaten" <·····@appsolutions.com> writes:
...
> > I think a lot can depend on how well they're written, how descriptive
the
> > names are, whether they're written to be easy to understand or to meet
> > some other constraint, etc.
>
> Absolutely right.  However, none of the posted definitions
> were easy to read, yet presumably their authors thought they
> were writing the macro in a good way.  That suggests that
> there is a problem with the language.

The syntax-rules constraints are definitely part of the issue here (note
that Will Clinger's point about R5RS doesn't apply to the specific examples
posted in this thread, since both examples expand to a combination of
definitions & expressions).

However, if you look at the example in my earlier message, you can see that
the change from using syntax-rules to syntax-case, to be able to use
generate-temporaries, is trivial.  It's analogous to starting out writing a
case expression and then realizing you need a more general cond, instead.
Of course, you can usually tell ahead of time which you're going to need,
anyway.

> I like the sort of pattern-matching used in functional languages
> enough that I wrote macros to provide it in Lisp.  Nonetheless,
> I think it has some serious problems.

It's useful to be able to choose between pattern matching or not.
Syntax-case supports that, which is why that "stx" is there (described
below).

> Why do you have (define var (if #f #f)) instead of, say
> (define var #f)?

(if #f #f) returns an implementation-dependent "unspecified" value.  R5RS
specifies that prior to initialization, variables have an unspecified value.
"Unspecified" means that an implementation can use any value it likes, but
for consistency with the host implementation, if you're writing code to
generate variable definitions, then (if #f #f) usually gives you access to
whatever value the implementation normally uses to represent an unspecified
value.  Most implementations have some kind of "void" value which is used
for this purpose.  Portable libraries can (define void (if #f #f)) and then
refer to the value by name; I just used the expression directly in my
examples.

> That's much nicer, though I wonder about the "stx" and the
> "(if #f #f)".

"Stx" is the syntax object representing the source syntax, which you can use
for other purposes than pattern matching with syntax-case.  You can write
procedural code to destructure it, if you like.  You can even convert it to
a list and use quasiquote to generate the syntax you need, then convert it
back to a syntax object - which is pretty much what syntax-case
implementations of defmacro do.

> > I think this is one of those shortcuts which
> > which may look confusing at first, but which experienced users tend to
> > quickly adopt, because its benefits soon become obvious.  The benefit is
> > that you're not repeating the name of the macro over and over in the
> > patterns.
>
> What happens in nested definitions?

In syntax-rules, the identifier in that position is ignored, and there's no
issue with nested definitions.  The patterns always apply to the closest
enclosing definition.  R5RS 4.3.2 says "The keyword at the beginning of the
pattern in a <syntax rule> is not involved in the matching and is not
considered a pattern variable or literal identifier".

In syntax-case, that identifier is similarly unimportant, although it can
sometimes be useful as a lexical token to specify the lexical level of
syntax being introduced by the macro.

> Also, I'm more concerned
> about reading.  That the name would be repeatedly typed doesn't
> seem like much of a cost, especially since editors will
> typically be able to complete it when only partially typed.

Reading is the reason to use the shortcut.  The repeated name really doesn't
buy you much.  You're inside a lexical block which is identified with the
name of the macro at the very beginning, so there's no ambiguity.

> It might be a benefit when reading, but it's not clear.  In some
> cases, it would be, because it would be easier to pick out the "_"s
> than to pick out the instances of the macro name.
>
> A similar abbreviation hasn't been defined for procedures,
> though it might also be useful.  Though procedures are a
> different case, it still suggests that the benefits are
> not large.

The equivalent situation with procedures in Scheme would be to use a
construct like case-lambda, in which the procedure name is omitted from the
cases.  Using "_" is just a way of "explicitly omitting" the name of the
macro.  With macros, there are cases where you want to use the name of the
macro, so you do need to be able to access it if necessary.  But if a
particular macro doesn't need it, then you have the choice of "omitting" it.

Any more tire-kicking you need to do?  ;o)

Anton
From: Rob Warnock
Subject: Re: Scheme closures
Date: 
Message-ID: <UYCdneZksNledRHdRVn-iQ@speakeasy.net>
Anton van Straaten <·····@appsolutions.com> wrote:
+---------------
| > Why do you have (define var (if #f #f)) instead of, say
| > (define var #f)?
| 
| (if #f #f) returns an implementation-dependent "unspecified" value.  R5RS
| specifies that prior to initialization, variables have an unspecified value.
| "Unspecified" means that an implementation can use any value it likes, but
| for consistency with the host implementation, if you're writing code to
| generate variable definitions, then (if #f #f) usually gives you access to
| whatever value the implementation normally uses to represent an unspecified
| value.
+---------------

CAREFUL! The "unspecified value" that uninitialized variables have is
in no way constrained to be the same as the "unspecified value" which
(if #f #f) returns!!  ...and in many implementations it's not! Nor is
the value of (if #f #f) required to be the same as other unspecified
values such as (set! foo 123) [though in many implementations it is].

+---------------
| Most implementations have some kind of "void" value which is used
| for this purpose.
+---------------

It is less common that "void" and (if #f #f) are different [for those
implementations which define a "void"], but I have seen a few. Or consider
MzScheme, where "void" is actually bound to a primitive procedure which
returns a "#<void>" object [which, though, is the same as both (if #f #f)
and (set! foo 123)].

[Also, in MzScheme both (void) and (values) suppress the printing of
any value when returning to the REPL.]


-Rob

-----
Rob Warnock			<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607
From: Karl A. Krueger
Subject: Re: Scheme closures
Date: 
Message-ID: <c6j2j1$o1c$1@baldur.whoi.edu>
In comp.lang.lisp Rob Warnock <····@rpw3.org> wrote:
> Anton van Straaten <·····@appsolutions.com> wrote:
> | > Why do you have (define var (if #f #f)) instead of, say
> | > (define var #f)?
> | 
> | (if #f #f) returns an implementation-dependent "unspecified" value.  R5RS
> | specifies that prior to initialization, variables have an unspecified value.
> | "Unspecified" means that an implementation can use any value it likes, but
> | for consistency with the host implementation, if you're writing code to
> | generate variable definitions, then (if #f #f) usually gives you access to
> | whatever value the implementation normally uses to represent an unspecified
> | value.
> 
> CAREFUL! The "unspecified value" that uninitialized variables have is
> in no way constrained to be the same as the "unspecified value" which
> (if #f #f) returns!!  ...and in many implementations it's not! Nor is
> the value of (if #f #f) required to be the same as other unspecified
> values such as (set! foo 123) [though in many implementations it is].

"An unspecified value" means any value without constraints -- not even
necessarily the same one every time.  "The unspecified value" implies
that there is some special value, which can be known by the name
"Unspecified", which is used to represent an undetermined value.  This
sounds like a great source of confusion -- just see what a mess some
database users get into with the NULL value in SQL.

The idea of there being a "value the implementation normally uses to
represent an unspecified value" is a confusion.  You cannot point at a
-value- and say, "This value is unspecified," since if there is some
particular value there it isn't unspecified.  You can only point at a
-form- and say "This returns some value, but what value it is, is not
specified."  If a return value is really -unspecified- then the
implementation can hand you 42 every third time and (BAGGY PANTS) the
others, and be within specification.  Or it can channel C and return
whatever happened to be lying around in memory.

Nasal demons are always a distinct possibility.  I recall one Scheme
implementation which went out of its way to evaluate function parameters
in random order -- to club students over the head with the idea that the
order of evaluation was unspecified.

-- 
Karl A. Krueger <········@example.edu>
Woods Hole Oceanographic Institution
Email address is spamtrapped.  s/example/whoi/
"Outlook not so good." -- Magic 8-Ball Software Reviews
From: Anton van Straaten
Subject: Re: Scheme closures
Date: 
Message-ID: <eidjc.11890$gH6.6789@newsread3.news.atl.earthlink.net>
Rob Warnock wrote:

> Anton van Straaten <·····@appsolutions.com> wrote:
> +---------------
> | > Why do you have (define var (if #f #f)) instead of, say
> | > (define var #f)?
> |
> | (if #f #f) returns an implementation-dependent "unspecified" value.
R5RS
> | specifies that prior to initialization, variables have an unspecified
value.
> | "Unspecified" means that an implementation can use any value it likes,
but
> | for consistency with the host implementation, if you're writing code to
> | generate variable definitions, then (if #f #f) usually gives you access
to
> | whatever value the implementation normally uses to represent an
unspecified
> | value.
> +---------------
>
> CAREFUL! The "unspecified value" that uninitialized variables have is
> in no way constrained to be the same as the "unspecified value" which
> (if #f #f) returns!!  ...and in many implementations it's not! Nor is
> the value of (if #f #f) required to be the same as other unspecified
> values such as (set! foo 123) [though in many implementations it is].

That's why I wrote "Unspecified means that an implementation can use any
value it likes", and "(if #f #f) __usually__ gives you access to whatever
value the implementation normally uses to represent an unspecified value".
In my experience, "usually" is true for the major implementations.

R5RS uses (if #f #f) to obtain an unspecified value in its derived
expression macros, so this idiom is enshrined in the standard.  You can't
actually go wrong doing this: the result of (if #f #f) is a value, which is
unspecified, and so it's valid to use it in places where an unspecified
value is wanted.  Actually, of course, it's valid to use any value, but you
may want to avoid using otherwise meaningful values.  If your host
implementation returns an ordinary value from (if #f #f), you may have other
problems anyway.

Finally, programs shouldn't rely on an unspecified value to be equal to
anything - that would be totally against the meaning of "unspecified".  Of
course, if the implementation specifies a value, and you want to write
implementation-dependent code, then you're free to do that, but at that
point, R5RS's semantics for "unspecified" are no longer a consideration.

Anton
From: Ray Dillinger
Subject: Re: Scheme closures
Date: 
Message-ID: <Aqhjc.8273$Fo4.106005@typhoon.sonic.net>
Anton van Straaten wrote:
> Rob Warnock wrote:
> 

> R5RS uses (if #f #f) to obtain an unspecified value in its derived
> expression macros, so this idiom is enshrined in the standard.  You can't
> actually go wrong doing this: the result of (if #f #f) is a value, which is
> unspecified, and so it's valid to use it in places where an unspecified
> value is wanted.  Actually, of course, it's valid to use any value, but you
> may want to avoid using otherwise meaningful values.  

The problem here is that there is no guarantee that the
value returned from (if #f #f) is not otherwise meaningful.
A compliant scheme may return #f, the empty list, the
string "tuesday," or any other value it likes. It may even
return a count of the number of times an expression that
gives an unspecified value has been evaluated.


> If your host
> implementation returns an ordinary value from (if #f #f), you may have other
> problems anyway.

You may think so, but the value returned from that
expression is not constrained in any way to be other
than "ordinary."

			Bear
From: Anton van Straaten
Subject: Re: Scheme closures
Date: 
Message-ID: <7jijc.12264$gH6.11659@newsread3.news.atl.earthlink.net>
Ray Dillinger wrote:
> Anton van Straaten wrote:
> > Rob Warnock wrote:
> >
>
> > R5RS uses (if #f #f) to obtain an unspecified value in its derived
> > expression macros, so this idiom is enshrined in the standard.  You
can't
> > actually go wrong doing this: the result of (if #f #f) is a value, which
is
> > unspecified, and so it's valid to use it in places where an unspecified
> > value is wanted.  Actually, of course, it's valid to use any value, but
you
> > may want to avoid using otherwise meaningful values.
>
> The problem here is that there is no guarantee that the
> value returned from (if #f #f) is not otherwise meaningful.
> A compliant scheme may return #f, the empty list, the
> string "tuesday," or any other value it likes. It may even
> return a count of the number of times an expression that
> gives an unspecified value has been evaluated.

That's all true, as a consequence of the word "unspecified", which implies
no guarantee of anything.  But what I'm saying is that if you're writing
code in which you want an unspecified value of a similar sort to that used
by the implementation, one way to get such a value is via (if #f #f).  At
the very least, you'll get a value which the implementation uses as an
unspecified value in this case.  That still doesn't guarantee anything, but
in practice, in quite a few implementations, it does indeed give you what
you would expect.

For the most part, it shouldn't actually matter much what value is used in
these situations - the whole point is that these are values that are used
before a variable is initialized, or when the result of an operation is not
intended to be meaningful.  The reason that implementations might choose to
avoid using meaningful values are for things like debugging, or to reduce
the chances that an attempt to use the value of an uninitialized variable
doesn't succeed by accident, when it shouldn't.

> > If your host implementation returns an ordinary value
> > from (if #f #f), you may have other problems anyway.
>
> You may think so, but the value returned from that
> expression is not constrained in any way to be other
> than "ordinary."

It's a quality of implementation issue, which is constrained by intelligent
behavior.  Not everything that a specification permits is necessarily a good
idea.

To make this more concrete, here are the results of evaluating (list (if #f
#f)) under several implementations (some of these may be old versions since
I don't keep all of them up to date):

Chicken: (#<unspecified>)
Gambit: (#<void>)
Guile: (#<unspecified>)
Kawa: (#!void)
Larceny: unspecified (not sure how it prints, don't have a working
implementation)
MIT: (#[unspecified-return-value])
Petite Chez: (#<void>)
PLT: (#<void>)
Scheme48: '(#{Unspecific})
SCM: (#<unspecified>)
SISC: (#<void>)
STk: (#[undefined])

I found a few implementations that returned other kinds of values:

JScheme: (#f)
LispMe (Palm Pilot): (#f)
TinyScheme: (())

That would have consequences if you were writing code like (if (if #f #f) #t
#f); all implementations would return #t, except JScheme & LispMe which
would return #f.  But then, you shouldn't be writing code which depends on
whether an unspecified value is considered true or false.

Anton
From: Taylor Campbell
Subject: Re: Scheme closures
Date: 
Message-ID: <5d744894.0404271216.57dbd825@posting.google.com>
"Anton van Straaten" <·····@appsolutions.com> wrote in message news:<·····················@newsread3.news.atl.earthlink.net>...
> Larceny: unspecified (not sure how it prints, don't have a working
> implementation)

Hey, don't you remember that it's 17 now?
From: Joe Marshall
Subject: Re: Scheme closures
Date: 
Message-ID: <ekq9j8yu.fsf@comcast.net>
"Anton van Straaten" <·····@appsolutions.com> writes:

> Finally, programs shouldn't rely on an unspecified value to be equal to
> anything - that would be totally against the meaning of "unspecified".  

Except exactly itself.  I hope that

  (let ((x (if #f #f)))
    (eq? x x))

returns #t.

-- 
~jrm
From: Anton van Straaten
Subject: Re: Scheme closures
Date: 
Message-ID: <OoCjc.13042$gH6.3923@newsread3.news.atl.earthlink.net>
Joe Marshall wrote:

> "Anton van Straaten" <·····@appsolutions.com> writes:
>
> > Finally, programs shouldn't rely on an unspecified value to be equal to
> > anything - that would be totally against the meaning of "unspecified".
>
> Except exactly itself.  I hope that
>
>   (let ((x (if #f #f)))
>     (eq? x x))
>
> returns #t.

Finally, something uncontroversial for R6RS!

That is, assuming this doesn't cause problems for FrTime or Quantum Scheme.

Anton
From: William D Clinger
Subject: Re: Scheme closures
Date: 
Message-ID: <fb74251e.0404280721.43ac3307@posting.google.com>
> > > Finally, programs shouldn't rely on an unspecified value to be equal to
> > > anything - that would be totally against the meaning of "unspecified".
> >
> > Except exactly itself.  I hope that
> >
> >   (let ((x (if #f #f)))
> >     (eq? x x))
> >
> > returns #t.
> 
> Finally, something uncontroversial for R6RS!
> 
> That is, assuming this doesn't cause problems for FrTime or Quantum Scheme.
> 
> Anton

It looks controversial to me.  (if #f #f) might return an inexact
approximation to pi.  I don't think there are too many people who
would argue that (EQ? (acos -1) (acos -1)) should be required to
return #t, because that would make EQ? much more complicated in
many implementations.

In the R5RS, EQ? is basically a broken version of EQV? that's in
the language because it's likely to be faster for the special
cases in which it is guaranteed to return the same answer as EQV?.

The R6RS cannot require (EQ? X X) to return true for all X without
doing one of the following:

    (1) Make the result of a procedure depend upon its argument
        expressions, not just the values of those expressions.
    (2) Make EQ? into a special form, not a procedure.
    (3) Add object identity to numbers, characters, and the other
        data types for which EQ? is not guaranteed to return the
        same value as EQV?
    (4) Something even worse than the above.

(1) is contrary to the essence of Scheme.  (2) is silly.
(3) would make numbers and characters slower, which is a silly
tradeoff because the sole reason for having EQ? in the language
is efficiency; it would be better to dump EQ? altogether than to
make numbers slower.  (4) would be even worse.

Will
From: Karl A. Krueger
Subject: Re: Scheme closures
Date: 
Message-ID: <c6okls$p7e$1@baldur.whoi.edu>
In comp.lang.lisp William D Clinger <··········@verizon.net> wrote:
> The R6RS cannot require (EQ? X X) to return true for all X without
> doing one of the following:
	[...]
>    (3) Add object identity to numbers, characters, and the other
>        data types for which EQ? is not guaranteed to return the
>        same value as EQV?

# [b] You can't do EQ on numbers and hope to win.  Recall also
#     the famous test in which NCOMPLR produced better numerical
#     code than the DEC FORTRAN compiler (Fateman 1973).
# 
# Quaxity quuxity,
# MacLISP and NCOMPLR
# Have a convention that
# Makes losers freak:
# Integers allocate
# Hyperefficiently,
# Bettering FORTRAN, but
# Screwing up EQ."

	-- The Great Quux, 1978
	   http://www.stinky.com/dactyl/steele.txt

-- 
Karl A. Krueger <········@example.edu>
Woods Hole Oceanographic Institution
Email address is spamtrapped.  s/example/whoi/
"Outlook not so good." -- Magic 8-Ball Software Reviews
From: Joe Marshall
Subject: Re: Scheme closures
Date: 
Message-ID: <wu40hxyd.fsf@comcast.net>
··········@verizon.net (William D Clinger) writes:

>> > > Finally, programs shouldn't rely on an unspecified value to be equal to
>> > > anything - that would be totally against the meaning of "unspecified".
>> >
>> > Except exactly itself.  I hope that
>> >
>> >   (let ((x (if #f #f)))
>> >     (eq? x x))
>> >
>> > returns #t.
>> 
>> Finally, something uncontroversial for R6RS!
>> 
>> That is, assuming this doesn't cause problems for FrTime or Quantum Scheme.
>> 
>> Anton
>
> It looks controversial to me.  (if #f #f) might return an inexact
> approximation to pi.  I don't think there are too many people who
> would argue that (EQ? (acos -1) (acos -1)) should be required to
> return #t, because that would make EQ? much more complicated in
> many implementations.

Yes, but I do think that you will find people to argue that

  (let ((x (acos -1)))
    (eq? x x))

really should be #t.


-- 
~jrm
From: Erann Gat
Subject: Re: Scheme closures
Date: 
Message-ID: <gNOSPAMat-C99F9C.10474928042004@nntp1.jpl.nasa.gov>
In article <············@comcast.net>,
 Joe Marshall <·············@comcast.net> wrote:

> ··········@verizon.net (William D Clinger) writes:
> 
> >> > > Finally, programs shouldn't rely on an unspecified value to be equal to
> >> > > anything - that would be totally against the meaning of "unspecified".
> >> >
> >> > Except exactly itself.  I hope that
> >> >
> >> >   (let ((x (if #f #f)))
> >> >     (eq? x x))
> >> >
> >> > returns #t.
> >> 
> >> Finally, something uncontroversial for R6RS!
> >> 
> >> That is, assuming this doesn't cause problems for FrTime or Quantum Scheme.
> >> 
> >> Anton
> >
> > It looks controversial to me.  (if #f #f) might return an inexact
> > approximation to pi.  I don't think there are too many people who
> > would argue that (EQ? (acos -1) (acos -1)) should be required to
> > return #t, because that would make EQ? much more complicated in
> > many implementations.
> 
> Yes, but I do think that you will find people to argue that
> 
>   (let ((x (acos -1)))
>     (eq? x x))
> 
> really should be #t.

R5RS explicitly disclaims this:

3.4 Storage model

...

An object fetched from a location, by a variable reference or by a 
procedure such as `car' ,`vector-ref' , or `string-ref' , is equivalent 
in the sense of eqv? (section see section 6.1 Equivalence predicates )to 
^^^^^^^^^^^^^^^^^^^^
the object last stored in the location before the fetch.

E.
From: Joe Marshall
Subject: Re: Scheme closures
Date: 
Message-ID: <k700hr9y.fsf@comcast.net>
Erann Gat <·········@flownet.com> writes:

> In article <············@comcast.net>,
>  Joe Marshall <·············@comcast.net> wrote:
>> 
>> Yes, but I do think that you will find people to argue that
>> 
>>   (let ((x (acos -1)))
>>     (eq? x x))
>> 
>> really should be #t.
>
> R5RS explicitly disclaims this:

It says that I do not think that?  Or that there aren't people who
would argue that? Or that

   (let ((x (acos -1)))
     (eq? x x))
 
 really should be #f?

> 3.4 Storage model
>
> ...
>
> An object fetched from a location, by a variable reference or by a 
> procedure such as `car' ,`vector-ref' , or `string-ref' , is equivalent 
> in the sense of eqv? (section see section 6.1 Equivalence predicates )to 
> ^^^^^^^^^^^^^^^^^^^^
> the object last stored in the location before the fetch.

   (let ((x (acos -1)))
     (eqv? x x))
 
 really should be #t.

-- 
~jrm
From: William D Clinger
Subject: Re: Scheme closures
Date: 
Message-ID: <fb74251e.0404281631.3c84e4d7@posting.google.com>
Joe Marshall <·············@comcast.net> wrote:
>    (let ((x (acos -1)))
>      (eqv? x x))
>  
>  really should be #t.

That is true in all R5RS-conforming implementations of Scheme,
and all conforming implementations of Common Lisp have the
analogous property (substituting EQL for EQ?).

Will
From: Joe Marshall
Subject: Re: Scheme closures
Date: 
Message-ID: <k6zzo7i3.fsf@comcast.net>
··········@verizon.net (William D Clinger) writes:

> Joe Marshall <·············@comcast.net> wrote:
>>    (let ((x (acos -1)))
>>      (eqv? x x))
>>  
>>  really should be #t.
>
> That is true in all R5RS-conforming implementations of Scheme,
> and all conforming implementations of Common Lisp have the
> analogous property (substituting EQL for EQ?).

Well now *that* is settled, should this be #t?

    (let ((x (if #f #f)))
      (eqv? x x))


-- 
~jrm
From: Jens Axel Søgaard
Subject: Re: Scheme closures
Date: 
Message-ID: <408fdd84$0$287$edfadb0f@dread11.news.tele.dk>
Joe Marshall wrote:

> ··········@verizon.net (William D Clinger) writes:

>>It looks controversial to me.  (if #f #f) might return an inexact
>>approximation to pi.  I don't think there are too many people who
>>would argue that (EQ? (acos -1) (acos -1)) should be required to
>>return #t, because that would make EQ? much more complicated in
>>many implementations.

> Yes, but I do think that you will find people to argue that
> 
>   (let ((x (acos -1)))
>     (eq? x x))
> 
> really should be #t.

So the unspecified value returned should have an implementation
independent specified behaviour?

Isn't that a bit silly?

-- 
Jens Axel S�gaard
From: Joe Marshall
Subject: Re: Scheme closures
Date: 
Message-ID: <smeohs07.fsf@comcast.net>
Jens Axel S�gaard <······@soegaard.net> writes:

> Joe Marshall wrote:
>
>> ··········@verizon.net (William D Clinger) writes:
>
>>>It looks controversial to me.  (if #f #f) might return an inexact
>>>approximation to pi.  I don't think there are too many people who
>>>would argue that (EQ? (acos -1) (acos -1)) should be required to
>>>return #t, because that would make EQ? much more complicated in
>>>many implementations.
>
>> Yes, but I do think that you will find people to argue that
>>   (let ((x (acos -1)))
>>     (eq? x x))
>> really should be #t.
>
> So the unspecified value returned should have an implementation
> independent specified behaviour?

Where the spec mandates it.  For instance the unspecified value should
also not satisfy more than one of the predicates boolean? symbol?
char? vector? procedure? pair? number? string? and port?

Furthermore, if the procedure pair? for the unspecified value returns
#t, I'd expect to take CAR and CDR of the unspecified value.


> Isn't that a bit silly?

Not at all.  If there is an unspecified value that is a first class
object, then I'd expect it to behave like all other first class
objects.  If it didn't, then you'd have to add exceptions to a huge
number of procedures.

Of course one could always specify that *no* value is returned.


-- 
~jrm
From: Mario S. Mommer
Subject: Re: Scheme closures
Date: 
Message-ID: <fzbrlcniet.fsf@germany.igpm.rwth-aachen.de>
Jens Axel S�gaard <······@soegaard.net> writes:
> Isn't that a bit silly?

Indeed.

And while it is also mildly entertaining, I wonder why you keep
crossposting this to c.l.l?
From: William D Clinger
Subject: Re: Scheme closures
Date: 
Message-ID: <fb74251e.0404281625.cc1b3dc@posting.google.com>
Pascal Costanza wrote:
> This seems to be about very low-level details of the Scheme spec. Why 
> are you cross-posting this to comp.lang.lisp?

And Mario S. Mommer <········@yahoo.com> wrote:
> > Isn't that a bit silly?
> 
> Indeed.
> 
> And while it is also mildly entertaining, I wonder why you keep
> crossposting this to c.l.l?

Because both Common Lisp and Scheme allow (LET ((X 5)) (EQ? X X))
to evaluate to a false value, so this issue is just as entertaining
for the Common Lispers as it is for the Schemers.

Those who do not understand Common Lisp's semantics should consult
http://www.lisp.org/HyperSpec/Body/fun_eq.html and pay special
attention not only to the example quoted above but also to this:

    An implementation is permitted to make "copies" of characters
    and numbers at any time.  The effect is that Common Lisp makes
    no guarantee that eq is true even when both its arguments are
    "the same thing" if that thing is a character or number.

Will
From: Pascal Costanza
Subject: Re: Scheme closures
Date: 
Message-ID: <c6pk4e$6u1$1@newsreader2.netcologne.de>
William D Clinger wrote:

> Because both Common Lisp and Scheme allow (LET ((X 5)) (EQ? X X))
> to evaluate to a false value, so this issue is just as entertaining
> for the Common Lispers as it is for the Schemers.

That's trivially true. However, a discussion about whether R6RS should 
include guarantees about unspecified values or not is far too specific 
for being cross-posted to c.l.l. Those who are interested in such issues 
will surely find a way to join such a discussion in c.l.s.


Pascal

-- 
1st European Lisp and Scheme Workshop
June 13 - Oslo, Norway - co-located with ECOOP 2004
http://www.cs.uni-bonn.de/~costanza/lisp-ecoop/
From: Anton van Straaten
Subject: Re: Scheme closures
Date: 
Message-ID: <B7Zjc.14377$gH6.3644@newsread3.news.atl.earthlink.net>
Pascal Costanza wrote:
>
> William D Clinger wrote:
>
> > Because both Common Lisp and Scheme allow (LET ((X 5)) (EQ? X X))
> > to evaluate to a false value, so this issue is just as entertaining
> > for the Common Lispers as it is for the Schemers.
>
> That's trivially true. However, a discussion about whether R6RS should
> include guarantees about unspecified values or not is far too specific
> for being cross-posted to c.l.l.

Sorry if it wasn't clear, but that original comment of mine about inclusion
in R6RS was a joke.  I could imagine that some CLers paying attention might
even have appreciated it: after all, there's one undeniable characteristic
which both CL and Scheme have in common, namely standards which are, shall
we say, particularly stable.

Anton
From: Arthur Lemmens
Subject: Re: Scheme closures
Date: 
Message-ID: <opr67j6mkuk6vmsw@news.xs4all.nl>
Anton van Straaten <·····@appsolutions.com> wrote:

> there's one undeniable characteristic which both CL and Scheme
> have in common, namely standards which are, shall we say,
> particularly stable.

You mean like the time when Scheme changed from #f and nil
being the same object to #f and nil being distinct objects?
(IIRC, this was a change from R3RS to R4RS.)

--
Arthur
From: Anton van Straaten
Subject: Re: Scheme closures
Date: 
Message-ID: <sY2kc.6987$g31.2929@newsread2.news.atl.earthlink.net>
Arthur Lemmens wrote:

> Anton van Straaten <·····@appsolutions.com> wrote:
>
> > there's one undeniable characteristic which both CL and Scheme
> > have in common, namely standards which are, shall we say,
> > particularly stable.
>
> You mean like the time when Scheme changed from #f and nil
> being the same object to #f and nil being distinct objects?
> (IIRC, this was a change from R3RS to R4RS.)

Ah yes, you mean back in the previous century?  It was a primitive time --
in those days, they had only just begun to comprehend these mysterious
things we now know as "disjoint types".

Anton
From: Pascal Costanza
Subject: Re: Scheme closures
Date: 
Message-ID: <c6qfh3$oo6$3@newsreader2.netcologne.de>
Anton van Straaten wrote:

> Arthur Lemmens wrote:
> 
>>You mean like the time when Scheme changed from #f and nil
>>being the same object to #f and nil being distinct objects?
>>(IIRC, this was a change from R3RS to R4RS.)
> 
> Ah yes, you mean back in the previous century?  It was a primitive time --
> in those days, they had only just begun to comprehend these mysterious
> things we now know as "disjoint types".

What problems does the disjointness of types solve?


Pascal

-- 
1st European Lisp and Scheme Workshop
June 13 - Oslo, Norway - co-located with ECOOP 2004
http://www.cs.uni-bonn.de/~costanza/lisp-ecoop/
From: Joe Marshall
Subject: Re: Scheme closures
Date: 
Message-ID: <fzannjft.fsf@comcast.net>
Pascal Costanza <········@web.de> writes:

> Anton van Straaten wrote:
>
>> Arthur Lemmens wrote:
>>
>>>You mean like the time when Scheme changed from #f and nil
>>>being the same object to #f and nil being distinct objects?
>>>(IIRC, this was a change from R3RS to R4RS.)
>> Ah yes, you mean back in the previous century?  It was a primitive
>> time --
>> in those days, they had only just begun to comprehend these mysterious
>> things we now know as "disjoint types".
>
> What problems does the disjointness of types solve?

It makes things easier to reason about.

-- 
~jrm
From: Pascal Costanza
Subject: Re: Scheme closures
Date: 
Message-ID: <c6rook$ehb$1@newsreader2.netcologne.de>
Joe Marshall wrote:

> Pascal Costanza <········@web.de> writes:
> 
>>Anton van Straaten wrote:
>>
>>>Arthur Lemmens wrote:
>>>
>>>>You mean like the time when Scheme changed from #f and nil
>>>>being the same object to #f and nil being distinct objects?
>>>>(IIRC, this was a change from R3RS to R4RS.)
>>>
>>>Ah yes, you mean back in the previous century?  It was a primitive
>>>time --
>>>in those days, they had only just begun to comprehend these mysterious
>>>things we now know as "disjoint types".
>>
>>What problems does the disjointness of types solve?
> 
> It makes things easier to reason about.

I would be interested in examples, especially those in which the 
distinction between #f and nil plays an important role. Is there any 
material available?


Pascal

-- 
1st European Lisp and Scheme Workshop
June 13 - Oslo, Norway - co-located with ECOOP 2004
http://www.cs.uni-bonn.de/~costanza/lisp-ecoop/
From: Anton van Straaten
Subject: Re: Scheme closures
Date: 
Message-ID: <XSfkc.7556$g31.4630@newsread2.news.atl.earthlink.net>
Pascal Costanza wrote:
>
> Joe Marshall wrote:
>
> > Pascal Costanza <········@web.de> writes:
> >
> >>Anton van Straaten wrote:
> >>
> >>>Arthur Lemmens wrote:
> >>>
> >>>>You mean like the time when Scheme changed from #f and nil
> >>>>being the same object to #f and nil being distinct objects?
> >>>>(IIRC, this was a change from R3RS to R4RS.)
> >>>
> >>>Ah yes, you mean back in the previous century?  It was a primitive
> >>>time --
> >>>in those days, they had only just begun to comprehend these mysterious
> >>>things we now know as "disjoint types".
> >>
> >>What problems does the disjointness of types solve?
> >
> > It makes things easier to reason about.
>
> I would be interested in examples, especially those in which the
> distinction between #f and nil plays an important role. Is there any
> material available?

Once again, I feel the need to mention that my original comment omitted an
intended annotation, namely:

    ;oP

Having now retracted my tongue, this issue could be discussed at length.
I'm happy to make some observations and state some opinions, but I don't
promise to respond beyond this:

* The benefits of disjoint types[*] are fairly well known, as recognized by
many languages, including CL for most of its types, such as numbers or
strings.

* The question of whether [some | all] conditional constructs should treat
certain values as being truth values is potentally a separate question from
whether the boolean type should be disjoint from other types.  This perhaps
has formal consequences for their disjointness, i.e. types could then be
disjoint in some contexts but not others, but there's no particular
difficulty with this, afaik.

* Achieving convenience by inseparably conflating types of values at a very
low level seems unfortunate to me.  I'd rather have the lower levels be
clear about such distinctions, and introduce convenience features in higher
layers.  That provides the option of having both constructs which make
strict distinctions, and those which favor convenience.

* I see Scheme's choice in this area as being focused on addressing the
requirement for low-level clarity.  One could always define macros to
implement convenience-oriented conditional constructs.  People don't
generally do that, probably because in the end, it's a pretty superficial
issue, that doesn't affect the semantics of programs.  I don't see the
separation of #f and nil as superficial, however, mainly because it's harder
to fake it if you don't have it, which is pretty much the definition of less
expressive.

Anton

[*] Re a separate discussion in c.l.s., I am using the term "type" here in
the ontic mood, pending clarification on what term I should be using
instead.
From: Jens Axel Søgaard
Subject: Re: Scheme closures
Date: 
Message-ID: <40917487$0$307$edfadb0f@dread11.news.tele.dk>
Pascal Costanza wrote:

> I would be interested in examples, especially those in which the 
> distinction between #f and nil plays an important role. Is there any 
> material available?

I suspect the place to look is

     <http://library.readscheme.org/page8.html>

under the heading

     "Program Analysis, Inlining and other Optimizations"

-- 
Jens Axel S�gaard
From: Joe Marshall
Subject: Re: Scheme closures
Date: 
Message-ID: <vfjgx7im.fsf@comcast.net>
>> Pascal Costanza <········@web.de> writes:
>>>
>>>What problems does the disjointness of types solve?

> Joe Marshall wrote:
>> It makes things easier to reason about.
>
> I would be interested in examples, especially those in which the
> distinction between #f and nil plays an important role. Is there any
> material available?

Dunno.  I don't think separating #f and nil was a good idea.


-- 
~jrm
From: Mark Wooding
Subject: Re: Scheme closures
Date: 
Message-ID: <slrnc9fksp.n01.mdw@tux.nsict.org>
Joe Marshall <·············@comcast.net> wrote:

> Dunno.  I don't think separating #f and nil was a good idea.

Separating #f from 'nil was a great plan.  The bit where Scheme went
wrong, I think, was in separating #f from '(), which does no good that I
can see whatever.  Scheme's disjointness of types doesn't suffer as a
result of terminating lists with #f instead of some other specially-
invented object.  I'd be happy if the default environment did
(define nil '()).

Summary: '() should be false, and anything else, including 'nil, should
be true; or, MIT Scheme gets it right.

-- [mdw]
From: Joe Marshall
Subject: Re: Scheme closures
Date: 
Message-ID: <n04mvdz6.fsf@comcast.net>
Mark Wooding <···@nsict.org> writes:

> Joe Marshall <·············@comcast.net> wrote:
>
>> Dunno.  I don't think separating #f and nil was a good idea.
>
> Separating #f from 'nil was a great plan.  The bit where Scheme went
> wrong, I think, was in separating #f from '(), which does no good that I
> can see whatever.  

Yes.  I should have said that more carefully.  I don't think that
separating #F from the empty list was a good idea.

-- 
~jrm
From: ifconfig
Subject: Re: Scheme closures
Date: 
Message-ID: <c7bkss$n99$1@news2.netvision.net.il>
I never did understand why a list should end with #f and not a list-specific
'()... (or a general null, but not false...)
Care to explain why it was like that in the first place?


-- 

ifconfig
BAGOS
http://bagos.sourceforge.net


"Joe Marshall" <·············@comcast.net> wrote in message
·················@comcast.net...
> Mark Wooding <···@nsict.org> writes:
>
> > Joe Marshall <·············@comcast.net> wrote:
> >
> >> Dunno.  I don't think separating #f and nil was a good idea.
> >
> > Separating #f from 'nil was a great plan.  The bit where Scheme went
> > wrong, I think, was in separating #f from '(), which does no good that I
> > can see whatever.
>
> Yes.  I should have said that more carefully.  I don't think that
> separating #F from the empty list was a good idea.
>
> -- 
> ~jrm
From: Pascal Costanza
Subject: Re: Scheme closures
Date: 
Message-ID: <c7crcj$n5q$1@newsreader2.netcologne.de>
ifconfig wrote:

> I never did understand why a list should end with #f and not a list-specific
> '()... (or a general null, but not false...)
> Care to explain why it was like that in the first place?

It makes typical list processing idioms more succinct.

(And it's actually the other way around: A list ends with (), and that 
value is also used for "false". This situation is similar to the use of 
0 as "false" in C-based languages.)


Pascal

-- 
1st European Lisp and Scheme Workshop
June 13 - Oslo, Norway - co-located with ECOOP 2004
http://www.cs.uni-bonn.de/~costanza/lisp-ecoop/
From: ifconfig
Subject: Re: Scheme closures
Date: 
Message-ID: <c7dtu3$eq6$1@news2.netvision.net.il>
My problems was basically with procedures that, e.g., read from a database
and return a list of results (empty if there are no query results), or false
if there was an error connecting to the database or in the syntax of the
query... What would you do in that case if '() were the same as #f?

-- 

ifconfig
BAGOS
http://bagos.sourceforge.net


"Pascal Costanza" <········@web.de> wrote in message
·················@newsreader2.netcologne.de...
>
> ifconfig wrote:
>
> > I never did understand why a list should end with #f and not a
list-specific
> > '()... (or a general null, but not false...)
> > Care to explain why it was like that in the first place?
>
> It makes typical list processing idioms more succinct.
>
> (And it's actually the other way around: A list ends with (), and that
> value is also used for "false". This situation is similar to the use of
> 0 as "false" in C-based languages.)
>
>
> Pascal
>
> -- 
> 1st European Lisp and Scheme Workshop
> June 13 - Oslo, Norway - co-located with ECOOP 2004
> http://www.cs.uni-bonn.de/~costanza/lisp-ecoop/
From: Pascal Costanza
Subject: Re: Scheme closures
Date: 
Message-ID: <c7dur2$uc$1@newsreader2.netcologne.de>
ifconfig wrote:

> My problems was basically with procedures that, e.g., read from a database
> and return a list of results (empty if there are no query results), or false
> if there was an error connecting to the database or in the syntax of the
> query... What would you do in that case if '() were the same as #f?

Don't return false when you have error - signal an error (by making use 
of the condition system in Common Lisp, of course ;).

Essentially: (error "There was an error connecting to the database.")

Chances are that the database library already does this for you.


Pascal

-- 
1st European Lisp and Scheme Workshop
June 13 - Oslo, Norway - co-located with ECOOP 2004
http://www.cs.uni-bonn.de/~costanza/lisp-ecoop/
From: Mark Wooding
Subject: Re: Scheme closures
Date: 
Message-ID: <slrnc9mp7j.n01.mdw@tux.nsict.org>
ifconfig <···@ntr.co.il> wrote:

> My problems was basically with procedures that, e.g., read from a
> database and return a list of results (empty if there are no query
> results), or false if there was an error connecting to the database or
> in the syntax of the query... What would you do in that case if '()
> were the same as #f?

Collapsing all errors to `#f' is obviously wrong anyway, since you're
discarding useful information about what the error actually was.  You
need an out-of-band way of reporting failure in this case.  While Scheme
doesn't have exceptions built-in they're easy enough to synthesise from
bits of string, call/cc and dynamic-wind; and many implementations have
them anyway.

-- [mdw]
From: Adam Warner
Subject: Re: Scheme closures
Date: 
Message-ID: <pan.2004.05.07.09.06.46.108315@consulting.net.nz>
Hi ifconfig,

> My problems was basically with procedures that, e.g., read from a
> database and return a list of results (empty if there are no query
> results), or false if there was an error connecting to the database or
> in the syntax of the query... What would you do in that case if '() were
> the same as #f?

While Pascal sensibly recommended signalling an error you could also
return NIL for an error and a list of the returned object otherwise. Thus
false returns NIL while an empty object is returned as (NIL). I don't like
this approach because a semantic error occurs if one ever forgets to take
the CAR of the returned object.

Returning multiple values is superior. Return the object or NIL as the
first value and the error result as the second value.

Common Lisp also has structures. You could return a type-safe encapsulated
query object such as #S(query object) or NIL for an error. Or switching
this around you could return the plain object or an error structure. You'd
only need to perform a predicate test to determine whether an error type
was returned. Or pack the information into a single structure and access
the query object as QUERY-OBJECT and the query status as QUERY-STATUS.

Regards,
Adam
From: Sander Vesik
Subject: Re: Scheme closures
Date: 
Message-ID: <1090866816.35629@haldjas.folklore.ee>
In comp.lang.scheme Pascal Costanza <········@web.de> wrote:
> 
> ifconfig wrote:
> 
> > I never did understand why a list should end with #f and not a list-specific
> > '()... (or a general null, but not false...)
> > Care to explain why it was like that in the first place?
> 
> It makes typical list processing idioms more succinct.

making everything a list processing problem is the curse of lisp and 
avoiding it is a good thing.

> 
> (And it's actually the other way around: A list ends with (), and that 
> value is also used for "false". This situation is similar to the use of 
> 0 as "false" in C-based languages.)
> 

except java that is c based and a bunch of other c offshoots too ... this is 
in fcat a very bad argument to bring in favour of it.

> 
> Pascal
> 

-- 
	Sander

+++ Out of cheese error +++
From: Hannah Schroeter
Subject: Re: Scheme closures
Date: 
Message-ID: <ce3jnd$o3g$1@c3po.use.schlund.de>
Hello!

Sander Vesik  <······@haldjas.folklore.ee> wrote:
>In comp.lang.scheme Pascal Costanza <········@web.de> wrote:

>> ifconfig wrote:

>> > I never did understand why a list should end with #f and not a list-specific
>> > '()... (or a general null, but not false...)
>> > Care to explain why it was like that in the first place?

>> It makes typical list processing idioms more succinct.

>making everything a list processing problem is the curse of lisp and 
>avoiding it is a good thing.

Common Lisp has arrays, strings, structures, classes (and instances
thereof). So it's only the curse of bad teaching and bad usage of Lisp.

>[...]

Kind regards,

Hannah.
From: Pascal Costanza
Subject: Re: Scheme closures
Date: 
Message-ID: <ce3k3k$i8s$1@newsreader2.netcologne.de>
Sander Vesik wrote:
> In comp.lang.scheme Pascal Costanza <········@web.de> wrote:
> 
>>ifconfig wrote:
>>
>>>I never did understand why a list should end with #f and not a list-specific
>>>'()... (or a general null, but not false...)
>>>Care to explain why it was like that in the first place?
>>
>>It makes typical list processing idioms more succinct.
> 
> making everything a list processing problem is the curse of lisp and 
> avoiding it is a good thing.

I certainly didn't suggest to "make everything a list processing problem".

>>(And it's actually the other way around: A list ends with (), and that 
>>value is also used for "false". This situation is similar to the use of 
>>0 as "false" in C-based languages.)
> 
> except java that is c based and a bunch of other c offshoots too ... this is 
> in fcat a very bad argument to bring in favour of it.

So what? A pattern or idiom that doesn't work well in some circumstances 
might work excellent in others.


Pascal

-- 
Tyler: "How's that working out for you?"
Jack: "Great."
Tyler: "Keep it up, then."
From: Matthew Danish
Subject: Re: Scheme closures
Date: 
Message-ID: <20040506155623.GJ25328@mapcar.org>
On Thu, May 06, 2004 at 06:03:40PM +0900, Alex Shinn wrote:
> P.S. I foolishly wrote the above ASSQ2 first as ASSQ which promptly
> hosed CMUCL, requiring me to suspend it and kill it from the shell.  I
> think I'll stick to lexical scope for my functions :)

This is a classic way to hose CMUCL =)  Actually, what is happening is
that the function EXT:ASSQ (ASSQ is not standard) is used by some part
of the top-level and redefining it causes that to break.

Not sure what the definition of top-level functions has to do with
lexical scope.  Scheme has this problem even more than Common Lisp,
because at least CL has packages.  In this case, the symbol is imported
into the default package so yes, it conflicts with random code you input
into the top-level (which is not advised for anything more serious, you
should make your own package then).  And package-locks could be
instituted to prevent this from happening as well.  

Also, you seem to be a bit confused about the semantics of ASSOC.  ASSOC
returns the cons cell that matches, so in (assoc 'a '((a nil))) => (A
NIL) and (assoc nil '((nil a))) => (NIL A).  Quite clearly there is no
chance for confusion of a successful match with that of a failure to
match.  Basically, the result type of ASSOC is CONS if success and NULL
if failure.  Introducing an out-of-band *not-found* unique value is
pointless, and an out-of-date tactic anyhow.  These days, we use a
second channel for such information, such as conditions or multiple
values.

-- 
; Matthew Danish <·······@andrew.cmu.edu>
; OpenPGP public key: C24B6010 on keyring.debian.org
; Signed or encrypted mail welcome.
; "There is no dark side of the moon really; matter of fact, it's all dark."
From: Pascal Costanza
Subject: Re: Scheme closures
Date: 
Message-ID: <c7d4dr$q20$1@f1node01.rhrz.uni-bonn.de>
Alex Shinn wrote:
> At Thu, 29 Apr 2004 22:32:21 +0200, Pascal Costanza wrote:
> 
>>I would be interested in examples, especially those in which the 
>>distinction between #f and nil plays an important role. Is there any 
>>material available?
> 
> Apart from the implementation reasons there are some things that are
> easier to express with #f and '() disjoint, just as there are things
> that are easier to express with them equivalent.
> 
> For example, considering the "large-programs" example posted
> illustrating the latter case, the Scheme version of this has the nice
> advantage that you can store '() as a reference in the a-list which has
> a distinct meaning from the key not being in the a-list.  I take
> advantage of this all the time - since lists are used so heavily in
> Lisp, it can be very handy to be able to actually store them
> meaningfully in a-lists (or hash-tables or whatever).
> 
> To handle this in the Common-Lisp version you'd have to redefine assq to
> return a unique symbol other than '():

Not quite. Common Lisp's ASSOC works on lists that contain conses 
(pairs), and returns a cons when it has found one, and nil otherwise. So 
the typical idiom is this:

(let ((cons (assoc item alist)))
   (when cons
      ... (cdr cons) ...))

...and this is unambiguous.

Other lookup functions for similar data structures (GETF for property 
lists, GETHASH for hash tables) allow you to specify a default value to 
be returned when they don't find what you're looking for. So this allows 
you to say this:

(let* ((undefined (gensym))
        (result (gethash key table undefined)))
   (if (eq result undefined)
      (...)
      (... result ...)))


Pascal

P.S.: Apart from that, these are not examples for reasoning about code.

-- 
ECOOP 2004 Workshops - Oslo, Norway
*1st European Lisp and Scheme Workshop, June 13*
http://www.cs.uni-bonn.de/~costanza/lisp-ecoop/
*2nd Post-Java Workshop, June 14*
http://prog.vub.ac.be/~wdmeuter/PostJava04/
From: Marco Antoniotti
Subject: Re: Scheme closures
Date: 
Message-ID: <Nfrmc.149$a5.46535@typhoon.nyu.edu>
Pascal Costanza wrote:

> Alex Shinn wrote:
> 
....
> Not quite. Common Lisp's ASSOC works on lists that contain conses 
> (pairs), and returns a cons when it has found one, and nil otherwise. So 
> the typical idiom is this:
> 
> (let ((cons (assoc item alist)))
>   (when cons
>      ... (cdr cons) ...))
> 
> ...and this is unambiguous.
> 
> Other lookup functions for similar data structures (GETF for property 
> lists, GETHASH for hash tables) allow you to specify a default value to 
> be returned when they don't find what you're looking for. So this allows 
> you to say this:
> 
> (let* ((undefined (gensym))
>        (result (gethash key table undefined)))
>   (if (eq result undefined)
>      (...)
>      (... result ...)))
> 

Not only that.  GETHASH returns two values

(defvar *ht* (make-hash-table)) ==> #<HASH-TABLE>

(gethash 'nil *ht*) ==> NIL, NIL

(setf (gethash 'nil *ht*) 'nil #|or 42 |#) ==> NIL

(gethash 'nil *ht*) ==> NIL, T


Cheers

marco
From: Mario S. Mommer
Subject: Re: Scheme closures
Date: 
Message-ID: <fzk6zpeq6z.fsf@germany.igpm.rwth-aachen.de>
Pascal Costanza <········@web.de> writes:
[...]
> Other lookup functions for similar data structures (GETF for property
> lists, GETHASH for hash tables) allow you to specify a default value
> to be returned when they don't find what you're looking for. So this
> allows you to say this:
>
> (let* ((undefined (gensym))
>         (result (gethash key table undefined)))
>    (if (eq result undefined)
>       (...)
>       (... result ...)))

GETHASH also returns two values. Another way of doing the above would
be

(multiple-value-bind (value found-p)
       (gethash key table)
    (if found-p ...

AFAICT, the semantics of GETF are a bit different, as the default
value for a given property (getf operates on property list) is
NIL. The &optional default parameter is just a convenience for locally
altering this behavior.

> P.S.: Apart from that, these are not examples for reasoning about code.

Indeed.

From my brief study of these matters I get the impression that the
whole type system business gets very serious problems when variables
of different types can hold the same value (here that would be both
boolean and list variables holding NIL).
From: Marcin 'Qrczak' Kowalczyk
Subject: Re: Scheme closures
Date: 
Message-ID: <pan.2004.04.30.08.04.18.328671@knm.org.pl>
On Thu, 29 Apr 2004 10:48:34 +0200, Pascal Costanza wrote:

>>>You mean like the time when Scheme changed from #f and nil
>>>being the same object to #f and nil being distinct objects?
>>>(IIRC, this was a change from R3RS to R4RS.)
>>
>> Ah yes, you mean back in the previous century?  It was a primitive time --
>> in those days, they had only just begun to comprehend these mysterious
>> things we now know as "disjoint types".
> 
> What problems does the disjointness of types solve?

It reduces confusion similar to here:
http://www.google.pl/groups?as_umsgid=5YqdnQyT88n2Rg3dRVn-tw%40speakeasy.net

-- 
   __("<         Marcin Kowalczyk
   \__/       ······@knm.org.pl
    ^^     http://qrnik.knm.org.pl/~qrczak/
From: Matthew Danish
Subject: Re: Scheme closures
Date: 
Message-ID: <20040430090438.GZ25328@mapcar.org>
On Fri, Apr 30, 2004 at 10:04:21AM +0200, Marcin 'Qrczak' Kowalczyk wrote:
> > What problems does the disjointness of types solve?
> 
> It reduces confusion similar to here:
> http://www.google.pl/groups?as_umsgid=5YqdnQyT88n2Rg3dRVn-tw%40speakeasy.net

And causes confusion similar to here:
http://www.lisp.org/humor/large-programs.html

=)

-- 
; Matthew Danish <·······@andrew.cmu.edu>
; OpenPGP public key: C24B6010 on keyring.debian.org
; Signed or encrypted mail welcome.
; "There is no dark side of the moon really; matter of fact, it's all dark."
From: Mario S. Mommer
Subject: Re: Scheme closures
Date: 
Message-ID: <fz65bhbwrl.fsf@germany.igpm.rwth-aachen.de>
Matthew Danish <·······@andrew.cmu.edu> writes:
> On Fri, Apr 30, 2004 at 10:04:21AM +0200, Marcin 'Qrczak' Kowalczyk wrote:
>> > What problems does the disjointness of types solve?
>> 
>> It reduces confusion similar to here:
>> http://www.google.pl/groups?as_umsgid=5YqdnQyT88n2Rg3dRVn-tw%40speakeasy.net
>
> And causes confusion similar to here:
> http://www.lisp.org/humor/large-programs.html

:)

Not to mention that you cannot assign anything reasonable to

(if #f #f)

What an ugly wart for a "semantically clean" language :)
From: Pascal Costanza
Subject: Re: Scheme closures
Date: 
Message-ID: <c6t60t$oku$1@f1node01.rhrz.uni-bonn.de>
Marcin 'Qrczak' Kowalczyk wrote:
> On Thu, 29 Apr 2004 10:48:34 +0200, Pascal Costanza wrote:
> 
>>>>You mean like the time when Scheme changed from #f and nil
>>>>being the same object to #f and nil being distinct objects?
>>>>(IIRC, this was a change from R3RS to R4RS.)
>>>
>>>Ah yes, you mean back in the previous century?  It was a primitive time --
>>>in those days, they had only just begun to comprehend these mysterious
>>>things we now know as "disjoint types".
>>
>>What problems does the disjointness of types solve?
> 
> It reduces confusion similar to here:
> http://www.google.pl/groups?as_umsgid=5YqdnQyT88n2Rg3dRVn-tw%40speakeasy.net

OK.


Pascal

-- 
ECOOP 2004 Workshops - Oslo, Norway
*1st European Lisp and Scheme Workshop, June 13*
http://www.cs.uni-bonn.de/~costanza/lisp-ecoop/
*2nd Post-Java Workshop, June 14*
http://prog.vub.ac.be/~wdmeuter/PostJava04/
From: Joe Marshall
Subject: Re: Scheme closures
Date: 
Message-ID: <oepchrux.fsf@comcast.net>
Mario S. Mommer <········@yahoo.com> writes:

> Jens Axel S�gaard <······@soegaard.net> writes:
>> Isn't that a bit silly?
>
> Indeed.
>
> And while it is also mildly entertaining, I wonder why you keep
> crossposting this to c.l.l?

To enlighten the savages?

I wasn't paying attention to the headers.  Sorry about that.

-- 
~jrm
From: Sander Vesik
Subject: Re: Scheme closures
Date: 
Message-ID: <1083626559.304210@haldjas.folklore.ee>
In comp.lang.scheme Jens Axel S?gaard <······@soegaard.net> wrote:
> Joe Marshall wrote:
> 
> > ··········@verizon.net (William D Clinger) writes:
> 
> >>It looks controversial to me.  (if #f #f) might return an inexact
> >>approximation to pi.  I don't think there are too many people who
> >>would argue that (EQ? (acos -1) (acos -1)) should be required to
> >>return #t, because that would make EQ? much more complicated in
> >>many implementations.
> 
> > Yes, but I do think that you will find people to argue that
> > 
> >   (let ((x (acos -1)))
> >     (eq? x x))
> > 
> > really should be #t.
> 
> So the unspecified value returned should have an implementation
> independent specified behaviour?
> 
> Isn't that a bit silly?
> 

Maybe, maybe not. It depends on if you (portably) want it to always
consistently be a single (and the same) value. This is slightly 
a preference question but deciding either way (with 'no' meaning
continuation of present state) is not silly.

-- 
	Sander

+++ Out of cheese error +++
From: Pascal Costanza
Subject: Re: Scheme closures
Date: 
Message-ID: <c6ok2k$70d$1@newsreader2.netcologne.de>
William D Clinger wrote:

> It looks controversial to me.  (if #f #f) might return an inexact
> approximation to pi
[...]

This seems to be about very low-level details of the Scheme spec. Why 
are you cross-posting this to comp.lang.lisp?


Pascal

-- 
1st European Lisp and Scheme Workshop
June 13 - Oslo, Norway - co-located with ECOOP 2004
http://www.cs.uni-bonn.de/~costanza/lisp-ecoop/
From: Sander Vesik
Subject: Re: Scheme closures
Date: 
Message-ID: <1083626376.684048@haldjas.folklore.ee>
In comp.lang.scheme Joe Marshall <·············@comcast.net> wrote:
> "Anton van Straaten" <·····@appsolutions.com> writes:
> 
> > Finally, programs shouldn't rely on an unspecified value to be equal to
> > anything - that would be totally against the meaning of "unspecified".  
> 
> Except exactly itself.  I hope that
> 
>   (let ((x (if #f #f)))
>     (eq? x x))
> 
> returns #t.
> 

There is no gurantee that it would, or that it would do so 
consitently. The same applies if you replace eq? with any
other predicate. 

-- 
	Sander

+++ Out of cheese error +++
From: Joe Marshall
Subject: Re: Scheme closures
Date: 
Message-ID: <fzagns2p.fsf@ccs.neu.edu>
Sander Vesik <······@haldjas.folklore.ee> writes:

> In comp.lang.scheme Joe Marshall <·············@comcast.net> wrote:
>> "Anton van Straaten" <·····@appsolutions.com> writes:
>> 
>> > Finally, programs shouldn't rely on an unspecified value to be equal to
>> > anything - that would be totally against the meaning of "unspecified".  
>> 
>> Except exactly itself.  I hope that
>> 
>>   (let ((x (if #f #f)))
>>     (eq? x x))
>> 
>> returns #t.
>> 
>
> There is no gurantee that it would, or that it would do so 
> consistently.  The same applies if you replace eq? with any
> other predicate.

The question is, then, is an `unspecified value' a real `value' (if
there is such a thing)?

Could more than one of these predicates return #T when applied to it?

   boolean?   pair?
   symbol?    number?
   char?      string?
   vector?    port?
   procedure?
From: Sander Vesik
Subject: Re: Scheme closures
Date: 
Message-ID: <1083709004.681909@haldjas.folklore.ee>
In comp.lang.scheme Joe Marshall <···@ccs.neu.edu> wrote:
> Sander Vesik <······@haldjas.folklore.ee> writes:
> 
> > In comp.lang.scheme Joe Marshall <·············@comcast.net> wrote:
> >> "Anton van Straaten" <·····@appsolutions.com> writes:
> >> 
> >> > Finally, programs shouldn't rely on an unspecified value to be equal to
> >> > anything - that would be totally against the meaning of "unspecified".  
> >> 
> >> Except exactly itself.  I hope that
> >> 
> >>   (let ((x (if #f #f)))
> >>     (eq? x x))
> >> 
> >> returns #t.
> >> 
> >
> > There is no gurantee that it would, or that it would do so 
> > consistently.  The same applies if you replace eq? with any
> > other predicate.
> 
> The question is, then, is an `unspecified value' a real `value' (if
> there is such a thing)?

what about :

	(let ((x (if #f #f))) 
		(let ((y x)) 
			(eq? x y))

it might not get optimised away in the same way - so would an implementation
of eq? that starts with:

	if (arg1 == scheme_unspecific)
		return 0;

be necesarily flawed? 

> 
> Could more than one of these predicates return #T when applied to it?
> 
>    boolean?   pair?
>    symbol?    number?
>    char?      string?
>    vector?    port?
>    procedure?

They shouldn't, at leats not in R5RS. But they might all return #f.

-- 
	Sander

+++ Out of cheese error +++
From: ifconfig
Subject: Re: Scheme closures
Date: 
Message-ID: <c7a6nq$6qe$1@news2.netvision.net.il>
The unspecified value returned by (if #f #f) is unspecified within R5RS.
That means implementations can choose the value themselves, be it (void),
#f, () or #unpsecified.
But it is still a value. And every value is eq? to itself, is it not?
The unspecified value may be different from what (if #f #f) would return
next time, meaning (eq? (if #f #f) (if #f #f)) could return false, but
whatever it returns, it is equal to itself.
(let ([x (anything)])
  (let ([y x])
    (eq? x y)))
will always return true (or an error).

-- 

ifconfig
BAGOS
http://bagos.sourceforge.net


"Sander Vesik" <······@haldjas.folklore.ee> wrote in message
······················@haldjas.folklore.ee...
> In comp.lang.scheme Joe Marshall <···@ccs.neu.edu> wrote:
> > Sander Vesik <······@haldjas.folklore.ee> writes:
> >
> > > In comp.lang.scheme Joe Marshall <·············@comcast.net> wrote:
> > >> "Anton van Straaten" <·····@appsolutions.com> writes:
> > >>
> > >> > Finally, programs shouldn't rely on an unspecified value to be
equal to
> > >> > anything - that would be totally against the meaning of
"unspecified".
> > >>
> > >> Except exactly itself.  I hope that
> > >>
> > >>   (let ((x (if #f #f)))
> > >>     (eq? x x))
> > >>
> > >> returns #t.
> > >>
> > >
> > > There is no gurantee that it would, or that it would do so
> > > consistently.  The same applies if you replace eq? with any
> > > other predicate.
> >
> > The question is, then, is an `unspecified value' a real `value' (if
> > there is such a thing)?
>
> what about :
>
> (let ((x (if #f #f)))
> (let ((y x))
> (eq? x y))
>
> it might not get optimised away in the same way - so would an
implementation
> of eq? that starts with:
>
> if (arg1 == scheme_unspecific)
> return 0;
>
> be necesarily flawed?
>
> >
> > Could more than one of these predicates return #T when applied to it?
> >
> >    boolean?   pair?
> >    symbol?    number?
> >    char?      string?
> >    vector?    port?
> >    procedure?
>
> They shouldn't, at leats not in R5RS. But they might all return #f.
>
> -- 
> Sander
>
> +++ Out of cheese error +++
From: Ray Dillinger
Subject: Re: Scheme closures
Date: 
Message-ID: <YX7mc.9773$Fo4.124033@typhoon.sonic.net>
ifconfig wrote:
> The unspecified value returned by (if #f #f) is unspecified within R5RS.
> That means implementations can choose the value themselves, be it (void),
> #f, () or #unpsecified.
> But it is still a value. And every value is eq? to itself, is it not?
> The unspecified value may be different from what (if #f #f) would return
> next time, meaning (eq? (if #f #f) (if #f #f)) could return false, but
> whatever it returns, it is equal to itself.
> (let ([x (anything)])
>   (let ([y x])
>     (eq? x y)))
> will always return true (or an error).
> 


Not necessarily true as stated, because eq? is more than just
a value comparison.  Eq's behavior is not guaranteed on some
types of data.  If you use one of the other equality predicates,
I think it is true.

				Bear
From: ifconfig
Subject: Re: Scheme closures
Date: 
Message-ID: <c78qu7$plu$1@news2.netvision.net.il>
"Joe Marshall" <···@ccs.neu.edu> wrote in message
·················@ccs.neu.edu...
> Sander Vesik <······@haldjas.folklore.ee> writes:
>
> > In comp.lang.scheme Joe Marshall <·············@comcast.net> wrote:
> >> "Anton van Straaten" <·····@appsolutions.com> writes:
> >>
> >> > Finally, programs shouldn't rely on an unspecified value to be equal
to
> >> > anything - that would be totally against the meaning of
"unspecified".
> >>
> >> Except exactly itself.  I hope that
> >>
> >>   (let ((x (if #f #f)))
> >>     (eq? x x))
> >>
> >> returns #t.
> >>
> >
> > There is no gurantee that it would, or that it would do so
> > consistently.  The same applies if you replace eq? with any
> > other predicate.
>
> The question is, then, is an `unspecified value' a real `value' (if
> there is such a thing)?

The unspecified value can, and I believe should be a value.
As unspecified as it may be, it's still an unspecified *value*

-- 

ifconfig
BAGOS
http://bagos.sourceforge.net
From: Rahul Jain
Subject: Re: Scheme closures
Date: 
Message-ID: <873c720zwg.fsf@nyct.net>
Grzegorz =?UTF-8?B?Q2hydXBhxYJh?= <········@pithekos.net> writes:

> For the record: this common extension can be easily written as a
> syntax-rules macro.

Ahem? Is scheme's `begin' not a separate lexical scope? It's not a
primitive and it's hygenic. I don't see how that would allow it to
define bindings outside of itself.

-- 
Rahul Jain
·····@nyct.net
Professional Software Developer, Amateur Quantum Mechanicist
From: Anton van Straaten
Subject: Re: Scheme closures
Date: 
Message-ID: <hzmgc.13515$zj3.6796@newsread3.news.atl.earthlink.net>
> > For the record: this common extension can be easily written as a
> > syntax-rules macro.
>
> Ahem? Is scheme's `begin' not a separate lexical scope?

No.  See R5RS 5.1: "At the top level of a program (begin <form1> ...) is
equivalent to the sequence of expressions, definitions, and syntax
definitions that form the body of the begin."

> It's not a primitive

At the top level at least, it is a primitive, because of the above.

> and it's hygenic. I don't see how that would allow
> it to define bindings outside of itself.

The wonder of axioms.

Anton
From: Rahul Jain
Subject: Re: Scheme closures
Date: 
Message-ID: <87isfxyhuy.fsf@nyct.net>
"Anton van Straaten" <·····@appsolutions.com> writes:

>> > For the record: this common extension can be easily written as a
>> > syntax-rules macro.
>>
>> Ahem? Is scheme's `begin' not a separate lexical scope?
>
> No.  See R5RS 5.1: "At the top level of a program (begin <form1> ...) is
> equivalent to the sequence of expressions, definitions, and syntax
> definitions that form the body of the begin."
>
>> It's not a primitive
>
> At the top level at least, it is a primitive, because of the above.
>
>> and it's hygenic. I don't see how that would allow
>> it to define bindings outside of itself.
>
> The wonder of axioms.

Ok, then section 4.2.3 does not belong in section 4.2 in r5rs without at
least some indication that it doesn't conform to the rules that section
4.2 claims all defintions in that section follow. Most preferably with a
reference to section 5.1.

-- 
Rahul Jain
·····@nyct.net
Professional Software Developer, Amateur Quantum Mechanicist
From: Anton van Straaten
Subject: Re: Scheme closures
Date: 
Message-ID: <Wrpgc.13610$zj3.3998@newsread3.news.atl.earthlink.net>
Rahul Jain wrote:

> "Anton van Straaten" <·····@appsolutions.com> writes:
...
> >> Ahem? Is scheme's `begin' not a separate lexical scope?
> >
> > No.  See R5RS 5.1: "At the top level of a program (begin <form1> ...) is
> > equivalent to the sequence of expressions, definitions, and syntax
> > definitions that form the body of the begin."
...
> Ok, then section 4.2.3 does not belong in section 4.2 in r5rs without at
> least some indication that it doesn't conform to the rules that section
> 4.2 claims all defintions in that section follow. Most preferably with a
> reference to section 5.1.

Sorry, I should have mentioned that this is addressed in the errata for
R5RS:
http://mumble.net/~kelsey/r5rs-errata.html

...under the heading "Begin at top level".

Anton
From: Bradd W. Szonye
Subject: Re: Scheme closures
Date: 
Message-ID: <slrnc855nh.7ph.bradd+news@szonye.com>
> Rahul Jain wrote:
>> Ok, then section 4.2.3 does not belong in section 4.2 in r5rs without at
>> least some indication that it doesn't conform to the rules that section
>> 4.2 claims all defintions in that section follow. Most preferably with a
>> reference to section 5.1.

Anton van Straaten wrote:
> Sorry, I should have mentioned that this is addressed in the errata for
> R5RS:
> http://mumble.net/~kelsey/r5rs-errata.html
> 
> ...under the heading "Begin at top level".

That errata list does not mention the use of BEGIN to splice internal
definitions, though. There are three different BEGINs in Scheme:

1. (begin <sequence>), a derived expression
2. (begin <command or definition>+), a top-level splicing command
3. (begin <definition>*), a splicing definition

This makes BEGIN parsing a bit tricky. It can contain different things,
depending on where it appears. BEGIN can be empty, but only at top level
or in a sequence of internal definitions. It can contain both
definitions and commands/expressions, but only at top level. Otherwise,
it must contain definitions only or commands/expressions only. If the
former, it can only appear at top level or in a sequence of internal
definitions.

I wish these different syntaxes had different names; it'd make it much
easier to write a Scheme interpreter.
-- 
Bradd W. Szonye
http://www.szonye.com/bradd
From: Anton van Straaten
Subject: Re: Scheme closures
Date: 
Message-ID: <58Cgc.3$gH6.0@newsread3.news.atl.earthlink.net>
Bradd W. Szonye wrote:

> > Rahul Jain wrote:
> >> Ok, then section 4.2.3 does not belong in section 4.2 in r5rs without
at
> >> least some indication that it doesn't conform to the rules that section
> >> 4.2 claims all defintions in that section follow. Most preferably with
a
> >> reference to section 5.1.
>
> Anton van Straaten wrote:
> > Sorry, I should have mentioned that this is addressed in the errata for
> > R5RS:
> > http://mumble.net/~kelsey/r5rs-errata.html
> >
> > ...under the heading "Begin at top level".
>
> That errata list does not mention the use of BEGIN to splice internal
> definitions, though.

That use is mentioned in R5RS 5.2.2.  I should have mentioned it, though.

> There are three different BEGINs in Scheme:
>
> 1. (begin <sequence>), a derived expression
> 2. (begin <command or definition>+), a top-level splicing command
> 3. (begin <definition>*), a splicing definition
...
> I wish these different syntaxes had different names; it'd make it
> much easier to write a Scheme interpreter.

At the level of an interpreter or compiler, you really only need two kinds
of BEGIN: the splicing kind, and the derived expression kind.  The former is
valid in definition contexts and at top level, and can be empty; the latter
is valid in expression contexts, and cannot be empty.  If a splicing BEGIN
expands to a sequence of definitions, commands and expressions that isn't
valid in the context into which it is spliced, that can be handled by the
same code that would handle such a sequence without a BEGIN.

The above implies an extension which doesn't seem to be specified by R5RS:
it allows the splicing form (begin <body>) to appear at the end of a
(possibly otherwise empty) sequence of internal definitions.  In that
context, it is equivalent to <body>, i.e. equivalent to <definition>*
<sequence>.  It can also occur at top-level, but then it's a special case of
#2 above.

You might decide you want strict R5RS compliance, so don't want to allow the
above extension, in which case you need a special rule to disallow this kind
of BEGIN.  However, afaict, you really don't want to do that.  Someone
please correct me if I'm wrong, but without this variant of BEGIN, many
syntax-rules macros would be difficult (impossible?) to write, because there
would be no direct way to define values intended to splice into the invoking
context, and then make use of those definitions in the same macro.  Macros
would have a choice of generating definitions, or a sequence of expressions,
but not both (except at top level).

My conclusion is that this is a case where "Scheme" transcends R5RS - the
"correct" definition of Scheme is simpler and more consistent than the
subset which R5RS presents in this case.

Anton
From: Bradd W. Szonye
Subject: Re: Scheme closures
Date: 
Message-ID: <slrnc85ub4.7ph.bradd+news@szonye.com>
Bradd wrote:
>> There are three different BEGINs in Scheme:
>>
>> 1. (begin <sequence>), a derived expression
>> 2. (begin <command or definition>+), a top-level splicing command
>> 3. (begin <definition>*), a splicing definition
>>
>> I wish these different syntaxes had different names; it'd make it
>> much easier to write a Scheme interpreter.

Anton van Straaten wrote:
> At the level of an interpreter or compiler, you really only need two
> kinds of BEGIN: the splicing kind, and the derived expression kind
> .... The above implies an extension which doesn't seem to be specified
> by R5RS: it allows the splicing form (begin <body>) to appear at the
> end of a ... sequence of internal definitions ....

True. I was actually a bit surprised that R5RS didn't define it that
way. It's certainly easier to implement; you don't need to expand as
much to determine which sort of BEGIN you're dealing with.

Then again, I still think it's weird to use BEGIN as a splicing
construct. It only seems useful for macros, and splicing BEGIN has
vastly different semantics from expression BEGIN. I think it'd be better
to give them different names (or to eliminate the need for splicing
BEGIN by allowing macros to generate more than one expression).

Heck, even expression BEGIN is a bit weird. It's an abbreviation for
((lambda () <sequence>)); why <sequence> and not <body>? The naive
syntax-rules implementation would permit a <body> anyway.

I'm not very happy about BEGIN as defined. It's an ugly wart.

> You might decide you want strict R5RS compliance, so don't want to
> allow the above extension, in which case you need a special rule to
> disallow this kind of BEGIN.  However, afaict, you really don't want
> to do that.  Someone please correct me if I'm wrong, but without this
> variant of BEGIN, many syntax-rules macros would be difficult
> (impossible?) to write, because there would be no direct way to define
> values intended to splice into the invoking context, and then make use
> of those definitions in the same macro.

Is that really desirable, though? Perhaps. If so, it'd be better served
by a general splicing construct, rather than the bizarre BEGIN stuff in
R5RS.

> My conclusion is that this is a case where "Scheme" transcends R5RS -
> the "correct" definition of Scheme is simpler and more consistent than
> the subset which R5RS presents in this case.

Eh, I'd be even happier with a SPLICE form that just does splicing,
regardless of context and a BEGIN form that's just shorthand for
((lambda () <body>)).
-- 
Bradd W. Szonye
http://www.szonye.com/bradd
From: Bradd W. Szonye
Subject: Re: Scheme closures
Date: 
Message-ID: <slrnc854f8.7ph.bradd+news@szonye.com>
Anton van Straaten <·····@appsolutions.com> wrote:
>> > For the record: this common extension can be easily written as a
>> > syntax-rules macro.
>>
>> Ahem? Is scheme's `begin' not a separate lexical scope?
> 
> No.  See R5RS 5.1: "At the top level of a program (begin <form1> ...) is
> equivalent to the sequence of expressions, definitions, and syntax
> definitions that form the body of the begin."
> 
>> It's not a primitive ....
> 
> At the top level at least, it is a primitive, because of the above.

It's also a primitive when (1) it appears in a series of internal
definitions and (2) it contains nothing but definitions.
-- 
Bradd W. Szonye
http://www.szonye.com/bradd
From: Rahul Jain
Subject: Re: Scheme closures
Date: 
Message-ID: <877jwe102s.fsf@nyct.net>
Adam Warner <······@consulting.net.nz> writes:

> The Scheme version suffers from duplication of variable names and
> assignments and the inability to rely upon a defined return value from
> set! assignments. But overall it's not too bad even though I can see why
> the translation wasn't immediately obvious.

And, AFAIK, it cannot be macroized.

-- 
Rahul Jain
·····@nyct.net
Professional Software Developer, Amateur Quantum Mechanicist
From: Anton van Straaten
Subject: Re: Scheme closures
Date: 
Message-ID: <3Fmgc.13531$zj3.10260@newsread3.news.atl.earthlink.net>
Rahul Jain wrote:
> Adam Warner <······@consulting.net.nz> writes:
>
> > The Scheme version suffers from duplication of variable names and
> > assignments and the inability to rely upon a defined return value from
> > set! assignments. But overall it's not too bad even though I can see why
> > the translation wasn't immediately obvious.
>
> And, AFAIK, it cannot be macroized.

It can.  In fact, the reason for the 'begin' behavior you asked about
elsewhere is to support this kind of macro.

Anton
From: David Steuber
Subject: Re: Scheme closures
Date: 
Message-ID: <87hdvimiub.fsf@david-steuber.com>
Curiously, the only thought that went through the potted geraniums
was, "oh no.  Not again!"  Philosophers have argued that if we knew
what that ment, we would understand a lot more about the universe.

-- 
I wouldn't mind the rat race so much if it wasn't for all the damn cats.
From: Rahul Jain
Subject: Re: Scheme closures
Date: 
Message-ID: <87ekqmyndh.fsf@nyct.net>
David Steuber <·····@david-steuber.com> writes:

> Curiously, the only thought that went through the potted geraniums
> was, "oh no.  Not again!"  Philosophers have argued that if we knew
> what that ment, we would understand a lot more about the universe.

And that when that happened, it would be replaced with something even
more bizarre and inexplicable. (Although I find the concept of a more
bizarre and inexplicable universe than the one we are in now to be
rather, well, bizarre and inexplicable.)

-- 
Rahul Jain
·····@nyct.net
Professional Software Developer, Amateur Quantum Mechanicist
From: Svein Ove Aas
Subject: Re: Scheme closures
Date: 
Message-ID: <2Kugc.25982$zf6.99272@news4.e.nsc.no>
Rahul Jain wrote:

> David Steuber <·····@david-steuber.com> writes:
> 
>> Curiously, the only thought that went through the potted geraniums
>> was, "oh no.  Not again!"  Philosophers have argued that if we knew
>> what that ment, we would understand a lot more about the universe.
> 
> And that when that happened, it would be replaced with something even
> more bizarre and inexplicable. (Although I find the concept of a more
> bizarre and inexplicable universe than the one we are in now to be
> rather, well, bizarre and inexplicable.)
 
It has been theorized that this has already happened, mind you.

That would indeed explain quite a bit.


(Although I find the concept of a macroscopically similar universe running
on different rules to be rather bizarre and inexplicable.)
From: Anton van Straaten
Subject: Re: Scheme closures
Date: 
Message-ID: <q_ggc.13281$zj3.4989@newsread3.news.atl.earthlink.net>
Adam Warner wrote:
> Please try your best to translate this Common Lisp code to Scheme:
>
> (let ((state 0))
>   (defun inc ()
>     (incf state))
>   (defun dec ()
>     (decf state))
>   (defun reset ()
>     (setf state 0)))

To complement the other replies, if you're feeling homesick, you could write
something like:

(top-let ((state 0))
  (defun inc () (inc! state))
  (defun dec () (dec! state))
  (defun reset () (set! state 0) 0))

...given the following macro:

(define-syntax top-let
  (syntax-rules (defun)
    ((_ ((var val) ...)
        (defun name (formal ...) fn-body ...)
        ...)
     (begin
       (define name #f)
       ...
       (let ((var val) ...)
         (set! name (lambda (formal ...) fn-body ...))
         ...)))))

...plus macros for inc! and dec!, which are common but not standardized in
R5RS, e.g.:

(define-syntax inc! (syntax-rules () ((_ x) (begin (set! x (+ x 1)) x))))
(define-syntax dec! (syntax-rules () ((_ x) (begin (set! x (- x 1)) x))))


Or, we could get rid of the defuns entirely, and go for something like this:

(make-state-wrapper ((x 0))
  (inc x (+ x 1))
  (dec x (- x 1))
  (reset x 0))

Which uses the following macro:

(define-syntax make-state-wrapper
  (syntax-rules ()
    ((_ ((var val) ...) (name x expr) ...)
     (begin
       (define name #f) ...
       (let ((var val) ...)
         (set! name (lambda () (set! x expr) x))
         ...)))))

> I'm beginning to appreciate that the main reason for exclamation naming
> is to shout to the programmer to be careful because the language doesn't
> provide a default order of evaluation

Not really, it's just because Scheme's functional orientation tends to
consider side effects something worth highlighting.

> (perhaps to permit parallel evaluation of arguments as the default,
> which could be a performance benefit in some architectures).

The order of evaluation is left up to implementations, which is probably the
major reason for it being unspecified, although that does allow the
possibility of parallel implementations.  Most implementations do fix an
order of evaluation, although it's not necessarily left-to-right.  In
standard Scheme, if you want left-to-right evaluation, you have to use a
construct that guarantees that.

Anton
From: Adam Warner
Subject: Re: Scheme closures
Date: 
Message-ID: <pan.2004.04.17.12.48.39.552149@consulting.net.nz>
> For Common Lispers:
> `define' appears to no longer create globally accessible definitions in
> the three implementations I have tested (Kawa, Bigloo and SISC) when it's
> not a top-level form.

The above is misleading. Here are the actual outcomes of evaluating
(let ((state 0)) (define (inc) (begin (set! state (+ state 1)) state))):

Kawa:
(inc) => gnu.mapping.UnboundSymbol: Unbound symbol inc

Bigloo:
(inc) => Unbound variable -- state

SISC:
Error: no expressions in body
(lambda (state) (define (inc) (begin (set! state (+ state 1)) state)))

So SISC can't evaluate the form, Bigloo can find the definition but can't
locate the state variable and Kawa can't locate `inc' itself.

To fix the above it appears we need a helper function:

(define (state-helper)
  (let ((state 0))
    (lambda ()
      (begin (set! state (+ state 1))
             state))))

(define inc (state-helper))

It gets more complicated when the helper function has to return different
functions for different parts of the API (inc, dec and reset in the
original post).

Please correct me if I'm wrong: I believe the begin verbosity is necessary
to force a sane order of evaluation as I created a side effect without the
benefit of set! implicitly returning the result of the assignment.

I'm beginning to appreciate that the main reason for exclamation naming
is to shout to the programmer to be careful because the language doesn't
provide a default order of evaluation (perhaps to permit parallel
evaluation of arguments as the default, which could be a performance
benefit in some architectures).

Regards,
Adam
From: =?UTF-8?B?SmVucyBBeGVsIFPDuGdhYXJk?=
Subject: Re: Scheme closures
Date: 
Message-ID: <40813eab$0$203$edfadb0f@dread11.news.tele.dk>
Adam Warner wrote:

>>For Common Lispers:
>>`define' appears to no longer create globally accessible definitions in
>>the three implementations I have tested (Kawa, Bigloo and SISC) when it's
>>not a top-level form.

> The above is misleading. Here are the actual outcomes of evaluating
> (let ((state 0)) 
 >   (define (inc)
 >      (begin
 >        (set! state (+ state 1))
 >        state)))

The problem is that the above snippet is not legal Scheme.
If you try it in DrScheme you get this error message:

     begin (possibly implicit): no expression after a sequence of internal definitions in:
       ((define (inc) (begin (set! state (+ state 1)) state)))

The LET expression expands (at least conceptually) into a lambda expression.
The body of a lambda expression (which have an implicit begin) has this syntax:

   <body> -> <definition>* <expression>

To get you example running you must therefore add an expression after
the definition of INC. E.g.

 >  (let ((state 0))
      (define (inc)
        (begin
          (set! state (+ state 1))
          state))
      inc)

#<procedure:inc>

 >  (define foo (let ((state 0))
                  (define (inc)
                    (begin
                      (set! state (+ state 1))
                      state))
                  inc))
 > (foo)
1
 > (foo)
2


The question was however how to define several definitions sharing state.

There are several possibilities:

1. Using define-values (not in R5RS)

   (define-values (inc dec reset)
       (let ([state 0])
         (define (inc)  (set! state (+ state 1)) state)
         (define (dec)  (set! state (- state 1)) state)
         (define (reset)(set! state 0)           state)

         (values inc dec reset)))

2. Using a module system

   (module foo mzscheme
       (provide inc dec reset)

       (define state 0)
       (define (inc)  (set! state (+ state 1)) state)
       (define (dec)  (set! state (- state 1)) state)
       (define (reset)(set! state 0)           state))

3. Using temporary definitions (R5RS)

   (define inc   'uninitialized)
   (define dec   'uninitialized)
   (define reset 'uninitialized)
   (let ([state 0])
     (define (internal-inc)  (set! state (+ state 1)) state)
     (define (internal-dec)  (set! state (- state 1)) state)
     (define (internal-reset)(set! state 0)           state)
     (set! inc   internal-inc)
     (set! dec   internal-inc)
     (set! reset internal-reset))

Of course the last solution is what the first solution
expands into.

-- 
Jens Axel Søgaard
From: Kalle Olavi Niemitalo
Subject: Re: Scheme closures
Date: 
Message-ID: <878yguoht7.fsf@Astalo.kon.iki.fi>
Adam Warner <······@consulting.net.nz> writes:

> Please correct me if I'm wrong: I believe the begin verbosity is necessary
> to force a sane order of evaluation as I created a side effect without the
> benefit of set! implicitly returning the result of the assignment.

R5RS section 4.1.4 (Procedures) specifies that "the expressions
in the body of the lambda expression will be evaluated
sequentially".  This differs from 4.1.3 (Procedure calls) where
"operand expressions are evaluated (in an unspecified order)".