Haskell is nicer than Scheme
I’m taking a class on DSLs this semester, and the first assignment was to write some trivial programs in Scheme. Haskell is so much prettier. I mean, just compare (lambda (x) (* x x)) to \x->x*x (the square function).
Then, of course, there’s the function to sum a list. In Scheme:
(define (sum lst)
(if (null? lst)
0
(+ (car lst) (sum (cdr lst)))))
Did you follow the closing parentheses? In Haskell, pattern matching makes this extremely convenient:
sum [] = 0 sum (x:xs) = x + sum xs
Then there are the benefits of lazy evaluation. In Scheme, to be efficient, map has to be written like: (stolen from guile’s srfi-1)
(define (map1 f ls)
(if (null? ls)
ls
(let ((ret (list (f (car ls)))))
(let lp ((ls (cdr ls)) (p ret)) ; tail pointer
(if (null? ls)
ret
(begin
(set-cdr! p (list (f (car ls))))
(lp (cdr ls) (cdr p))))))))
while in Haskell, it can be written naturally as
map f [] = [] map f (x:xs) = f x : map f xs
This has to do with lazy evaluation, since the remainder of the Haskell list isn’t evaluated until it is needed and so doesn’t require any extra stack space. It also allows us to map a function over an infinite list, which would run forever in Scheme. To be fair, lazy evaluation has its costs: if we actually need to evaluate the whole list, Haskell’s map will run slower than Scheme’s.
Some of my favorite uses of Haskell involve infinite lists:
fibonacci = 0 : 1 : zipWith (+) fibonacci (tail fibonacci) take 20 fibonacci == [0,1,1,2,3,5,8,13,21,34,55,89, 144,233,377,610,987,1597,2584,4181] — Using the Sieve of Eratosthenes sieve (p:ns) = p : sieve [n | n <- ns, n `mod` p /= 0] primes = sieve [2..] take 20 primes == [2,3,5,7,11,13,17,19,23,29,31,37, 41,43,47,53,59,61,67,71]
Of course, neither of these are possible in Scheme.
Recall the use of let in the definition of map: (let ((ret (list (f (car ls))))) …). In Haskell, we have syntax to avoid the excessive use of parentheses:
let ret = [f,head ls] in …
Scheme does have a few benefits. Because it is dynamically typed, you can apply a function to any number of arguments: (zip '(1 2 3) '(2 3 4) '(3 4 5) '(4 5 6)) == ((1 2 3 4) (2 3 4 5) (3 4 5 6)). In Haskell, you have to give the number of arguments explicitly: zip4 [1,2,3] [2,3,4] [3,4,5] [4,5,6] == [(1,2,3,4),(2,3,4,5),(3,4,5,6)]. On the other hand, all of my complaints (which I haven’t published yet) about dynamic typing still apply.
