Live data from Hacker News

Why I chose Common Lisp over Python, Ruby, and Clojure

postabon.posterous.com

41–50 of 143 posts

Re: Why I chose Common Lisp over Python, Ruby, and Clojure

#41
post #10

Earlier quoted context omitted.

A single, non-nested list comprehension or generator exp is basically map(filter). You need nesting to get filter(map). e.g. map(expensive_call, filter(cond, seq)) equals [expensive_call(each) for each in seq if cond(each)] but filter(cond, map(expensive_call, seq)) equals [each for each in [expensive_call(x) for x in seq] if cond(each)] note because of "expensive_call", it's inefficient (and silly) to do [expensive_…

I don't get how map/filter is more flexible than list comprehensions. Map/filter require nesting: (filter (map expensive_call X) cond) So do list comprehensions: [y for y in [expensive_call(x) for x in X] if cond(y)] Near as I can tell, the only difference is that list comprehensions also provide a syntactic sugar for the convenience function filter_then_map. Sometimes this saves you a level of nesting, sometimes not…

Well, FP is mostly about nesting, but it's uniform and people get used to thinking that way. List comprehensions, on the other hand, are more like procedure code (conceptually), and it sucks to nest them. Nesting aside, it's the different level of abstraction that matters for FP-ers.

Plus, you get 5 mentions (3 y's and 2 x's) of some intermediate variables instead of 0 in your code, so both token-wise and char-wise, map/filter alternative is shorter, and less a mental burden (think about the "succinct" idea by PG).

Re: Why I chose Common Lisp over Python, Ruby, and Clojure

#42
post #21

Earlier quoted context omitted.

Really? What has improved in Common Lisp in the past two years? Thanks for this comment.

In the last two years? Clozure Common Lisp at least: an open source multithreaded Lisp implementation with unicode on Win32. Before then it was all Unix. Lisp platform independence is so good, I hack on win32 all day and when I am ready to deploy on Linux, the only warning I get is from git telling me it's converting line endings to Unix style. The staggering number of new and maturing infrastructure libraries; borde…

* Few years ago you couldn't just download a random lisp library and expect it to work *

Yeah, that was my painful experience as a noob.

Now dependency libraries get downloaded behind the scenes.

You mean ASDF takes care of dependencies for you?

Re: Why I chose Common Lisp over Python, Ruby, and Clojure

#43
post #33
post #27

Ok, so Rails is too heavy weight for you? What about Merb? Or Sinatra, which was designed for just that reason? Dismissing Ruby as language because only one of a dozen available web frameworks is too "heavy-weight"sounds a bit short-sighted to me.

