Live data from Hacker News

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

postabon.posterous.com

101–110 of 143 posts

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

#101
post #15
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_…

Most times you are interested in doing the simple, e.g.: filtered = [x for x in seq if x>10] Python's list comprehension is much more readable than using map/filter/reduce - at least for Python programmers :) Anyhow, I really like Guido's decision on dropping these - it creates a cleaner language and forces people to think Pythonic when programming in Python.

Um...

    (filter #(> x 10) seq)
sure is readable for me, and I'm fluent in Python and various Lisps. (That example is Clojure.)

I would like to point out, however, that CL allows you to write:

    (loop for x in seq
          when (> x 10)
          collect x)
which you might think is verbose ("why do I need that 'collect'?")... except that loop allows you to write things like

    (loop for i in *random*
          counting (evenp i) into evens
          counting (oddp i) into odds
          summing i into total
          maximizing i into max
          minimizing i into min
          finally (return (list min max total evens odds)))
Loop knocks Python's trivial list comprehensions into a cocked hat.

I switch between map/filter and loop depending on whether I'm working with predefined functions (e.g., (filter 'less-than-ten seq)), handling multiple sequences, doing side-effects, etc.

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

#102
post #19
post #17

Earlier quoted context omitted.

> Python's list comprehension is much more readable than using map/filter/reduce - at least for Python programmers For simple cases, yes. But I wouldn't say [each for each in [expensive_call(x) for x in seq] if cond(each)] is more readable than filter(cond, map(expensive_call, seq)) at least for functional-thinking minds. The level of thinking in abstract is different here. Now the problem is, some people see Python…

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.

There's a difference between things being possible and being encouraged.

De-emphasizing functional operations makes it more likely for libraries to work in a non-functional style, for tutorials to do so, etc.

It's tiring fighting against a community and a (benevolent) dictator that disagree with you.

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

#103
post #22
post #6

Earlier quoted context omitted.

Nope - just a style thing. You don't need lambdas either - named functions are just as powerful. But I often think 'functionally.' Since I have options, I'd rather go with a language that allows me to program how I think - instead of being forced to translate my thought into its semantics.

Nope - just a style thing. You don't need lambdas either - named functions are just as powerful. It depends on what you define as power, and how wide of a continuum you are willing to presume that it runs. Named functions add two levels of clutter. The first is to the actual code, because you have to add a name to something that never wanted one, and it has to be defined apart from where it is used. You could give it…

The "correct" alternative to multiline lambda might be not a named function but an explicit code block: no clutter at the prize of vertical space.

  result = []  
  for item in iterable:
      # here goes multiline lambda as an explicit suite
      # that computes value
      result.append(value)

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

#104
post #96

Earlier quoted context omitted.

