[plt-dev] I love Haskell (not an April Fools Joke!), feature request for 'for'

From: Matthias Felleisen (matthias at ccs.neu.edu)
Date: Wed Apr 1 10:51:31 EDT 2009

Please read

  http://programmingpraxis.wordpress.com/2009/03/31/rail-fence-cipher/

and compare the Scheme code with the Haskell code. How can anyone in  
his sound mind prefer Scheme over Haskell after reading this post?

So let's refine this statement. Here are my comments:

1. The first impression of this Haskell style is a throw back to  
Backus's "variable free" programming. It's almost all combinators,  
difficult to read and comprehend.

2. The second look suggests that it is more readable than the old  
Backus experience would suggest. And if you don't have FL experiences  
or don't even know what this is, the concise mix of combinators and  
variables makes this look nice.

3. Once you understand 'waves'
> waves :: Int -> String -> [Int]
> waves n = map snd . sort . zip (cycle $ [1..n] ++ [n-1,n-2..2]) .  
> zipWith const [0..]

you see that the poster has chosen a "Fortran" design. Instead of  
traversing the list in an up and down motion, the 'waves' function  
plays "indexing games." That is a turn-off.

4. The next thing you get out of 'waves' is that it is the only use  
of laziness in the whole program. It zips and zaps over "infinite"  
lists but the finite string, eh, list of chars, delimits the use of  
laziness. Neat.

5. The final insight that I took away from this code inspection is  
that strings as list of chars is a neat idea because you almost  
always want to traverse the string in some sequential order. Of  
course, once you discover that for/xyz treats strings as sequences,  
you're fine in PLT Scheme.

;; ---

I have posted a response that demonstrates how point 5 can be  
reversed for a language like PLT Scheme. (Oh and thanks for allowing  
'append' as a constructor in shared.) So here we go:

> (define (fence s n)
>   (define is (shared ((x (append (range 1 n) (range (- n 1) 2) x)))  
> x))
>   (define wv (for/list ((c s)) (begin0 (list c (car is)) (set! is  
> (cdr is)))))
>   (map first (sort2 wv)))


These four lines demonstrate how a locally delimited use of mutation  
achieves the same purpose.

FEATURE REQUEST: could for just treat something like is as a  
sequence? I have seen this trick I just used time and again over my  
Scheme career and we shouldn't have to expose the set! statement at  
all. (BTW, I don't think I can use the built-ins to turn this cyclic  
form of data into a 'sequence'.)

-- Matthias


Posted on the dev mailing list.