Object-oriented programming with imperative languages like C, C++ and Java has been the norm over the years. But some visionaries argue that other paradigms are more productive. In imperative languages, any method that can possibly return different values, given the same input, has side effects. This article explores the basics of functional programming using Haskell. You to can come to appreciate the raw productivity and power that a functional language can provide and how it eliminates programming side effects.
Many of the attributes that the author mentions in regard to Haskell are also attributes of Scheme and traditional LISP. It would be intestesting to see these languages contrasted.
In other words, what makes Haskell better than Scheme, if anything?
off the op of my head, the major difference is in typing. haskell is based very firmly in a strong typing world. in fact, its pretty much the entire basis for the language.
Off the top of my head, I would say it’s got a very nice syntax. For people coming from the imperative world, Haskell seems quite familiar. Further, it’s syntax, being very similar to math, makes it easy to prove (generally using Induction) that a particular algorithm is correct. This makes it a good tool for prototyping important algorithms.
I never got beyond the basics in my Comp. Sci. course, but I’ve heard a lot of people say that its support for “monads” is also a significant feature. I don’t know much about these, but there’s some info on Wikipedia: http://en.wikipedia.org/wiki/Monads_in_functional_programming
However, one of the languages demerits is that its features for managing and describing data are quite poor. It has OOP, of a sort, but I found it difficult to get to grips with. Personally I think the approach taken by C#, Scala, Python and Ruby of mixing functional techniques into imperative OOP languages is the better avenue in most (though not necessarily all) cases.
i have been (trying to) dive in haskell for some time after using a proprietary variant called miranda a looong time ago in school.
there’s a lot to like about haskell. the tools are decent, the resulting executables are (relatively) high performance across a range of problems (basing this mostly on the programming language shootout), and most importantly it will teach you to think differently about programming.
also, since haskell is very strict about mutability, it lends itself to application spaces which may in the future demand concurrency. it is no mistake that erlang (the best language for concurrent programming) is a functional language.
BUT
programming these days is often about talking to established systems and protocols. haskell is getting better at providing support for doing things like talking to mysql etc, but there is still a ways to go, and you often have to hunt down the code yourself. it is telling that the standard libraries released with haskell98 did not include networking tools you would take for granted in java, c#, etc. a place for improvement in haskell-prime (the “next” haskell which is only being hashed out now) would be to support something like CPAN, gems etc so there is ONE place to host and get libraries from.
also, it must be noted that haskell, at least in my opinion, tends to make some things very easy and some things very hard. writing quicksort in haskell is easy, but how many times are you going to do that? on the other hand, dealing with I/O is in my opinion quite difficult in haskell, and employs a idiom called Monads that is almost impossible to grasp the first time you read the official explanations. there is a wikibook for haskell monads (not to be confused with the wikipedia entry, which is different) that explains it well but uses a metaphor. i am almost convinced that Monads are so hard to grasp that they are just wrong. very intelligent people can grok this stuff but i can’t imagine asking the average coder to figure it out. i would almost say just take Monads at a surface (syntactic) level and don’t even bother trying to understand them. i know it sounds like i am harping on one little detail, but Monads are a huge part of haskell.
so i would say haskell is worth a look, but if you really need to integrate tightly with a lot of pre-existing platforms (apache, mysql, http, xml) i would suggest employing a more mainstream tool.
> dealing with I/O is in my opinion quite difficult in haskell,
> and employs a idiom called Monads that is almost impossible to grasp
> the first time you read the official explanations.
I think there are many unnessecary reasons for this. The official docs might be bad (haven’t seen them). The definition of monads in the language is too general to be understood instantly. If somebody (with a CS background) asked me, I would explain it this way:
“Monads are similar to callback procedures, and are used in event-driven programming just like callbacks. The difference is that a callback *does* things in response to an event, while a monad computes a value in response that tells the runtime system what it wants to do. It’s just a slightly different way to model the response to an event.”
Actually, there’s a lot more to monads than side effects, but that’s exactly the stuff a newbie is *not* interested in.
“You to can come to appreciate the raw productivity and power that a functional language can provide and how it eliminates programming side effects.”
Don’t expect to try functional programming tomorrow and double your productivity. When I was learning a bit about scheme and SML, I spent a LOT of time trying to write things that would be trivial to do in Java, Python, C, etc.
Mindset has a lot to do with it. People pick up on Java/C#/Python fairly quickly, because their syntax and semantics are broadly similar to C++. Haskell, Lisp, etc, are quite different, and take some time to figure out for those with a conventional background.
I remember banging my head on Lisp a lot before really being able to use it productively. For example, I kept trying to map things to my C++-biased understanding of the machine, and failing quite badly at it. I eventually realized that there was no point trying to do that. A symbol isn’t a pointer, not really, cons isn’t malloc, etc. After approaching the language on its own terms, it felt a lot better.
In my experience it depends on your background. When learning programming at university most math majors had no real problem wrapping their brain around Haskell, but many found Java and OOP quite confusing. For people with a CS background it was basically the opposite.
Personally I like Haskell since it allows me to code math pretty much like I think math with higher order functions and induction and stuff like. That being said using it as a general purpose language is just painful and cannot be recomended to anyone.
Functional programming and function-level programming (slightly different thing) is so much more fun than imperative programming. That’s just my opinion, but applying functions to functions to create new functions is how in my opinion is things should be.
What I really want in a language is support for functional and function-level programming (like the J programming language), imperative programming (like J), support for object oriented programming if you want to (like J), but that also comes with easy access to GUI widgets and comes with a compiler (unlike J). How does Haskell do with the latter two?
edit: I see it has both an interpreter and a compiler..nice! It’s a sad fact most of the ‘fun’ languages only come with an interpreter.
Edited 2006-07-19 21:21
There also are GUI toolkits, wxHaskell is oneof them: http://wxhaskell.sourceforge.net/index.html
I agree. There should be more functional programming out there especially considering that with functional programming many tasks that are difficult with imperative programming such as concurrent and parallel programming become easier in the functional world. Erlang for example was designed with concurrency in mind.
I think what’s stopping functional programming from taking off is simply a stigma. The stigma being that functional programs are slow and difficult to write. Like many stigmas that are really no longer true (Look how many people still say Java is slow for EVERYTHING or still call Solaris, Slowaris) It takes a long time for the stigma to be shaken off.
What the functional programming world needs is a champion app of sorts. Just to show the tech world that functional programming can be used outside of academia, and possibly make software development easier and more efficient with functional programming.
What the functional programming world needs is a champion app of sorts. Just to show the tech world that functional programming can be used outside of academia, and possibly make software development easier and more efficient with functional programming.
What the functional programming world need is a good resource for learning the shit that doesn’t deal with quicksort and other useless algorithm wanking.
If anyone has any good links where you can learn patterns and idioms for information systems programming along with a functional language. I’d be be very interested.
ok, it’s not haskell, but i hope it helps:
Erlang is a general-purpose concurrent programming language and runtime system. the sequential subset of Erlang is a functional language, with strict evaluation, single assignment, and dynamic typing. It was designed in the company Ericsson to support distributed, fault-tolerant, soft-real-time, non-stop applications. it supports hot swapping so code can be changed without stopping the system/program.
real word examples
a simple ftp server, ftp client, mini-os, etc.:
http://www.erlang.org/examples/examples-2.0.html
a simple mines game, time server, ftpd, find, wc, etc.
http://www.erlang.org/examples/klacke_examples/index.html
a simple telnet client, tetris, etc.
http://www.erlang.org/examples/small_examples/index.html
as for tutorials:
4days introduction to Erlang with examples
http://www.erlang.org/course/course.html
part one of the Erlang book
http://www.erlang.org/download/erlang-book-part1.pdf
Joe Armstrong’s excellent PhD thesis
http://www.sics.se/~joe/thesis/armstrong_thesis_2003.pdf
the distribution of the language together with libraries and a real-time distributed database (Mnesia) is known as the OTP [Open Telecom Platform]. to download it, go to http://www.erlang.org/download.html
last but not least, the erlang video ;-D
http://video.google.com/videoplay?docid=-5830318882717959520
Edited 2006-07-20 19:49
Thanks for the links. I’ll look into it.
Surfing around on this topic the other day gave me the impression that OCaml is more like what you describe.
well, you know, functions
I like Haskell, although I prefer ML, being old school and all.
Only use them for toys, though, since operating systems are about side effects.
Only use them for toys, though, since operating systems are about side effects.
I think you are looking at the domain from too much of a C/Assembly point of view. Operating Systems are ultimately just programs that run other programs. Most functional programming languages can implement themselves trivially, so they are ideal for writing programs that run other programs. Really, the only hard part is getting the compiler to produce executables that run on the bare hardware.
In fact there have been numerous operating systems written in functional programming languages, including one named House, which is written in Haskell.
Only use them for toys, though, since operating systems are about side effects.
I think you are looking at the domain from too much of a C/Assembly point of view. Operating Systems are ultimately just programs that run other programs. Most functional programming languages can implement themselves trivially, so they are ideal for writing programs that run other programs. Really, the only hard part is getting the compiler to produce executables that run on the bare hardware.
Loaders are programs that run other programs. Operating systems are systems of programs that implement virtual machine abstractions and manage resource sharing.
HoP/house (see http://www.cse.ogi.edu/~hallgren/ICFP2005/house.pdf ) is hardly an “operating system”. In current OS terms it would be a boot loader.
in particular, by skipping file i/o, House is avoiding precisely the reason why side effects are important in operating systems.
There’s a reason there are no storage devices or name spaces in house, and it’s not that the programmers didn’t have time to add them.
> Only use them for toys, though, since operating systems are about side effects.
OSes are also about access to peripheral hardware, which is not possible in many mainstream languages. Ever tried to implement outport() completely in C? However, you can model such access in C (outport does) and likewise you can model side effects in Haskell using monads.
OSes are also about access to peripheral hardware, which is not possible in many mainstream languages.
If access to the hardware requires an i/o instruction from the processor, then no high level language will be able to directly perform i/o, but for each adding the ability would be a simple as adding peek and poke to basic was, back in the day.
If access to the hardware is done through memory mapped registers, as is true of most modern hardware, then it is trivial to do entirely in C and other languages that directly support pointers but difficult to do in languages that don’t.
There’s very little hardware in modern systems that can’t be directly manipulated in C. The example you wanted wasn’t i/o, it was memory management, as that usually requires using special instructions to manipulate processor registers in a priviliged mode.
> There’s very little hardware in modern systems that
> can’t be directly manipulated in C. The example you
> wanted wasn’t i/o, it was memory management, as that
> usually requires using special instructions to
> manipulate processor registers in a priviliged mode.
I wasn’t even referring to anything specific. My point was, if a language doesn’t support something directly (hardware access, virtual memory, I/O, mutable data) then it can often be modeled in terms that *are* supported in the language.
The problem is that “modeling” in this case often adds a layer of abstraction that is only there because the language fails to directly provide the tools.
Modeling side effects in Haskell leads to unnecessary complexity that negates whatever value the functional nature of the language brings to the table, in this case.
> Modeling side effects in Haskell leads to unnecessary
> complexity that negates whatever value the functional
> nature of the language brings to the table, in this case.
Right, but it does so only where side effects are inherent to the problem, which is quite seldom.
Right, but it does so only where side effects are inherent to the problem, which is quite seldom.
unless you’re designing OSes, in which case side effects are your bread and butter.
1.Order-based bugs do not go away when using an FP language. Since it is not possible to write a program without I/O, the IO monad will be used in many cases, thus order becomes important again.
2. Concurrency is not ‘automatically’ solved as a problem as the author says. Haskell does not support threads; there is a special version that provides threading. Extracting parallelism from functional programs is not trivial and certainly not up to the level Haskell inventors claim.
3. Some things are very difficult, if not impossible, to do with Haskell. For example, when I am writing GUI-driven apps, I use the model-view pattern…it is a very clear pattern and very easy to understand and code. Since Haskell does not not have assignment, one has to do various tricks to perform the same thing.
Things get downright almost impossible when one uses trees with nodes that have references to other nodes in the same tree (as for parent-child relationships).
4. logical bugs do not go away. The Hidley-Milner type system is not a depentent type system.
5. Performance issues are still there. It is not a coincidence that databases are coded with ‘real’ programming languages like C/C++.
6. Most of the time in FP languages will be spent trying to figure out how to code a particular task. Lot’s of time.
7. Haskell may have GUI libraries, but can I write a native one? Haskell does not support records and inheritance.
After having used C++ and Java for many years, I can say that bugs in C/C++ programs can be classified in the following two major categories:
A. 90% pointer-related problems.
B. 10% logic problems.
With Java, the problems of category A go away. The rest of the problems remain even in Haskell.
You can replace Java with your favorite garbage-collected language and the argument would be the same.
Conclusion: functional programming languages are good when a program is mostly about calculations. When a program is about reactive programming, functional programming languages get in the way.
> 1.Order-based bugs do not go away when using an FP language. Since
> it is not possible to write a program without I/O, the IO monad will be
> used in many cases, thus order becomes important again.
But order is then important only where it *has* to be important because effects to the external world must be ordered. In pure computation, order is irrelevant.
> 2. Concurrency is not ‘automatically’ solved as a problem as the author
> says.
Being a pure functional language, Haskell maps the problem of implementing concurrency to the problem of avoiding data dependencies. Thus threads can be used internally while not visible to the programmer. Concurrency with nondeterministic effects is not included here, and IMO shouldn’t be (because hidden nondeterminism is one of the worst nightmares of a programmer).
> 5. Performance issues are still there. It is not a coincidence that
> databases are coded with ‘real’ programming languages like C/C++.
Sadly, yes. This was reason #1 NOT to use Haskell in one of my projects.
> 6. Most of the time in FP languages will be spent trying to figure out
> how to code a particular task. Lot’s of time.
I do this with imperative languages too, to get cleaner code, though it’s more visible to me in FP. This might be an issue of getting used to FP, though.
> 7. Haskell may have GUI libraries, but can I write a native one?
> Haskell does not support records and inheritance.
Records are supported (named or ordered), you’re simply misinformed on that one. As for inheritance, many people in the OOP world are slowly coming to the conclusion that the traditional subclassing and inheritance model is flawed, but some pieces of it aren’t. Two main pieces are interface inheritance and code sharing, and both are possible in Haskell.
But order is then important only where it *has* to be important because effects to the external world must be ordered. In pure computation, order is irrelevant.
Indeed, but show me a program where order of execution is not relevant for the 99% of it.
Being a pure functional language, Haskell maps the problem of implementing concurrency to the problem of avoiding data dependencies. Thus threads can be used internally while not visible to the programmer.
Yet we haven’t seen real progress in this sector. Where is the Haskell version that automatically threads computations to all the available cores? I am not saying that FP is not promising, but there are serious technical challenges not overcomed yet.
I do this with imperative languages too, to get cleaner code, though it’s more visible to me in FP. This might be an issue of getting used to FP, though.
Thanks but no thanks. Since I’ve switched to using garbage-collected programming languages, I usually write the correct code in the first try. Any bugs that my code has are purely logical, the kind of bugs Haskell does not catch.
Records are supported (named or ordered), you’re simply misinformed on that one.
Care to share a link? last time I’ve checked, Haskell did not support records:
http://haskell.org/haskellwiki/History_of_Haskell
> Indeed, but show me a program where order of execution
> is not relevant for the 99% of it.
A C compiler. The main actions are:
– read input files and preprocess (since that is required to find #include statements).
– compile
– write object file
Step #2, compile, can be paralellized to a high degree. When writing this in a pure functional language, you jsut have to write down the data dependencies, while in an imperative language you have to implement parallelism explicitly using threads.
> Yet we haven’t seen real progress in this sector.
> Where is the Haskell version that automatically
> threads computations to all the available cores?
You have a point here. However, even if not done automatically, threading can be written down in a simpler manner than with imperative languages, meaning that you just write down hints to aid the compiler/interpreter. And hints cannot contain errors, at worst they slow things down.
> Any bugs that my code has are purely logical, the
> kind of bugs Haskell does not catch.
Well, this is simply not true. Haskell *does* catch logical bugs. Not all, but many. I can’t explain why it does, this is based on experience with both Java and Haskell.
> Care to share a link? last time I’ve checked, Haskell
> did not support records:
Maybe we disagree about what a record is. I thought you mean something like a ‘struct’ in C (ordered example, since I’m not used to the syntax for named elements):
data myStruct = Int Int String
…to Erlang or Haskell?
A very important question. Managers take decisions. Managers only know of C#, Visual Basic and Java.
How do I persuade them to use Erlang (for example)?
May I generalize this question: How do I persuade my managers of *any* decision that I think is good after doing some evaluation personally?