Using do-notation is probably cheating, but what do you think of this? (in Haskell): do { w We're trading horizontal space for vertical space. I think it's much clearer than either list comprehensions or plain map/filters. It's the best of both worlds.

I like the look of it. Am I correct that the order the statements are in translates into the order things are evaluated in when the code is called? If eg I edited it to be: do { l Does that force it to go through "location-first" and only check the w and s of (w,s,l) for compatibility if it has already ascertained that w and s are in stock @ l?

Yes, that's correct.

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

#105
post #58
post #7

I predict you will get a great deal of pythonic fire. Nevertheless, I find it very nice that you plan to deal with the specific libraries you're using in the next posts. The greatest problem in adopting CL seems to be the extremely decentralized (not to say disorganized) library spacs.

"Python 2 is fine now – but in the coming months and years new libraries, features, and performance improvements are only going to be introduced in Python 3, and I didn’t want to get left behind or forced to take on an expensive and time consuming port in the future." Does this argument hold some water, or is Python 2-to-3 conversion often pretty trivial in practice?

Word on the street is that the 2to3 tool is magical. Just run the Py2.6 interpreter with the "-3" flag for warnings, fix the warnings, and run the 2to3 tool to get your port.

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

#106
post #78

Earlier quoted context omitted.

As a beginner to lisp, I have always been bothered by the lack of standardization - especially in terms of libraries. For example, a couple of weeks back, there was an article about a python-based tool on HN (I forget which). There was a lot of opinion, however was generally about BeautifulSoup vs lxml. Coming to CL, I dont even know where to begin for XML parsing ( http://www.cliki.net/XML ). Which is why, it seems…

As a beginner just grab the XML lib which is easiest to install and looks comfortable to use. If it doesn't work out try another one. I really don't get all the complaints in this thread about the lack of a central library repository. How hard is it to use Google? Libraries aren't suddenly bad because they're not from Lib Grand Central. In other languages, Perl specifically, I've tried libraries from CPAN that were t…

Perhaps it's possible to get lucky and find good libraries using nothing but Google and patience, but I'm baffled that anyone would deny the value of something like CPAN.

CPAN's structure enforces good practices: (e.g., tests, docs, bug tracking).

CPAN provides not one but two excellent search pages. It also contains many reviews, and makes it trivial to see the source of any library or app before you download it.

CPAN helps enable sprawling, group-built libraries (Catalyst, Moose, DateTime).

CPAN has a whole mini-network of related sites that provide secondary help (installation testing and reports, annotation for docs from users, etc.).

I really don't get what you don't get. It's obvious to me why a good centralized library repository is a win for any language.

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

#107
post #98

Earlier quoted context omitted.

I like lambda because it allows anonymous functions-- functions that can be defined on the fly (dynamically) and then thrown away. IMO, it's generally bad form for a program to be dynamically creating named functions, filling the namespace. Also, I like map and filter because they aren't just functions in the procedural sense but combinators: you can pass them around, using them as arguments and returning them. It's…

IMO, it's generally bad form for a program to be dynamically creating named functions, filling the namespace. That's what inner functions are for. This isn't the best example, but you get the idea: def foo(mylist): def n_to_the_n(n): if n > 1: return n**n return 1 return [n_to_the_n(i) for i in mylist]

Do the inner functions get cleaned up after you exit the function body?

I'm used to Lisps, where def/defun/define/defn imply internment. For example, in Clojure:

  (defn foo [list]
    (defn n-to-nth [n] (Math/pow n n))
    (map n-to-nth list))
Would intern the symbol 'n-to-nth in the current namespace. So every time I see "def", I think of something that has that (mild, almost always innocuous) side effect.

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

#108

It's funny, that the decision to choose Common Lisp for some project often has to defend itself (because of so much FUD around the language). CL has one killer feature, that will appeal to any mature developer: it's the only production-ready language around, in which you are virtually not constrained by any third-party design decision. That's it. Discussing other details just boils down to the question of tastes (tha…

What about Clojure, circa now? Do you not consider it "production ready"?

I've used both CL and Clojure. I'd prefer either over Blub, but Clojure wins in my opinion.

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

#109

Earlier quoted context omitted.

You bring up a good point about passing map and filter around. I hadn't really thought of that. I still prefer to user list comprehensions, and don't think it would be so bad to have map, filter, reduce live in the itertools module. This would stylistically match what is done with the comparison operator functions living in their own module, which you can import if you need to pass the functions around.

List comprehensions are great, but they're sort of a DSL-- something the syntax recognizes as special and converts to something else. It's unusual that you can pass around higher-order syntactic elements, while every modern language worth its salt allows you to pass around functions. Common Lisp has something similar, called LOOP. Implemented as a macro, it's a within-Lisp DSL for expressing looping constructs, e.g.…

Indeed, we figured out recently that it's basically embedded Algol 68... which seems superbly fitting somehow.

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

#110
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.

It's the other way around. For things you've decided to write from scratch, especially if they're hard, CL is a dream. There's nothing comparable in my experience [~]: you can build unbelievably powerful and concise programs easily, then just as easily transform them in major ways. It's the ultimate combination of malleability and expressive power. (Oh, and performance, when you need it.) I can think of only three reasons to prefer Ruby over it: (1) you want Rails etc.; (2) you don't like Lisp; (3) you really like Ruby. The latter two are matters of taste, which leaves #1.

[~] I haven't tried Clojure yet. Then again, I don't need to: the JVM is a drawback for me, and I don't need all those Java libraries right now.

Post reply on HN