I am not the OP, but I have a problem with Rails and alternatives: there does not seem to be a viable alternative to ActiveRecord around? I looked into DataMapper (I think that was it's name) which initially looked great. But then I could not find any information on how to use transactions, and also received no answers on the newsgroup. I guess I should have read the source, but I gave up at that point. Since I hate…

Just so you know, one of the stated goals of Rails 3 is to make it super-easy to swap in your own ORM layer, DataMapper included.

Re: Why I chose Common Lisp over Python, Ruby, and Clojure

#44
post #24

Some of the conclusions are inconsistent. For example, Ruby got canned mainly for having a heavyweight framework, since he wants to write everything from scratch. What keeps one from doing that in Ruby? Ruby does not depend on Rails. His complaint about different versions and implementations is a red herring. Lisp is not immune from this.

There are different implementations, of course. But the the multiple version problem was worked out over a decade ago.

Re: Why I chose Common Lisp over Python, Ruby, and Clojure

#45
post #31
post #19

Earlier quoted context omitted.

I know you all know this, but I feel like it bears mentioning that nobody is forcing you to use list comprehensions whether map/filter stay in Python's built-ins or not. They can be defined in around 3-4 lines of code each. Lisp aficionados, already accustomed to the bottom-up style of programming, ought to have no problem writing functions like these as necessary.

Yeah I know. Maybe "force" is not the right word ... probably "discourage"? Actually only one line of code is enough for each of map/filter: def map(fn, seq): return [fn(each) for each in seq] def filter(cond: seq): return [each for each in seq if cond(each)] But seriously, what do you really gain by removing these two? Isn't that too ideological? I don't really see how un-Pythonic it would be to use map/filter inste…

They ultimately weren't removed. reduce was removed from the builtins, but it's still just one import away. From itertools import reduce.

Re: Why I chose Common Lisp over Python, Ruby, and Clojure

#46
post #32
post #10

Earlier quoted context omitted.

A single, non-nested list comprehension or generator exp is basically map(filter). You need nesting to get filter(map). e.g. map(expensive_call, filter(cond, seq)) equals [expensive_call(each) for each in seq if cond(each)] but filter(cond, map(expensive_call, seq)) equals [each for each in [expensive_call(x) for x in seq] if cond(each)] note because of "expensive_call", it's inefficient (and silly) to do [expensive_…

It depends slightly on how you came to functional programming. You can arguably trace Python's list comprehension syntax all the way back to setl, a "set-theoretic programming language", and the resemblance to mathematical set-builder notation is intentional; compare - let B = { g(a) s.t. | a \in A and f(a) holds} - B = [g(a) for a in A if f(a)] If you're used to thinking in sets having to decompose into "maps" and "…

Python's lambda sucks, but that does not necessarily mean map/filter sucks with it too. Of course there are cases where list comprehensions are more convenient and more powerful (esp. if they are more like their "real" counterparts in Haskell and friends). But in cases when map/filter are more convenient, I like the option of using them.

Re: Why I chose Common Lisp over Python, Ruby, and Clojure

#47
post #41

Earlier quoted context omitted.

I don't get how map/filter is more flexible than list comprehensions. Map/filter require nesting: (filter (map expensive_call X) cond) So do list comprehensions: [y for y in [expensive_call(x) for x in X] if cond(y)] Near as I can tell, the only difference is that list comprehensions also provide a syntactic sugar for the convenience function filter_then_map. Sometimes this saves you a level of nesting, sometimes not…

Well, FP is mostly about nesting, but it's uniform and people get used to thinking that way. List comprehensions, on the other hand, are more like procedure code (conceptually), and it sucks to nest them. Nesting aside, it's the different level of abstraction that matters for FP-ers. Plus, you get 5 mentions (3 y's and 2 x's) of some intermediate variables instead of 0 in your code, so both token-wise and char-wise,…

I have a longer comment here that argues the opposite: list-comprehensions are only a syntactic pun or two away from set-builder notation, which is a higher level-of-abstraction (it declaratively states what it is) than map+filter (which specify a procedure to generate it, albeit at higher level of abstraction than a for-loop).

If you can put together a nontrivial usage of map+filter with at least three source collections that's more concise than the equivalent list comprehension I'll (figuratively) eat my hat.

Re: Why I chose Common Lisp over Python, Ruby, and Clojure

#48
post #21

Earlier quoted context omitted.

Really? What has improved in Common Lisp in the past two years? Thanks for this comment.

In the last two years? Clozure Common Lisp at least: an open source multithreaded Lisp implementation with unicode on Win32. Before then it was all Unix. Lisp platform independence is so good, I hack on win32 all day and when I am ready to deploy on Linux, the only warning I get is from git telling me it's converting line endings to Unix style. The staggering number of new and maturing infrastructure libraries; borde…

I have to second this. I switched from CL to Python years ago because of problems with the infrastructure, but now I'm in the process of switching back, largely due to Clozure becoming really ready for prime time, and tremendous improvements in the stability and usability of available libraries. The situation is still not perfect, but it vastly improved and getting better all the time.

Re: Why I chose Common Lisp over Python, Ruby, and Clojure

#49
post #36
post #12

Earlier quoted context omitted.

I think you drawing that conclusion may be a result of how I structured my essay (I introduced my conclusion, then my reasoning). I freely admit my personal biases and experiences eliminated a lot of potentially good options without ever giving them due consideration (e.g., Haskell, Scheme, Lua). But I really did try to give the 3 options listed in the article a fair shake at the time. For what it's worth - I was abo…

I too thought the logic was weak. Here was my basic objection: you chose not to use two popular web programming languages because of their potential volatility, but then went with one that has been so infrequently used in web programming that it almost certainly has opaque deffeciencies. It's not that your reasons were bogus, they just didn't carry the decision.

That's a fair point.

For a programmer without Lisp experience, that would be true. But I've written enough Lisp-based webapps that there aren't really that many 'unforseen' problems for me anymore (rule of thumb: use software by Edi Weitz - everything he writes is golden :-D)).

That being said, I still ran into trouble with Elephant, so I probably should have taken these sort of 'unknown unknowns' (which are more prevalent in unusual languages like Lisp) into consideration upfront. To not do so was certainly an oversight.

Re: Why I chose Common Lisp over Python, Ruby, and Clojure

#50
post #46
post #32

Earlier quoted context omitted.

It depends slightly on how you came to functional programming. You can arguably trace Python's list comprehension syntax all the way back to setl, a "set-theoretic programming language", and the resemblance to mathematical set-builder notation is intentional; compare - let B = { g(a) s.t. | a \in A and f(a) holds} - B = [g(a) for a in A if f(a)] If you're used to thinking in sets having to decompose into "maps" and "…

Python's lambda sucks, but that does not necessarily mean map/filter sucks with it too. Of course there are cases where list comprehensions are more convenient and more powerful (esp. if they are more like their "real" counterparts in Haskell and friends). But in cases when map/filter are more convenient, I like the option of using them.

I'm partially defending list comprehensions here and partially challenging you to consider the possibility that there are higher levels of abstraction out there than those employed by functional programming primitives like map and filter.

Level 0: for-loops with an explicit accumulator

Level 1: map + filter (!)

Level 2: ??? arguably an atemporal set-theoretic approach

In practice in python list comprehensions are a superior syntax for computing with multiple source collections.

(!) Really all you need is reduce

    map = lambda f,l: reduce(lambda h,t: h + f(t), l, [])
    filter = lambda f,l: reduce(lambda h,t: h + t if f(t) else h, l, [])
You'd be silly to implement them that way of course but know your tools.
Post reply on HN