Posted by Daniel Lyons
Thu, 04 Oct 2007 02:27:00 GMT
I noticed something interesting the other day about the functional and object-oriented languages.
Consider Python, where you can write functions like:
def foo(first, second=0, *rest, **kwargs):
return first + second / len(rest) * kwargs['multiple']
Compare to a functional language like Haskell, where you can’t do that, but you can create types like:
data MyThing = YourThing Integer
| AnotherThing (Int, Char, Float)
| NoThing
Weird that in Haskell, a functional language, you don’t get keyword arguments or arbitrary numbers of arguments, but you do in Python, whereas in Python, you’re confined to a rather small set of built-in types or full-on objects.
Of course in Lisp, you get really ornate functions and the ability to make new types through OOP. But you don’t get strong typing. ;)
Tags haskell, languages, programming, python | 2 comments
Posted by Daniel Lyons
Thu, 20 Sep 2007 07:14:00 GMT
For a good time, please read a very twisted analysis of the benefits of performing poorly. (To my new anal-retentive readers: you try and figure out this guy’s name, and then I’ll cite it).
I have some remarks on Reddit which I’m proud enough of that I thought I’d share them with you sharks here. I wonder if the author has really listened to his own argument. I find it somewhat lacking in the “holding water” department:
“If you know the language to be dog slow any way, you’re much less likely to waste your time on the pointless microoptimizations that geeks so love…”
I think this one works equally well in reverse: if you know the language is already quite fast, you’re much less likely to waste time on pointless micro-optimizations that geeks so love. In fact, if your language is dog slow, there are probably more optimization opportunities than there are if it’s already quite fast, as a matter of diminishing returns.
“The fact that non-standard library code is inherently somewhat inferior adds further incentive to attempt community wide standardization…”
This fails rather spectacularly to explain why the Common Lisp standard includes such a huge standard library. Consider the inverse argument: “the fact that your library code runs as well as built-in code removes incentive to use the standard library.” In the magical imaginary world I pretend to live in, people apply appropriate abstractions without much regard for the performance—abstractions that perform radically poorly being considered inappropriate, I guess—but I would never imagine sitting on my hands, wondering whether or not I can “afford” the overhead of a function call.
“Python’s very slowness represents part of its competetive edge over languages that are in some ways better engineered and more capable…”
What is this, things that are poor in one area tend to be good in others?
I could only consider agreeing if somehow it were a zero-sum equation: all languages have equal amounts of effort applied to them, and some of it goes to performance. But it’s not a zero-sum equation, languages receive differing amounts of attention to different strengths for different reasons. Moore’s law and the rapidly increasing demand for programming alone have enabled Python to compete against a language three times older, better designed, implemented and specified.
Actually, no, that’s flat-out nonsense.
“I’d not be suprised if on the whole it greatly increases programmer productivity and results in clearer and more uniform code…”
I would tend to expect uniformity from any language which syntactically enforces it. :)
I certainly would not expect a poorly-performing program to go through as many stages of evolution as a rapid program. You have to factor in the compilation phase—but one usually doesn’t compile in-development Lisp programs while working on them. They evolve much more organically, because there’s not necessarily a separation between development and testing, whereas in Python there is to a larger extent. Supposing the compile-time differences are negligible (which, they are, if you are careful) I have a hard time believing that Python programs running more slowly permits more evolution to take place.
“Also, since only builtins have reasonable performance there’s added motiviation to become very familiar with the available builtins and far less temptation to roll one’s own version of say dict.setdefault (even if it it sucks)...”
I think the existence of sucky built-ins like setdefault contradicts the point about the quality of the standard library. From where I’m sitting, the quality of the standard library is a function of backwards-compatibility more than community involvement. Lisp has a larger, somewhat clunkier one because it is much older. Ruby’s library is much cleaner because it went through a lot of life without having to worry about backwards compatibility very much. Io is doing even better, having been designed by language aesthetes like Steve Dekorte who are familiar with a lot of good and bad APIs, and who aren’t afraid to break backward compatibility to make a global improvement in expressiveness.
This article nicely dovetails with an argument my friend Pi has been having with various cornholes on IRC about Python and Ruby. Ruby’s standard library is just plain nicer. Which do you prefer, based on your gut instinct:
foo.bar.baz.split.collect { |x| x.bazzle }.join(' ')
Or this:
' '.join([ bazzle(x) for x in string.split(foo.bar()) ])
Hell, for good measure, let’s toss in some Haskell:
unwords $ map bazzle $ words $ foo bar
I’m talking about your aesthetic reaction here. Your artistic reaction. You know which of these you prefer. You want the agglutinative glory of Ruby or the isolating awesome of Haskell. Follow your eyeballs on the above Python example. Compare to Ruby and Haskell. Your eyes hop around on the Python, trying to figure it out. Haskell and Ruby, your eyes slide across from left to right. You feel like you’re reading a language, not decoding one.
As an aside, slap the next person you meet who, ignorant of Haskell, rants about static typing. They’ve never used it, they have no idea what they’re talking about. They’re actually giddy or incensed about type annotations and other forms of busy-work. Don’t put up with it.
Tags haskell, languages, programming, python, ruby | 4 comments
Posted by Daniel Lyons
Tue, 10 Apr 2007 09:49:00 GMT
You guys are too sad for words.
Still, I wish you the best of luck. I can’t wait until I start seeing links on reddit about you.
Tags python, zope | 1 comment
Posted by Daniel Lyons
Wed, 22 Nov 2006 08:33:00 GMT
If you are interested in implementing quicksort in any reasonable language from scratch, you may not want to read this post.
I had some fun making this post but by all means draw your own conclusions and ignore my commentary.
The OO Languages
Io
List quicksort := method(
(self isEmpty) ifTrue(return List clone) ifFalse(
first := self first
rest := self slice(1)
below := Quicksort quicksort(rest select(i, i < first))
above := Quicksort quicksort(rest select(i, i >= first))
return below appendSeq(list(first) appendSeq(above))
)
)
I’ll be honest: this one took the longest and was the hardest to write. Additionally, it is the not very aesthetically pleasing (though moreso than any of the other OO languages), and I still don’t understand how Io knows when to execute a given piece of code (look at the select portion). It also was pretty unreadable until I separated the above and below variables out. I also didn’t understand why I needed return but it seemed to break the code to not have it there.
That said, it is very whitespacey, which is worth points in my book. This is the implementation I’m the least confident of. Io has changed a lot since I last was using it, and I never became very proficient at it.
Python
def quicksort(l):
if l == []:
return []
else:
x, xs = l[0], l[1:]
return quicksort([ i for i in xs if i < x ]) + \
[x] + quicksort([ i for i in xs if i >= x ])
For some reason, the list comprehensions didn’t do it for me this time. I preferred them in the functional languages where there seems to be less overhead. The parallel assignment helped a bit, but the lack of pattern matching was pretty annoying.
Ruby
def quicksort(l)
if l == [] then
[]
else
x, *xs = l
quicksort(xs.select { |i| i < x }) + [x] +
quicksort(xs.select { |i| i >= x })
end
end
It feels a little tidier than Python. The select was a little tidier than the equivalent list comprehension in Python, and seems to get right to the point a little better whereas with the list comprehension, the meaningful portion is in the if conditional on the far right.
I prefer the x, *xs = l notation, because it reminds me of pattern matching in the functional languages.
The Functional Languages
Haskell
module Quicksort where
quicksort (x:xs) = quicksort [ i | i <- xs, i < x ]
++ [x] ++
quicksort [ i | i <- xs, i >= x ]
quicksort [] = []
Well, you’d expect a winner, and lo, it is a winner.
Erlang
-module(quicksort).
-export([quicksort/1]).
quicksort([H|T]) ->
quicksort([ X || X <- T, X < H ])
++ [H] ++
quicksort([ X || X <- T, X >= H ]);
quicksort([]) -> [].
Looks just like the Haskell to me, albeit with Prolog-esque syntax. But I like Prolog, so that’s worth a couple points. :) Tie with Haskell.
OCaml
let rec quicksort = function
| (x::xs) ->
(quicksort (List.filter (fun i -> i < x) xs))
@ [x] @
(quicksort (List.filter (fun i -> i >= x) xs))
| [] -> []
;;
Naturally, a bit of OCaml noise enters the picture. No nice list comprehension syntax so we get to use the old-fashioned filter function. However, it’s still quite small. I think it is very readable, I’m just wondering whether OCaml is going to wind up being the functional language I use the least.
Lisp
(defun quicksort (l)
(cond
((null l) nil)
(t (let ((x (car l))
(xs (cdr l)))
(concatenate 'list
(quicksort (remove-if #'(lambda (i) (< x i)) xs))
(cons x nil)
(quicksort (remove-if #'(lambda (i) (> x i)) xs)))))))
Wow. That’s… so ugly. By far the wordiest functional language. I could have done it without the let block though, in which case it looks like this:
(defun quicksort (l)
(cond
((null l) nil)
(t (concatenate 'list
(quicksort (remove-if #'(lambda (i) (< (car l) i)) (cdr l)))
(cons (car l) nil)
(quicksort (remove-if #'(lambda (i) (> (car l) i)) (cdr l)))))))
How unpleasant. I would have expected Lisp to do better. Oh well.
Tags erlang, haskell, io, languages, lisp, ocaml, programming, python, ruby | 13 comments
Posted by Daniel Lyons
Thu, 21 Sep 2006 04:27:30 GMT
I didn’t expect to say this ever again, but I have to say it: Python is good. Python 2.5 brings it back up to speed with Ruby. Plus it’s faster and it has the best web development environment on Earth. And SQLAlchemy rocks my socks.
Python 2.5 cool features:
- Partial function application. Helloooo functional programming. :)
- The
with Statement: Feature parity with Ruby, one feature at a time.
- Generators are now full coroutines
- Conditional expressions a la the infamous ternary operator
- Built-in SQLite
SQLAlchemy, glory that it is, is a full SQL abstraction layer, meaning pretty much any SQL statement can be implemented just by calling functions in Python without handing over any raw SQL, and then on top of that you get the most flexible object-relational mapping system I’ve ever seen. Goodbye meaningless auto-incrementing IDs, hello sexy object relationships in the database with meaningful primary keys.
Pylons I can’t even begin to describe the excellence of. In short: it takes everything good from Rails and improves it. It uses WSGI throughout, which means it’s shockingly flexible: replace the template system, the backend web server, or anything in between and reuse everything else. The excellent Routes library borrows Ruby’s routing system, and the superb FormEncode makes validation quite simple. In the near future FormBuild will make it so that I never have to make a form by hand again and AuthKit will abstract out all authentication/authorization problems. It rocks in every way Zope wants to but can’t.
Enough free advertising. Thanks to Ben and James and everyone else for implementing an excellent framework! May it hit 1.0 soon!
Tags development, python, shoutouts, web | 1 comment
Posted by Daniel Lyons
Thu, 14 Sep 2006 20:43:38 GMT
“The fact that Zopers don’t understand why Python framework developers are busy routing around an inherently unpythonic application server is somewhat amusing, yes. Or tragic.”
—Fredrik Lundh on a blog
Tags languages, programming, python, quotes | no comments