Path: utzoo!utgpu!news-server.csri.toronto.edu!mailrus!cs.utexas.edu!tut.cis.ohio-state.edu!usenet.ins.cwru.edu!eagle!amelia!eos!shelby!neon!max From: max@Neon.Stanford.EDU (Max Hailperin) Newsgroups: comp.lang.scheme Subject: Re: Non-local variables Message-ID: <1990May9.222152.27950@Neon.Stanford.EDU> Date: 9 May 90 22:21:52 GMT References: <9005081621.AA13048@mtecv2.mty.itesm.mx> <1990May8.205719.2014@sun.soe.clarkson.edu> <7478@accuvax.nwu.edu> Organization: Computer Science Department, Stanford University Lines: 63 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.