Catch up on stories from the past week (and beyond) at the Slashdot story archive

 



Forgot your password?
typodupeerror
×

Draft Scheme Standard R6RS Released 235

Watson Ladd writes, "The new version of the official Scheme standard has been released as a draft (PDF)." From the draft: "[This] report gives a defining description of the programming language Scheme. Scheme is a statically scoped and properly tail-recursive dialect of the Lisp programming language invented by Guy Lewis Steele Jr. and Gerald Jay Sussman. It was designed to have an exceptionally clear and simple semantics and few different ways to form expressions. A wide variety of programming paradigms, including imperative, functional, and message passing styles, find convenient expression in Scheme."
This discussion has been archived. No new comments can be posted.

Draft Scheme Standard R6RS Released

Comments Filter:
  • Re:Qs (Score:3, Interesting)

    by RAMMS+EIN ( 578166 ) on Sunday September 17, 2006 @03:42PM (#16125776) Homepage Journal
    ``What about a web application?''

    Scheme's first-class continuations [wikipedia.org] are actually a very good match for web programming, where a user can re-submit an old form at any time. Basically, with languages that lack call/cc, you will have to break up your application in little pieces to account for this, whereas call/cc allows you to structure your application like a regular one, and the language implementation will deal with the issues.

    When it comes to practicality, it all depends on the implementation. The Scheme report is (deliberately) very minimal, and you can't write many Real World programs using only standard Scheme. However, implementations often provide features and libraries that make Scheme practical for real projects, to some extent.

    ``Is it more or less powerful than, say, C++, Java, or Python?''

    It depends what you mean by "powerful". In the programming language community, the answer would likely either be "Scheme is more powerful", because its constructs are very flexible (e.g. it has first-class functions and continuations, which the languages you mention lack or only have to a limited extent), or "No", because all these languages are Turing-complete and thus can do everything the others can.

    However, outside the programming language community, the question probably refers not just to the language, but also to the libraries, and there Scheme could reasonably be said to lose out to at least Java. On the other hand, there are Scheme implementations that can call Java code, and thus access everything that is available for Java...
  • by brilinux ( 255400 ) on Sunday September 17, 2006 @03:56PM (#16125853) Journal
    While we are on this bit, I would recommend an ML, either SML [standardml.org] or OCaml [inria.fr], perhaps even in place of Haskell [haskell.org] (Haskell's syntax can be easily argued to be either better than or worse than ML's, and anything you can so in Haskell (including type-classes and lazyness) can be done in ML, so while I do use Haskell, I generally recommend one of the MLs as a well-typed, type-inferring functional language to know (OCaml if they are more systems/applications oriented, and SML if they are more theory oriented or just curious).
  • by Bluesman ( 104513 ) on Sunday September 17, 2006 @06:15PM (#16126415) Homepage
    This always comes up, but if you're at all interested in programming languages, here's why you should learn Scheme.

    A few years ago I was doing a project that involved parsing the intermediate code that GCC generated while compiling a C program. Doing a bit of research I found out that one of GCC's intermediate stages was a language called RTL (register transfer language). To my surprise, RTL looked something like this:

    (set (reg:0) (mem:blah blah))

    But wait, I thought -- that looks like Lisp. Come to find out RTL was based on lisp s-expressions.

    It was then I realized what the Big Deal with Lisp was - it has no syntax at all, and programs written in this parenthetical form are trivially converted into a parse tree. In fact, if you've ever written a simple interpreter or compiler, odds are good you'd use a list-like structure to store the parsed code.

    The reason Lisp and Scheme are so "powerful" is that you, as a programmer, have direct access to the program's parse tree at all times. (You can even alter the parse tree at compile time with macros, which is really modifying the compiler to suit your program.)

    But really, the best way to learn why Scheme or Lisp are so great is to implement them. Writing a Scheme to assembly compiler will give you an incredibly deep understanding as to how compilers and programming languages in general work.

    If you were to try to write a compiler for any other language, you'd probably spend most of your time on the lexer and parser. With Lisp or Scheme, the program, as written, is already almost fully parsed for you. Once you understand that, you'll realize why it's so cool.

  • Re:an oxymoron (Score:5, Interesting)

    by RAMMS+EIN ( 578166 ) on Sunday September 17, 2006 @06:39PM (#16126559) Homepage Journal
    ``"properly tail recursive" is an oxymoron. Tail recursion is not proper. Decent programmers use loop constructs for looping.''

    That's highly debatable. I would agree that when you want to express the concept of a loop, it's best to use a looping construct, but other people would disagree. Also, tail calls are more general than loops; for example, they also work for mutually recursive functions.

    Which is more elegant?

    int gcd(int a, int b) {
        return (b == 0) ? a : gcd(b, a % b);
    }

    or

    int gcd(int a, int b) {
        int t;
        while (b != 0) {
            t = b;
            b = a % b;
            a = t;
        }
        return a;
    }

    ``Your problem is that Scheme can't do that.''

    That depends on what you mean by "Scheme can't do that". It's entirely possible to implement looping constructs in Scheme, and several people have done so. Scheme can't do looping in the same sense that C can't compute factorials.

    ``When all you have is a hammer, everything looks like a nail.''

    Except that, in Scheme, you can make your own tools on a much more fundamental level than in many other languages. Thanks to tail call optimization, you can _implement_ looping constructs, even though the language doesn't provide them.

    ``Needless recursion makes your code more convoluted and less readable.''

    I think the example I gave earlier illustrates that, sometimes, recursion leads to less convoluted, more readable programs. The right tool for the job, ey? In a language that isn't properly tail recursive, the recursive gcd would be a bad idea because the recursion would eat memory, but in Scheme it's no problem.

    ``It's amazing how people can claim a deficiency as some kind of advantage. You just keep smoking...''

    I'm not claiming a deficiency as an advantage. I'm claiming tail call optimization is a nice features to have. There is no deficiency here.

    You could argue that the lack of looping constructs is a deficiency. However, the lack of looping constructs (1) is not at all implied by the language being properly tail recursive, (2) is easily remedied, and (3) actually has been remedied in many implementations.

    And no, I don't smoke, though I do live in the Netherlands.
  • Re:Qs (Score:3, Interesting)

    by RAMMS+EIN ( 578166 ) on Sunday September 17, 2006 @06:43PM (#16126580) Homepage Journal
    ``Languages without extensive first/third parties libraries are useless.''

    I won't argue this point further. I've already stated that languages without _extensive_ libraries can still be useful in specific domains. I still stand by that view.

    ``And languages like Scheme and Lisp are particularly crippled because they don't even have a standard extension mechanism.''

    Huh? The package system is a standard feature of Common Lisp. R6RS may standardize a module system for Scheme (although this is not certain yet); in the absence of that there is SLIB, which provides a de-facto standard mechanism.
  • Re:Qs (Score:3, Interesting)

    by smallpaul ( 65919 ) <paul @ p r e s c o d . net> on Sunday September 17, 2006 @08:47PM (#16127254)
    Given the fact that Guile is more than just Scheme and that Scheme has very little traction as a scripting language, Guile is essentially "yet another scripting language" in competition with Python, Ruby and the rest. At one point there was a pipe dream that other languages would be compiled to Guile but that never materialized. In retrospect, Guile was a huge mistake for the FSF. Despite their long-term investment in Guile, Python is more popular for programming Gnome than Guile is. If the translation concept had worked then Guile might have been a reasonable project. But as your post demonstrates, since development actually began, Guile has essentially been just another Scheme implementation.
  • no it doesn't (Score:3, Interesting)

    by r00t ( 33219 ) on Monday September 18, 2006 @12:30AM (#16127901) Journal
    It's time you looked at the output from a modern C compiler. I compiled the example for PowerPC using gcc 4.1 and got the assembly shown below. There is no recursion. There isn't even any memory access; everything is done in registers. (FYI, "blr" is the PowerPC instruction for "return")

    gcd:
                    cmpwi 0,4,0
                    bne 0,.L7
                    blr .p2align 4,,15 .L9:
                    mr 4,0 .L7:
                    divw 0,3,4
                    mullw 0,0,4
                    subf 0,0,3
                    mr 3,4
                    cmpwi 7,0,0
                    bne 7,.L9
                    mr 3,4
                    blr
  • by RAMMS+EIN ( 578166 ) on Monday September 18, 2006 @07:10AM (#16128821) Homepage Journal
    Short and simple explanation of continuations:

    A continuation is "the part of the program that hasn't been executed yet". If your code is

    (foo)
    (bar)
    (baz)

    and you've just executed (foo), the continuation is (bar) (baz).

    In Scheme, continuations are first-class values, which means they can be stored in variables, returned from functions, passed as arguments, etc.

    There is a single way to create continuations, namely through the call-with-current-continuation form (often abbreviated call/cc). You pass call/cc a function that takes one argument, and call/cc will call that function, passing it the current continuation as an argument. E.g., in

    (foo)
    (call/cc fun)
    (bar)
    (baz)

    fun will be called with a continuation representing (foo) (bar) as an argument.

    The continuation itself is a function that takes one argument, and calling that function will have the effect of returning from the call/cc that created it, with the value you pass to the continuation as a return value. E.g.

    (display (call/cc (lambda (cont) (cont 42))))

    will display 42, because that's the value you passed to the continuation.

    Now, things get _really_ interesting once you don't immediately invoke the continuation, but you store it in a variable for later use. E.g.

    (define cont #f)
    (call/cc (lambda (c) (set! cont c)))
    (foo)

    Now, cont is set to the continuation that, when invoked, will have the effect or returning from the call/cc form (i.e. (foo) will be the next form executed). The great power of Scheme's continuations is that this cont can be invoked any number of times, just like a normal function.

    What is it actually useful for? Well, it's definitely not something you use all the time. But you could use it to implement threads, for example:

    (define *threads* '())

    (define (schedule-thread thread)
            (set! *threads* (append *threads* (list thread))))

    (define (run-next-thread)
            (if (not (null? *threads*))
                        (let ((thread (car *threads*))
                                  (set! *threads* (cdr *threads*))
                                  (thread))))

    (define (make-thread thunk)
            (schedule-thread thunk)
            (yield))

    (define (yield)
            (call-with-current-continuation
                    (lambda (cont)
                            (schedule-thread (lambda () (cont #t)))
                            (run-next-thread))))

    Now, you can create a new thread by saying

    (make-thread (lambda ()
            ; your thread's code goes here
            ))

    and a thread can give up its timeslice by calling (yield).

    No time to check the code now, I have to go to a meeting.
  • Re:142 page PDF... (Score:3, Interesting)

    by John Nowak ( 872479 ) on Monday September 18, 2006 @08:42AM (#16129169)
    For one, I'm not sure unicode should be mandatory. I believe it should be described as a recommended component, but not necessary to call your language R6RS-compliant. Would I use a Scheme without unicode support? No, but for some applications and on some systems it isn't necessary. It is great to standardize on an interface, so all that do implement it (and most will) will do it compatibly, but it shouldn't be mandatory. Other things that should probably be recommended by not required are exceptions and the hygienic macro system (although R5RS was no better on this point). I'm less sure about the macro system being recommended instead of required actually. Section 7 should be strictly optional. It already is in a way, but this should be more explicit. The I/O portion of the library is huge -- It does a lot, and is quite flexible. That's great, but it is a rather onerous implementation requirement, and should be recommended, not required... and maybe even broken up into two pieces. Finally, I'm not sure I agree with keeping mutable pairs (set-car!, set-cdr!), but again this is no different from R5RS. The rest of my things are trivial... 'when' and 'unless' aren't needed. Ultimately, anything that makes R6RS significantly harder to implement should be moved from "required" to "recommended". R6RS-compatible scheme can then clearly say which of the five or so "recommended" groups of functionality they suppose; In reality, probably most will support all five, but for some Schemes it just doesn't make sense to do so.

One man's constant is another man's variable. -- A.J. Perlis

Working...