I don’t think Haskell’s IO system is truly hard to use*, especially if you don’t come into it with a lot of baggage and preconceptions from other programming experience. Though Rysto is probably still right that Haskell isn’t exactly what you’re looking for here (and the crows is probably right that Python is what you’re looking for here), who knows? If you give Haskell a try, you might find that you really enjoy it anyway; it’s really quite a beautiful system, very mathematically elegant and cleanly motivated in its way, and though the perspective and approach to programming it engenders is somewhat different than most other things out there, it’s often extraordinarily natural, useful, and convenient (one small example which impressed me highly in my first exposure: you want a variable to store the Fibonacci sequence in all its infinite glory, and be treated and manipulable just the same as any other more plain-vanilla list? No problem!). At the very least, I think experience with Haskell and the ways of thinking it trains you in makes you a better programmer elsewhere as well. At the very, very least, you shed some biases about what seems obviously the only way to do things in programming, and get a better appreciation for what’s necessary vs. what is simply contingently mainstream.
(further details for those who might care): Apart from preconceptions of “The only natural way to do thing X is way Y, since that’s what I’ve seen and am used to” which arise from other programming experience, the thing that trips a lot of people up with Haskell, I think, is all the talk about “monads”, making them think they have to understand the abstract concept of a monad to use Haskell’s IO system. You don’t have to know anything about monads to use Haskell’s IO system, not even what they are, any more than you have to know about commutative rings to use C’s integer arithmetic. In fact, one works with monads all the time in C, Java, Lisp, assembly, whatever; people just don’t talk about them as such (lists (arrays, stacks, queues), trees, and other ‘container class’ type things are all monads; you could say “monad” is just a fancy word for a particular concrete technical notion of “container class”). The best way to learn to write programs in Haskell which do nontrivial input/output is the same way a complete beginner learns to do it in C or Java or any language: someone shows you the basic syntax and concepts, you play around with some toy programs, and eventually you get enough practice that it just seems the obvious way to do things.
Yeah, but unlike a makefile, where the white space is used in seemingly random ways, white space in python enforces structure. Everyone ought to be indenting things that way anyway, so making it required in the language rather than suggested in some “code standards” guidelines just lets you use the compiler/interpreter to force those coders into line.
And, as essell may be saying, making whitespace significant in this fashion prevents you from having to redundantly clutter your code with other structure-indicating elements, like the more conventional braces.
In a way, the rage some people have for significant whitespace (which also exists in Haskell, by the way, though you can optionally use more conventional braces and semicolons to override/ignore it) is another example of preconceptions and biases from long programming experience with particular styles hardening into ill-supported opinions about “the way things shouldn’t be”. Why shouldn’t whitespace characters ever be significant in this fashion (which is really just significance of indentation, and maybe spacing; it’s never the case that invisible whitespace characters at the end of a line change a program’s meaning)? There’s nothing magical about them; they’re characters/visible elements of the program like anything else.
I meant to write “should”, though I suppose there are all kinds of hardenings which go on. Anyway, hardenings into distinctions between natural and unnatural which actually aren’t natural distinctions at all, except because of long arbitrary acquaintance.
When debugging, I’ll often put my temporary, debug lines at the first column. It’s expedient, and works in every, single text editor. Then I can find 'em and delete 'em quickly. Python breaks that habit.
Was having to develop a new habit for use in Python really such a big deal?
Maybe someone is used to using the line number reordering feature of old BASIC interpreters to isolate their temporary debug lines. Then, when they start using C, they find they can’t do so anymore. This doesn’t indicate a substantive problem with C’s syntax; it’s just a minor incompatibility between it and a fairly arbitrary habit they’ve developed. Same sort of thing here.
C# is fairly easy to pick up, has severalfree IDEs, and has a decent amount of libraries to do the boring stuff you don’t want to.
It has the added benefit of being taught as an intro language at most universities, meaning you can go to their webpages and download the course notes, and then complete the assignments they give. (Seems to be what our engineering counterparts at work are doing, based on what’s showing up in the code repository. Can’t seem to find a good one just now though.).
I don’t think I’d recommend any books on gaming programming; the one or two I bought never caught my interest. My local libraries each have a few that aren’t terribly out of date though; I’d recommend checking yours.
I would agree. In my experience universities tend to use mostly unix-type operating systems in the CS departments. And while mono is out there, I can’t imagine anyone wanting to use that while Java is out there (and so many better alternatives too).
Scheme is written mostly using parentheses. Good Scheme programmers quickly learn to ignore them.
Scheme was created solely to generate the Fibonacci sequence. Every Scheme tutorial ever written uses generating this sequence as a demonstration program. Therefore, every Scheme tutorial actually eliminates the need for Scheme itself. This takes all the pressure off the new Scheme programmer.
The Lambda calculus is essential to understanding Scheme. You can’t even create a 3-line do loop program without grokking the Lambda calculus. The Lambda calculus is about metarecursion. In fact, you can’t begin to figure it out until you have already mastered it.
From this and other comments I think I gather that by learning Python, one can learn how a lot of other kinds of programming languages work. This is very appealing to me, but is it true?
Depends on what you mean by work. The lambda calculus and its cousins are the basis for the theory of programming languages, and if you’re interested in how compilers and interpreters work, it’s invaluable. It’s also useful for understanding functional language idioms which are starting to show up more often in non-functional languages.
On the other hand, if you want to know how the code you write corresponds to what the machine or interpreter executes, it’s not quite so important. C/C++ are better for that, although I don’t recommend trying to pick them up without access to an expert.
For the amount of casual Python programming I do, yeah, it really was a big deal. If I were to make it my “main language” (you know, “give it a chance”) I’d probably not find that it was such a big deal, though. On the other hand, using it as a main language would guarantee that I use XCode, which breaks me from counting on “universal text editor behavior” as it has quite a lot of robust debugging, text-editing, and other code-related tools. And I’m pretty sure that it supports Python. And I think it supports bindings to Cocoa via Python. Hey, maybe I could give this thing a chance!
The last time I checked, the Python “lambda” construct was both crippled in functionality (limited to expressions rather than statements, which would be acceptable in some contexts (e.g., a pure functional language which essentially has only expressions), but is just pointless in Python) and broken (I remember closures being messed up; certainly, the scoping rules in Python are a mess). There are workarounds, but the whole business of forcing people to use such workarounds just gives them a misleading idea that the lambda construct is inherently tricky to use, rather than that the problem lies in Python’s half-hearted embrace of it.
Time and again, Guido van Rossum has demonstrated his complete antipathy towards (and, I would say, lack of understanding of) the lambda calculus and the functional programming style more generally. See, for example, here, where he states
Also, see his remarks on tail call optimization here:
Whatever its merits, I don’t think one can say Python is really capable of giving any true experience with the lambda calculus/functional programming style.
I admire Guido’s honesty - at the end of the day, Python wasn’t designed as a functional language and the functional bits are shoehorned in, and badly. Maybe they should be removed.
I just don’t get my head around functional programming. I tried LISP at uni, but it went woosh. I did manage to make PROLOG work for me, but it’s not something I use now. Maybe I was just slow.
I think one way of looking at lambda constructs is that it’s a way of writing your own control statements.
For instance, say you’ve got a small language that has a c-like if() {} and a way of constructing anonymous functions / code-blocks that can be passed around. With that you can implement case/switch constructs, unless() operators, collection iterators etc in the core language (the following is basically javascript):
In Javascript this is very useful because it means I can implement all kinds of “standard” iterators like forEach, filter etc myself if the browser that I’m running on doesn’t support them natively. It also means I can reuse those iterator names and API even with collection objects that I’ve built myself. Ruby uses that a lot too.
Now javascript’s syntax makes this really more verbose than you’d want, but it does work and work well. In Ruby you could write the unless() statement so that you could call it as:
unless x < 10 {
print "X >= 10"
}
And in lisp macros give you the ability to compress and warp the syntax down to exactly what you’d want for short but expressive code.
All this is to say, that most flow-control constructs you see in C-like languages could be implemented in the language, provided you have functional constructs and a single basic construct.
Or look at it this way:
if ( condition ) {
some_statements
}
Could “really” be a test that calls an anonymous function containing