dorai@titan.rice.edu (Dorai Sitaram) (06/19/89)
The recent discussion of "unspecified" values reveals that Scheme is not as syntactically uniform as it is claimed to be. Some Scheme syntactic forms return meaningful values, others don't: the former are "expressions" and the latter "commands". "Commands" are usually used to represent side-effects, e.g., assignment in the form of set!. In an expression-oriented language, a "command" is awkwardly "expressed" by an expression returning an arbitrary "unspecified" value. Perhaps, SET! is not the ideal side-effecting construct for an expression-oriented language. Felleisen and Friedman [1] propose a side-effecting construct called a SIGMA-capability. This looks just like a LAMBDA-expression, but whereas LAMBDA introduces new bound variables, SIGMA modifies the binding of existing lexical variables. In other words, on applying a SIGMA-capability to arguments, the variables corresponding to the SIGMA-parameters are side-effected. Problems about "unspecified" return values disappear. The application of a SIGMA-capability side-effects the SIGMA-parameters and returns the result of evaluating the SIGMA-body (the parallel being the application of a LAMBDA-expression). In addition, SIGMA gives a very natural method for parallel assignment, since the arguments to a SIGMA-capability are all evaluated before the application performs the side-effects. We can retrieve the old SET! from SIGMA as follows: (set! x a) == ((sigma (x) <what-now>) a) where <what-now> is the "unspecified" value of your choice. Thus, there is no dependence on a system-chosen unspecified value. Even better, we need not fall back on a command with its necessarily arbitrary choice of unspecified return value. We can define a _generalized_ SET! in terms of SIGMA that is more along the lines of LET in terms of LAMBDA: (set! ([x a] ...) e ...) == ((sigma (x ...) e ...) a ...) The upshot of all this is that while we have side-effects, we still have a syntactically uniform language. --dorai [1] Felleisen & Friedman, A calculus for assigments ..., POPL 1987, 314 - 325. ps: In terms of SET!, SIGMA's effect is as follows: (sigma (x ...) e ...) == (lambda (x^ ...) (set! x x^) ... e ...) where x^ ... are new variables, used only to show what's going on. A native implementation of SIGMA is simply got by mimicking LAMBDA, except for the following: where LAMBDA has extend-environment, SIGMA has update-environment. ------------------------------------------------------------------------------- It may be that the gulfs will wash us down; It may be we shall touch the Happy Isles. -------------------------------------------------------------------------------
Alan@REAGAN.AI.MIT.EDU (Alan Bawden) (06/20/89)
Date: 18 Jun 89 23:17:50 GMT From: Dorai Sitaram <titan!dorai@rice.edu> ... Perhaps, SET! is not the ideal side-effecting construct for an expression-oriented language. Felleisen and Friedman [1] propose a side-effecting construct called a SIGMA-capability. This looks just like a LAMBDA-expression, but whereas LAMBDA introduces new bound variables, SIGMA modifies the binding of existing lexical variables. In other words, on applying a SIGMA-capability to arguments, the variables corresponding to the SIGMA-parameters are side-effected. Problems about "unspecified" return values disappear.... I'm having a hard time applying this idea to the NEWLINE procedure -- which is specified in R3RS to return an unspecified value. Is the idea to introduce a side-effecting construct that looks like LAMBDA, but performs a newline when applied to an output port? ((NULINE () <body>) (CURRENT-OUTPUT-PORT))
dorai@titan.rice.edu (Dorai Sitaram) (06/20/89)
In response to my posting suggesting SIGMA and SIGMA-based SET! (a la LAMBDA and LET) instead of traditional SET!, I received email which basically states that SIGMA violates the orthogonality of Scheme constructs, viz., SIGMA does "two" things: it "side-effects the environment" _and_ "returns a value". In other words, it is felt that any side-effecting construct should just perform the job it was made for, viz., side-effecting, and not do something else too, like returning values. SIGMA allegedly "fails" in the latter detail. But then, we should remember that our goal was to preserve the syntactic uniformity of Scheme. Scheme is (and very deliberately too) an expression-oriented language. In spite of our best efforts, traditional SET! does return a value. Given that whichever primitive side-effecting construct we pick will inevitably return a value, which construct should we choose? I would prefer one where the returned value is not only meaningful but _necessary_. The value that SET! returns is totally arbitrary. What SIGMA returns is crucial to its correctness. Recall that SIGMA does not perform a side-effect immediately; it returns a closure, which needs to be applied to value(s) before any side-effecting can take place. (Incidentally, LAMBDA, the cornerstone of Scheme, also has "two" purposes _if_ we take "returning a value" as a distinguishing property in assessing the orthogonality of Scheme. LAMBDA introduces fresh lexical variables _and_ returns a closure. I don't think anyone seriously wants to reject LAMBDA for lack of orthogonality!) --dorai ps: Other questions: * Why was SIGMA created? Felleisen & Friedman (POPL 1987) devised a calculus for a lambda-calculus-like language with assignments. SIGMA kind of falls out naturally. * Why is it "superior" to SET!? "Superior" is a tough word. However, I did mention the naturalness of parallel assignment in my orig. posting. Using SIGMA-capabilities as arguments to control-reifiers like call/cc is also delicious. * There is also another reason why the SIGMA-model of assignment, viz., (sigma (x ...) e ...) or (set! ([x a] ...) e ...), makes sense. In any program, one always performs some operation _after_ the side-effecting (of variable-bindings(see + below)) has been done. If the side-effecting were the last thing done in the program, there is no way it could be detected, hence no way it could be meaningful. Thus the application of a SIGMA-capability returns the value of the body of the SIGMA-expression, something (and such a something invariably exists) that is evaluated _after_ the side-effecting has taken place. +{PRINTF is the only side-effect which can meaningfully be the last thing in a program.} * [Alan Bawden's question about NEWLINE...] How do you deal with the other "commands" of Scheme? (E.g., READ, SET-CAR!, PRINTF.) Easier than SET!. SIGMA-like counterparts need _not_ be made for these, as that would lead to a plethora of special forms (as opposed to 'procedures'). All of these "command" procedures now take an additional argument for "the body" (thunk actually) whose value is returned. {* SIGMA of course is necessarily a special form (i.e., it cannot be substituted by a procedure as for READ, SET-CAR!, PRINTF above). The reason is variable names can't be passed as procedure arguments.} --dorai ------------------------------------------------------------------------------- It may be that the gulfs will wash us down; It may be we shall touch the Happy Isles. -------------------------------------------------------------------------------
manis@grads.cs.ubc.ca (Vincent Manis) (06/20/89)
I've bitten my tongue on this, but I really can't see the point of #!unspecified. Perhaps it would be nice in theory (especially if (define loop (lambda (x) (loop (1+ x)))) returned #!unspecified, which would then be equivalent to `bottom' in the Scott-Strachey world), but it seems pointless. One can argue, as somebody has, that the existing behaviour distinguishes between expressions and commands; however, Scheme already has a strong notion of side effects (unlike, say, Miranda), and whether a side-effecting procedure yields (), #f, an unspecified result, or #!unspecified really makes no difference to anybody, except in one place, which I'll mention in a moment. I regard `returns an unspecified result' as an injunction not to place a call to a procedure in a value-returning position, e.g., the last step in a lambda or begin. If I wrote a Scheme compiler, fascist that I am, I would probably generate an error message for such a usage. Going to the trouble to develop a calculus of unspecified values strikes me as almost as silly as some of the things I did when I was involved in writing an Algol 68 compiler. The one place where #!unspecified makes some sense is in Read-Eval-Print loops. One can use #!unspecified as a trigger that the result is not to be printed. But then one does not need to change the language: PC Scheme, for example, has *the-non-printing-object*. If it ain't broke, don't fix it. ____________ Vincent Manis | manis@cs.ubc.ca ___ \ _____ The Invisible City of Kitezh | manis@cs.ubc.cdn ____ \ ____ Department of Computer Science | manis%cs.ubc@relay.cs.net ___ /\ ___ University of British Columbia | uunet!ubc-cs!manis __ / \ __ Vancouver, BC, Canada V6T 1W5 | (604) 228-2394 _ / __ \ _ "Theoretical computer science helps me convince people that ____________ my indecisiveness is really Nondeterminism, which sounds like a much more positive characteristic." -- a student
pierce@lanai.cs.ucla.edu (Brad Pierce) (06/20/89)
In article <2281@ubc-cs.UUCP> manis@grads.cs.ubc.ca (Vincent Manis) writes: << Stuff omitted. >> >I regard `returns an unspecified result' as an injunction not to place >a call to a procedure in a value-returning position, e.g., the last >step in a lambda or begin. If I wrote a Scheme compiler, fascist that >I am, I would probably generate an error message for such a usage. << Stuff omitted. >> This is really not a criticsm, only a question. How does one go about building a compiler that can detect when a procedure is going to return an unspecified result, especially those which sometime return unspecified values and sometimes return specified values? For example, in an object-oriented program most objects will respond to some messages with actual information and to some messages with unspecified values. On the face of it, it sounds very difficult to determine such things syntactically. And wouldn't runtime checking amount to introducing the unspecified object? It doesn't seem right to me that a user should have to know the full specifications of an object before being able to confidently send messages to that object. It would seem preferable to me to be able to check whether the result returned has any information content. Also in this discussion I haven't heard any mention of my suggestion to see the unspecified object as being analogous to NaN in the IEEE numeric standard. Is that a bad analogy? Is NaN a bad idea? Just wondering. -- Brad
ALAN@ML.AI.MIT.EDU (Alan Bawden) (06/21/89)
Date: 19 Jun 89 23:24:37 GMT From: Dorai Sitaram <titan!dorai@rice.edu> How do you deal with the other "commands" of Scheme? (E.g., READ, SET-CAR!, PRINTF.) Easier than SET!. SIGMA-like counterparts need _not_ be made for these, as that would lead to a plethora of special forms (as opposed to 'procedures'). All of these "command" procedures now take an additional argument for "the body" (thunk actually) whose value is returned. So we would write (NEWLINE (CURRENT-OUTPUT-PORT) (LAMBDA () (WRITE X (CURRENT-OUTPUT-PORT) (LAMBDA () X)))) to newline, and then output and return the current value of X. (Or perhaps the continuations are passed as the first argument -- it doesn't matter in the current discussion.) Now it would seem to me that the most uniform way to include assignment in this scheme, is to have SET! take a continuation as well. So (SET! X (+ X 1) (LAMBDA () X)) would increment the value of X and return the new value. SET! is still a keyword, so this isn't -exactly- parallel with the side-effecting procedures. But I'll bet that once people start writing programs using this scheme, the thing that will impress them the most is that whenever they perform a side-effect they have to create an explicit continuation to wait for the side-effect to happen. And I'll bet they will be most comfortable if they have to make exactly the same kind of continuation for SET!. I'm currently working on a language where users really -must- control sequencing by explicitly using thunks, so I'm very interested in linguistic constructs that support this style. Actually, in my case its worse than in plain Scheme, because users must also exert control over when variables are -read- as well as written. Thus users have to write something like (LOOK! X (LAMBDA (VALUE) (SET! X (+ 1 VALUE) (LAMBDA () <whatever> )))) to increment the value of X, because if they wrote (SET! X (+ 1 X) (LAMBDA () <whatever> )) the occurrence of X in (+ 1 X) might be taken to refer to the value of X -after- the SET! happens (so that the value of X would become the fixed point of (lambda (n) (+ 1 n))!).
mkatz@SESAME.STANFORD.EDU (Morris Katz) (06/22/89)
At the R*RS meeting in Snowbird we discussed the possibility of adding some form of multiple values to Scheme and allowing continuations to accept multiple values. I wonder if the solution to the problem of what should be returned by side effecting procedures like SET! is to just have them return no values (i.e. a zero arity multiple value). As long as continuations can handle multiple values appropriately, it seems to me that this solution would have many, if not all, of the advantages of #!UNSPECIFIED without introducing many of the undesirable side effects. Morry Katz katz@polya.stanford.edu P.S. After the meeting at Snowbird, Guy Steele and I came to an agreement as to the correct of the two conflicting semantics for multiple values to continuations that we proposed. At that time, we believed that this solution would probably be acceptable to the great majority of the community. Is there interest in having the proposal written up for future consideration? I would be willing to strain my memory in an attempt to creat such a proposal if there is genuine interest.
chaynes@iuvax.cs.indiana.edu (Chris Haynes) (06/22/89)
From: mkatz@SESAME.STANFORD.EDU (Morris Katz) Newsgroups: comp.lang.scheme Date: 21 Jun 89 21:17:54 GMT ... P.S. After the meeting at Snowbird, Guy Steele and I came to an agreement as to the correct of the two conflicting semantics for multiple values to continuations that we proposed. At that time, we believed that this solution would probably be acceptable to the great majority of the community. Is there interest in having the proposal written up for future consideration? I would be willing to strain my memory in an attempt to creat such a proposal if there is genuine interest. I'm interested.
gateley@m2.csc.ti.com (John Gateley) (06/22/89)
In article <2281@ubc-cs.UUCP> manis@grads.cs.ubc.ca (Vincent Manis) writes: >Going to the trouble to develop a calculus of unspecified values >strikes me as almost as silly as some of the things I did when I was >involved in writing an Algol 68 compiler. ... >____________ Vincent Manis | manis@cs.ubc.ca ... Do you mean Matthias Felleisen's calculus for Scheme? It is neither a calculus of unspecified values nor silly. It is a better theoretical basis for Scheme than the lambda value calculus: it includes both set! style side effects and continuations in its equations. John gateley@m2.csc.ti.com
manis@grads.cs.ubc.ca (Vincent Manis) (06/23/89)
In article <81872@ti-csl.csc.ti.com> gateley@m2.UUCP (John Gateley) writes: >Do you mean Matthias Felleisen's calculus for Scheme? It is neither a >calculus of unspecified values nor silly. It is a better theoretical >basis for Scheme than the lambda value calculus: it includes both >set! style side effects and continuations in its equations. To clarify, let me say emphatically that I *don't* mean Felleisen's calculus. As John says, Felleisen's work is not at all silly. I was instead referring to the proposals for #!unspecified, which, is either the same as `bottom' in denotational semantics or it is not. In the former case, #!unspecified should be returned, also, in both a division by 0 and a non-terminating recursion. In the latter case, #!unspecified is somewhat pointless (set! could just as easily return `()), unless one has some reason for distinguishing the two. While I do not care for William of Ockham's metaphysics, there is much to say for his Razor. ____________ Vincent Manis | manis@cs.ubc.ca ___ \ _____ The Invisible City of Kitezh | manis@cs.ubc.cdn ____ \ ____ Department of Computer Science | manis%cs.ubc@relay.cs.net ___ /\ ___ University of British Columbia | uunet!ubc-cs!manis __ / \ __ Vancouver, BC, Canada V6T 1W5 | (604) 228-2394 _ / __ \ _ "Theoretical computer science helps me convince people that ____________ my indecisiveness is really Nondeterminism, which sounds like a much more positive characteristic." -- a student
dorai@titan.rice.edu (Dorai Sitaram) (06/26/89)
In article <2281@ubc-cs.UUCP> manis@grads.cs.ubc.ca (Vincent Manis) writes: >Going to the trouble to develop a calculus of unspecified values >strikes me as almost as silly as some of the things I did when I was >involved in writing an Algol 68 compiler. If this is in response to my posting(s) entitled "unspecified and set!" (and I'm not sure it is -- Vincent doesn't say), I request permission to shriek, "No! This is not what I meant!" ;-) I was drawing attention to side-effecting constructs in the literature (that they appeared in a calculus-definition is of secondary importance) that give all the "power" of current Schemes WITHOUT having to mess with (returning) unspecified values at all. I do, of course, concur with Vincent that having an unspecified object like #!unspecified is close to being the all-time great oxymoron of our troubled times (though he might not use the selfsame words ;-]). Second, the comparison that Vincent draws between "(#!)unspecified" and "bottom" is not correct. "Bottom" stands for divergence (non-termination) and occasionally, errors; "(#!)unspecified" is a stopgap value concocted to stand for a meaningless value returned in a TERMINATING computation. --dorai ------------------------------------------------------------------------------- It may be that the gulfs will wash us down; It may be we shall touch the Happy Isles. -------------------------------------------------------------------------------