Hacker News new | past | comments | ask | show | jobs | submit login
Why I Like PLT Scheme (2004) (kuro5hin.org)
36 points by rw on March 16, 2009 | hide | past | favorite | 9 comments



The map definition that OP uses doesn't look like a pure tail-recursive one:

    ; map-kuro5hin : (X -> Y) * (listof X) -> (listof Y)
    ; http://www.kuro5hin.org/story/2004/3/17/93442/8657
    (define (map-kuro5hin func a-list)
      (cond
        [(null? a-list) null]
        [else (cons (func (car a-list)) (map-kuro5hin func (cdr a-list)))]))
In a simple substitution model it unwraps to:

    (define sq (lambda (x) (* x x)))
    (map-kuro5hin sq '(1 2 3))
    (cons (sq 1) (map-kuro5hin sq '(2 3)))
    (cons (sq 1) (cons (sq 2) (map-kuro5hin sq '(3))))
    (cons (sq 1) (cons (sq 2) (cons (sq 3) (map-kuro5hin sq '()))))
    (cons (sq 1) (cons (sq 2) (cons (sq 3) '())))
    (cons (sq 1) (cons (sq 2) '(9)))
    (cons (sq 1) '(4 9))
    '(1 4 9)
In this model it uses stack to store the result list. Of cause an actual Scheme implementation might perform the calculation without using stack.

Here's a pure tail-recursive variant:

    ; make external definition to allow unwrapping demonstration
    (define (map-iter func lst result)
      (if (null? lst) result
          (map-iter func (cdr lst) (cons (func (car lst)) result))))
    
    (define (map-tr func a-list)
      (map-iter func (reverse a-list) '()))
That translates to:

    (map-tr sq '(1 2 3))
    (map-iter sq (reverse '(1 2 3)) '())
    (map-iter sq '(3 2 1) '())
    (map-iter sq '(2 1) (cons (sq 3) '()))
    (map-iter sq '(1) (cons (sq 2) '(9)))
    (map-iter sq '() (cons (sq 1) '(4 9)))
    '(1 4 9)


I now think lisp variants like scheme, CL and arc allow you to write code that reflects how you think about the problem at hand, with much less boilerplate than C, C++ or Java. Performance is good enough, and the repl is a very effective RAD tool.

Ive heard the same about Python, ruby, ocaml, F#, Haskell etc. After years of C and C++, I just cant bring myself to use the 'end' keyword, which rules some of these out.

Im very impressed with plts mzscheme command shell. The docs are excellent and clever blog articles abound for scheme. It seems a good way to learn a lisp while getting real work done.

I do wish there was a #lang arc 'personality' to provide the Arc language from within plt itself - that would be my dream machine.


Since the PLT Scheme community is so helpful, you might consider diving into the language by immediately trying to build that Arc-flavored dialect. The source to everything is available - give it a shot!


your absolutely right.

I'm trying to avoid the temptation to play with language too much, while I build my startup app.

Theres so much cool stuff there.. Being interested in the language makes for much more pleasant hacking / prototyping experience. [Id lost this feeling with C++/java even ruby]

You can actually just get the basics and then learn in more depth as interest and time dictate.


There is truth to giving more thought in functional programming. Writing recursive functions requires thought especially when implementing tail recursion.


I tend to avoid explicit recursion. It's nearly as much to think about as the iterative loops you are trying to escape from.

Combinators like map, filter, foldl/foldr keep your mind free of clutter.


I suppose my point was that iterative loops didn't make you think very much and so sometimes you become careless as was the case with that Zune bug from January. Recursion keeps you on your toes and if you practice enough then you can manage so-called clutter well and still have room to think.


Perhaps I am too much into Scheme and FP in general. I have come to view iterative loops as special case of tail recursion, necessary because some languages do not support general proper tail recursion.

Iterative loops and explicit recursion make you think about stuff you'd rather not think about. For example if I want to apply a function on a number of items:

> for(int i=0;i<n;i++) > b[i]=f(a[i]);

plus managing the length of the array and creating the new array b in the first place.

With explicit recursion (in Haskell syntax):

> foo :: [a] -> [b] > foo [] = [] > foo (x:xs) = (f x: foo xs)

You no longer have to care about the length of the list or an index. But you still have to think about where you place the recursive descent and how to make it tail recursive.

And the same function with combinators:

> foo :: [a] -> [b] > foo = map f

Perhaps you will have to think a bit harder to write such a version, especially when you use the more advanced combinators like foldl/foldr, but reading is a pleasure.

Of course you also have to define the combinators somewhere --- but those definitions are way easier when they are not mirred in domain specific details.


yep.

well I don't avoid recursion per se, it can sometimes be very clean.

But I sure did notice the power of map-, fold-, reduce- style programming from playing with KDB+/K/Q [an apl derived terse language for handling stream/column data] and the lisps.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: