views:

517

answers:

6

These two languages are very different. They're each well-suited to their own particular tasks. What tasks are easy to do in Scheme, yet are hard / require lots of ugly code to do in Java? Another way of putting it: what is Scheme better at?

If you can think of things that Java is better at, see this question.

+8  A: 

Function objects

Scheme has first-class functions, in the form of lambdas. Java does not, so in order to pass around functions or define anonymous inline functions, you need to define a new class or interface and then subclass it. Even with anonymous subclasses, it's still a bit of a pain:

# Scheme: sort in descending order with a custom comparator
(sort '(3 1 4 2) (lambda (x y) (> x y)))  # close ' to un-confuse source colorizer

// Java: call a sort function with a custom comparator
Integer[] array = new Integer[]{3, 1, 4, 2};
Arrays.sort(array, new Comparator<Integer>()
    {
        public int compare(Integer i1, Integer i2){
        {
            return i1 > i2;
        }
    });
Adam Rosenfield
And the other neat thing about Scheme, being a Lisp-1, is that you could just write the above sort as (sort '(3 1 4 2) >) and be done. :-)
Chris Jester-Young
Chris: That has nothing to do with it being a Lisp-1. In CL, it'd normally be written (sort '(3 1 4 2) #'>).
Ken
+7  A: 

I suppose anything that had to do with continuations. A good example is On Lisp style nondeterminism. Basically you provide several different possible choices to the choice function. If at any point you are able to determine that the choice made is incorrect, you call fail and another choice is made. What's great about this is that it restores the state of the stack at the exact time the choice is made, so you don't have to worry about backtracking at all - the end result is a program that chooses the correct choice every time seemingly by magic.

This would be quite difficult to implement in Java as seamlessly as Scheme because as far as I know Java does not provide any facilities for saving and restoring its runtime stack. In fact, I'm not sure how you'd do this at all in Java save for manually keeping your own stack at every step.

edit: Here's an implementation in Scheme:

(define *paths* ())

(define (choose choices)
  (call-with-current-continuation
   (lambda (cc)
     (set! *paths*
           (append *paths*
                   (map (lambda (choice)
                          (lambda () (cc choice)))
                        choices)))
     (fail))))

(define (fail)
  (if (null? *paths*) 'fail
      (let ((p1 (car *paths*)))
        (set! *paths* (cdr *paths*))
        (p1))))
Kyle Cronin
Exceptions are one possible way to jump up the stack... not that I'm recommending using exceptions as flow control...
Jimmy
oh. someone thought of this a long time ago. http://www.hpl.hp.com/personal/Mark_Lillibridge/Unchecked_Exceptions/hosc99.pdf
Jimmy
Yes, unchecked exceptions cannot be implemented with call/cc, but I think that the reverse is also true (though there is no formal proof I know of).
Kyle Cronin
+5  A: 

Writing a Scheme interpreter

Yoni Roit
We need a poll for How many Stack Overflow members have written a scheme interpreter in scheme.
Alex B
Are we talking "proof-of-concept" interpreter or the real thing, fully optimized?
Arkadiy
Lisp is close enough, right?
Bill the Lizard
simple enough: (define (interp expr) (eval expr)).
Claudiu
+2  A: 

Tail call optimization, Java does not even support it in the JVM's bytecode (which is a roadblock for Clojure with respect to the goal to bring Lisp power to the JVM, by the way).

Svante
Isn't that a pure question of the implementation and not of the language ? I mean: is it explicitely ruled out in the VM spec to "NOT do til call optimization" ? I would not think so. Then, future VMs might support it...(its probably not much of a issue, as Java progs tend to less recursive anyway)
blabla999
+3  A: 

Integrating new functionality as if it were syntax - here's parallel OR (excerpted from here):

(define-syntax por
  (syntax-rules ()
    ((_ x ...)
     (first-true
       (list (make-engine (lambda () x)) ...)))))

(define first-true
  (lambda (engs)
    (if (null? engs)
        #f
        ((car engs) 1
          (lambda (ticks value)
            (or value (first-true (cdr engs))))
          (lambda (eng)
            (first-true
              (append (cdr engs) (list eng))))))))
plinth
+1  A: 

Well, being in the refactoring business myself:

handling code (analyse, rewrite, macro-expand, automatic refactoring and all the rest) is very hard in Java. Having code-as-data around (or the same format for it) as in Lisp definitely helps a lot with all this. Actually, not having ANY syntax is pure fun when doing this.

This of course includes "self modifying code", which sounds bad first, but is just another phrase for "learning".

regards

PS: so its not a surprise, that many language processing systems use Lisp or a Lisp-like representation internally...

blabla999