Hacker News new | past | comments | ask | show | jobs | submit login

> They broke the abstraction layers, mess up logic with implementation

your opinion is one i haven't seen before, do you care to elaborate?





The implementation of Clojure itself is not idiomatic nor is it intended it to be so. Most of the complexity in that example, for instance, is to deal with chunked lazy sequences. In user-land code, chunking of lazy sequences is pretty much a pure performance optimization that you don't have to worry about.

Granted, it's not a ideologue "turtles all the way down" LISP. But it isn't intended to be. If you want that, I advise you to find an old Lisp Machine and use that.


Your three line version is pretty much equivalent to this part of the Clojure version:

    (let [x (f (first s))]
        (if (nil? x)
            (keep f (rest s))
            (cons x (keep f (rest s)))))
The rest of it appears to be performance optimizations, that probably make sense for a key function in the core library likely to be commonly invoked.


There are some subtle differences, which makes the whole sense.

Classic version has a self-evident clarity and familiar shape of a recursive function, which utilizes TCO.

Perfection is achieved when there is nothing more to cut off, not when there is nothing more to pile up.)


Is the classic one actually going to be able to leverage tail-call elimination? Obviously it could be refactored to make a tail-recursive call, but correct me if I'm wrong, it wouldn't be automatic.

After refactoring it, the tail-recursive version would be a bit harder to read than the naive implementation. In a sense the Clojure code is in the same boat, it's just that the optimizations are more complicated, because it's not working with singly linked lists in the "address register" and "decrement register".


So the classic version works in a lazy fashion, for example with infinite structures? Keep in mind that Clojure is a strict language by default.


Nothing more to cut off, including runtime and memory usage.


Apple & oranges. The only thing these 2 have in common is their name, the clojure version does a lot more.

A definition of a similar keep fn in clojure would be almost indistinguishable from your lisp example (it would just be more readable).


Who told you that more is better? Why we should have nested lets and all that boilerplate for a classic filter?


Because you then don't need the complexity (& boilerplate) of SERIES or LOOP the moment you want to do a series of transformations on a slightly bigger list.


You could write the clojure version in the exact same way (well, you wouldn't say null?, but, basically the same) as the lisp one. But it wouldn't be as efficient given the various ways sequences might be implemented in Clojure. That makes sense as part of the standard library, IMO---users of keep don't need to care about whether their sequence is chunked or whatever. And it makes sense that there should be a variety of implementers of sequences: there's more to life than singly-linked lists.

(Even Guy Steele, who should know, recommended a couple years ago that language designers omit cons from their langauges!)




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

Search: