jk0@image.soe.clarkson.edu (Jason Coughlin) (05/09/90)
Hi. I've got a short little example which creates a non-local variable to implement a simple little counter. In my implementation of Scheme, I create it like this: (let ([a 0]) (define counter (lambda () (set! a (+ a 1)) a ) ) ) PC-Scheme barfs on this complaining about an illegal letrec syntax. Both PC-Scheme and my Scheme allow the example in Dybvig's book, _The Scheme Programming Language_: (define counter (let ([a 0]) (lambda () (set! a (+ a 1)) a ) ) ) Am I missing something important here? -- Jason Coughlin ( jk0@sun.soe.clarkson.edu , jk0@clutx ) "Every jumbled pile of person has a thinking part that wonders what the part that isn't thinking isn't thinking of." -- They Might Be Giants "If you read the _TV Guide_, then there's no need for a TV." -- Lost Boys
krulwich@ils.nwu.edu (Bruce Krulwich) (05/10/90)
In article <1990May8.205719.2014@sun.soe.clarkson.edu>, jk0@image (Jason Coughlin) writes: > Hi. I've got a short little example which creates a non-local >variable to implement a simple little counter. In my implementation of >Scheme, I create it like this: > >(let ([a 0]) > (define counter > (lambda () > (set! a (+ a 1)) > a > ) > ) >) > > PC-Scheme barfs on this complaining about an illegal letrec syntax. I think that the problem is that DEFINE's that are not at the top-level are considered by Scheme (but not T or CL) to be local definitions like LETREC's. Probably the code you give above is transformed into a LET containing a body-less LETREC, which is illegal. This is an issue that has been discussed before. Basically, the treatment of internal DEFINE's as local definitions makes it impossible to have static locally-scoped variables that span across procedures. (Having static variables for one procedure can be achieved as you showed later in your message.) Having internal DEFINE's result in local definitions doesn't add any power, because they're identical in meaning to LETREC, but to some people this seems more semantically correct than simply having all DEFINE's result in top-level definitions. Of course, another issue for many people is that changing the meaning would make old code incorrect. Bruce Krulwich Institute for the Learning Sciences krulwich@ils.nwu.edu
max@Neon.Stanford.EDU (Max Hailperin) (05/10/90)
In article <7478@accuvax.nwu.edu> krulwich@ils.nwu.edu (Bruce Krulwich) writes: >In article <1990May8.205719.2014@sun.soe.clarkson.edu>, jk0@image (Jason >Coughlin) writes: ... >>(let ([a 0]) >> (define counter >> (lambda () >> (set! a (+ a 1)) >> a >> ) >> ) >> ... PC-Scheme barfs on this complaining about an illegal letrec syntax. >I think that the problem is that DEFINE's that are not at the top-level are >considered by Scheme (but not T or CL) to be local definitions like >LETREC's. Probably the code you give above is transformed into a LET >containing a body-less LETREC, which is illegal. Yes, this is what's wrong. However, the syntax error is in fact discernable without resorting to the explanation of the rewriting into a letrec (though you wouldn't understand then why the error message mentions letrec). The syntax for let says it takes a "body" which is defined as zero or more definitions followed by one or more expressions. Hence, the code above is illegal because there is no expression in the body of the let, just a definition. While I'm at it, I'd like to chip in my two cents on some of the other issues raised: >This is an issue that has been discussed before. Basically, the treatment >of internal DEFINE's as local definitions makes it impossible to have >static locally-scoped variables that span across procedures. ... This isn't true, though it requires what some consider an unaesthetic idiom. What you do is define the procedure names as some placeholder, e.g. #f, and then use set! within the appropriate lexical scope to mutate them to name the actual procedures, made with lambda. The main disadvantage of this idiom, from my perspective, is that it makes the procedure names mutable, which causes compilers and people alike to handle them gingerly. On the other hand, I don't know of any better alternative -- see the below. >Having internal DEFINE's result in local definitions >doesn't add any power, because they're identical in meaning to LETREC, Right, that's why R3RS makes them optional. On the other hand, while they don't add anything semantically, they can be nice syntactically by helping prevent your code from gradually drifting off the right edge of the page. >but >to some people this seems more semantically correct than simply having all >DEFINE's result in top-level definitions. Of course, another issue for >many people is that changing the meaning would make old code incorrect. The issue isn't "semantic correctness," but rather that we (yes, I am one of the "some people") don't accept the premise that there is a unique top-level. Real systems frequently have levels of varying degrees of top-ness, and it's hard to know just where the programmer intended a definition to be installed, if not the current scope. Aside from this, the right level for a procedure might not be a top-level at all, in any sense. Take the case of two procedures which need to share some private state and should themselves only be visible in a restricted part of the program. This works fine using the set! approach, but can't be handled by the define-is-always-top-level approach.
gintera@cpsc.ucalgary.ca (Andrew Ginter) (05/10/90)
In article <7478@accuvax.nwu.edu>, krulwich@ils.nwu.edu (Bruce Krulwich) writes: > This is an issue that has been discussed before. Basically, the treatment > of internal DEFINE's as local definitions makes it impossible to have > static locally-scoped variables that span across procedures. (Having > static variables for one procedure can be achieved as you showed later in > your message.) It seems to me that the variable "a" below is a locally scoped variable which spans procedures... (define dummy (let ((a 0)) (list (lambda () (set! a (+ 1 a)) a) (lambda () (set! a (- 1 a)) a)))) (define count-up (car dummy)) (define count-down (cadr dummy)) Andrew Ginter, 403-282-2984, gintera@CPSC.UCALGARY.CA, Ginter@UNCAMULT.BITNET