This defaults Num, Read, and Show to Integer—I try to avoid defaulting because it’s kind of a language wart. And speaking of golf: same length but one fewer import by killing the fmap.
That's a bit of cheating, as it removes 'lines' or 'line' from code, decreasing readability. So to be fair you want to add it back:
print sum(map(float, open('somefile.txt'))) # over lines
or
print sum(map(lambda line: float(line), open('somefile.txt')))
Either one is all right, but personally I prefer list comprehension notation.
As per Guido: ... and that a more concise notation for anonymous functions would make map() more attractive. Personally, I disagree—I find the list comprehension notation much easier to read than the functional notation, especially as the complexity of the expression to be mapped increases. ...
In Python it's well known that the default iterator on a file gives you the lines. Arguably a function would've been a clearer design, but this is idiomatic in the language we have.
As far as map vs. list comprehension, yes, I prefer the comprehension in the cases where map would need lambda. Here that's not the case. Per "as the complexity of the expression to be mapped increases", this expression 'float' is the simplest possible.
Python was my favourite language, but after a year of scala I can't go back. Syntax is almost as lightweight as python, sometimes even lighter (_.something rather than lambda x: x.something is a godsend); tuples and case classes mean it's easy to define a new type for things where you'd use a dictionary or object() in python, and the type system is expressive enough that it doesn't get in the way, not to mention the joys of e.g. the typeclass pattern (which allows a level of dynamicity that would be simply impossible to do sanely in python). There's a mature deployment story (because at that stage it's just .jars) and the huge java library ecosystem is available up to a point.
I'm curious, what for? Performance, type safety or compile errors?
If type safety, then in my opinion it is overrated. A side effect of using dynamically-typed language is that developers keep their naming conventions consistent and in check. Because that's the only sane way to avoid stupid typos in a language that doesn't have a compiler. It is not so in the compiled language world. What I often see in the code, where type safety is enforced, - is that developers get sloppy with names! And as a result, there is a significant increase in bugs caused by logic errors. sad
A side effect of using dynamically-typed language is that developers
keep their naming conventions consistent and in check.
I've not found this to be the case. I just discussed method naming in Javascript with a developer today while I was reviewing his code. He's a very good developer and this is an A+ codebase (no, it's not a pile of jQuery plugins...). But he hadn't really thought about how to name some methods and didn't realize the confusion that would be caused in 6-18 months. We left it as he had written it because it would have been a pain to hunt down the dependencies.
Were we working in a compiled world, we would have refactored and the compiler would have caught any missed dependencies in a second.
What I often see in the code, where type safety is enforced, -
is that developers get sloppy with names!
I've definitely not seen that. I maintain the same rigor w.r.t. hygiene whether I'm working in statically or dynamically typed languages, but I really miss the compiler when I'm working in dynamic languages.
At the risk of sounding really rude, can I ask whether your anecdotes are informed by work with competent developers?
We left it as he had written it because it would have been a pain to hunt down the dependencies. Were we working in a compiled world, we would have refactored and the compiler would have caught any missed dependencies in a second.
Ideally, unit tests should take compiler role and be able to catch typos and missing dependencies. There is really no excuse for not maintaining unit tests in the dynamic world.
Unless it is a research grade code with limited lifetime.
As to your question, I have no idea really. I've stopped judging goodness of other developers and myself some years back.
Pardon me for not being clear enough (and for derailing the thread?).
What I was trying to say, is that you can catch missing dependencies and misspellings for free, while running lightweight unit tests. (unit tests are there for catching logic errors and allowing debugging of individual modules; catching misspellings is just a side effect).
On a side note, if somebody is complaining that "a typo in the python code caused client call at 2AM, this could have never happened in Haskell", what they are really saying is that they haven't bothered to run any test coverage whatsoever before deploying new code.
>What I was trying to say, is that you can catch missing dependencies and misspellings for free, while running lightweight unit tests. (unit tests are there for catching logic errors and allowing debugging of individual modules; catching misspellings is just a side effect).
Sure, but a lot of code doesn't need that. Say you're writing a conversion between two datatypes; in something like Haskell you can be confident that if it compiles then it's correct. There's no logic for there to be errors in, so having to write a unit test would be an additional overhead in a more weakly typed language.
>On a side note, if somebody is complaining that "a typo in the python code caused client call at 2AM, this could have never happened in Haskell", what they are really saying is that they haven't bothered to run any test coverage whatsoever before deploying new code.
Bollocks. You can have 100% line coverage and still hit a type error. And a language where you have to have 100% coverage is a lot less pleasant to work in than one where you don't.
There are some things you can enforce with a type system that you cannot practically implement with unit tests.
For example in [1] it is described how a type system can be used to help you keep track which kind of string contains what data (SQL, XML, user input...) to catch problems with injection attacks at compile time.
A type system like this can create a lot of drag, when, say, you need to interface to an external library and suddenly discover that this library, annoyingly, only works with strings, not your data types. In this case you might have been better off, just by keeping name conventions straight.
I'll take a sloppily named Haskell codebase over a well-named Python codebase, especially when reliability is compared.
Type-safety of the Java kind might be overrated. Type-safety of the Haskell kind, though is hard to over-rate. It catches the vast majority of bugs, including ones people would refer to as "logic bugs".