Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

I'm interested in better learning functional programming. To do so, it seems obvious that I should force myself to use the purest possible functional programming language. Hence, I'm here asking, more or less, for an ordering of functional programming languages according to their purity.

It seems to me that it would be more practical to learn Lisp or Clojure (or Scheme, or Scala, etc.), but for what I've heard recently, Haskell would be very hard to beat at teaching functional programming principles to someone. I'm not sure about this yet, so I'm asking you: which is the purest functional programming language? An ordering would be great if several are competing for the magnificent title of the purest functional programming language.

share|improve this question

closed as primarily opinion-based by MichaelT, Bart van Ingen Schenau, GlenH7, Dan Pichelman, BЈовић Jul 5 '13 at 6:36

Many good questions generate some degree of opinion based on expert experience, but answers to this question will tend to be almost entirely based on opinions, rather than facts, references, or specific expertise.If this question can be reworded to fit the rules in the help center, please edit the question.

1  
I learnt Miranda at university so I'm biassed, but I would suggest Haskel to anyone wanting to immerse themselves in a functional language without the distractions of impurity. *8') –  Mark Booth Feb 6 '12 at 15:59
    
After you're done learning functional programming, you should also learn statically typed programming with an expressive type system. In the combined category (both functional and typed), I suggest: Coq > Haskell > OCaml > Scala > others. There are some less popular alternatives that fit in between Coq and Haskell (like Epigram and Agda). Haskell misses OCaml's expressive module system. –  lukstafi Jul 5 '13 at 22:01

7 Answers 7

up vote 18 down vote accepted

There's no scale for assessing the degree of purity of functional languages. If the language allows sideeffects it's impure, otherwise it's pure. By this definition, Haskell, Mercury, Clean etc are pure functional languages; whereas Scala, Clojure, F#, OCaml etc are impure ones.

EDIT: Maybe I should have phrased this as "if language doesn't allow side-effects without letting the type system know, it's pure. Otherwise it's impure.".

share|improve this answer
5  
Not quite: Haskell does allow side effects (IO monad). It's just that side-effect-causing code is clearly marked as such. I don't think it's useful to talk of pure/impure languages at all (Haskell lets you program imperatively! Gasp!) but it can still be useful to talk of chunks of code (function, module, program, whatever) as being pure/impure. –  Frank Shearar Dec 10 '10 at 9:48
6  
@Frank: Yes, Haskell does allow side-effects, but it does more than just marking side-effect-causing code. It also maintains referential transparency even when using side-effect-causing code and that's what it makes pure - at least by many people's definition of purity. Of course that doesn't match missingfaktor's definition of "no sideeffects allowed". –  sepp2k Dec 10 '10 at 13:08
3  
@Frank Shearar but it is useful to talk in a such a way because the IO monad is pure. Its the runtime library that isn't, not your code, since your main function is basically a huge state transformer. (Something like main :: World -> World behind the scenes) –  alternative Apr 20 '11 at 18:20
1  
My language has referential transparency, too. You just write program = "some C code", and then the runtime environment deals with the C code. :-) –  Daniel Jun 14 '11 at 23:12
2  
As printing out to the screen is a side-effect truly pure functional programs are pretty boring. –  user1249 Nov 22 '11 at 11:01

I personally categorise languages in three tiers of functional purity:

  • Pure functional languages - i.e. those that treat your entire program as a pure function and handle mutability solely through interaction with the runtime - Haskell is probably the canonical example

  • Impure functional languages - i.e. those that emphasise a functional style but allow side effects. Clojure is clearly in this category (it allows mutation in a controlled fashion as part of its STM framework), also OCaml or F#

  • Multi-paradigm languages - these are not functional languages first and foremost but can support a functional style by the use of first class functions etc. Scala is a good example here, I'd also put Common Lisp in this category and you could even include languages like JavaScript.

In your situation, I'd suggest learning Haskell first, then Clojure. This was what I did and it worked very well for me! Haskell is beautiful and teaches you the purest functional principles, Clojure is much more pragmatic and helps you get a lot done while still being very much functional at heart.

I don't really count the third category as functional languages (although after learning Haskell and Clojure I often find myself taking advantage of functional techniques when using them!)

share|improve this answer
    
Within very strict limitations, even C has functional capabilities. (The main limitation is on runtime synthesis of functions, which is truly horrendous in C, so much so that most people claim it can't be done.) –  Donal Fellows Jun 15 '11 at 8:40
1  
@Donal Fellows: In the limit as silliness goes to infinity, every Turing-complete language is functional: one need merely implement a Lisp interpreter in the language, and then use that. :] –  C. A. McCann Jun 16 '11 at 0:55
    
Paradigms are meaningless if you take the viewpoint that everything is Turing complete and therefore can emulate everything else. When you think about paradigms you have to focus on what the language makes idiomatic and what it discourages/prevents. To count as a functional language in my view, mutation and side effects must be unidiomatic (for impure FP) or prohibited (for pure FP). That means C is not functional. Neither are multi-paradigm languages like Scala. –  mikera Nov 22 '11 at 10:56
    
@mikera: I find your answer very interesting: if Scala is not functional but only multi-paradigm, how do you judge functional programming features in C++11, C#, or even Java (the planned introduction of lambdas)? –  Giorgio Mar 10 '12 at 20:20
    
@Giorgio : I think functional features in all the languages you mention are probably a good idea, they just don't make them "functional languages". Or to look at it from the opposite direction, the fact you can do imperative-style monadic IO doesn't make Haskell an imperative language :-). Multi-paradigm languages are basically the result when you bring features from lots of different paradigms together and don't put any particular style first and foremost. IMHO C++, C# and Java are all all moving towards being multi-paradigm, but aren't quite there yet since class-based OOP is still dominant. –  mikera Mar 11 '12 at 13:51

Not an entirely serious answer, but Unlambda has to be a contender. You can't get any more "pure functional" than S K I combinators.

share|improve this answer
3  
Madness! Heresy! What sort of pure language has absurdities like combinators with side-effects? No, no. What you really want here is Lazy K. –  C. A. McCann Jun 15 '11 at 17:51

Impure languages don't really differ in principle from the more familiar imperative languages, especially now that many functional tricks have been copied. What's different is the style - how you solve problems.

Whether you count Haskell as pure, or count the IO monad as impurity, Haskell style is an extreme form of this style and well worth learning.

The Haskell IO monad is derived from the mathematical theory of (of course) monads. However, for imperative programmers, I think a backwards way of arriving at monads makes more sense.

Phase one - a pure functional language can easily return a big string value as its result. This big string can be the source code of an imperative program, derived in a pure functional way from some requirement-specifying parameters. You can then build a "higher level" compiler that runs your code generator, then automatically feeds that generated code into the imperative language compiler.

Phase two - rather than generating textual source code, you generate a strongly-typed abstract syntax tree. Your imperative-language compiler is absorbed into your "higher level" compiler, and accepts the AST directly as source code. This is a lot closer to what Haskell does.

This is still awkward, though. For example you have two distinct kinds of functions - those evaluated during the code-generating phase and those executed when the generated program is run. It's a bit like the distinction between functions and templates in C++.

So, for phase 3, make the two the same - the same function with the same syntax may be partially evaluated during the "code generation", or fully evaluated, or not evaluated at all. Further, discard all looping construct AST nodes in favor of recursion. In fact, discard the idea of AST nodes as a special kind of data altogether - don't have "literal value" AST nodes, just have values etc.

This is pretty much what the IO monad does - the bind operator is a way of composing "actions" to form programs. It's nothing special - just a function. Many expressions and functions can be evaluated during the "code generation", but those that depend on I/O side-effects must have evaluation delayed until run-time - not by any special rule, but as a natural consequence of the data dependencies in expressions.

Monads in general are just generalisation - they have the same interface, but implement the abstract operations differently, so instead of evaluating to a description of imperative code they evaluate to something else instead. Having the same interface means there are some things you can do to monads without caring which monad, which turns out to be useful.

This description will no doubt make purists heads explode, but to me it explains some of the real reasons why Haskell is interesting. It blurs the boundary between programming and metaprogramming, and uses the tools of functional programming to reinvent imperative programming without needing special syntax.

A criticism I have of C++ templates is that they are a kind of broken pure functional sublanguage in an imperative language - to evaluate the same basic function at compile-time rather than run-time you have to re-implement it using a completely different style of coding. In Haskell, while impurity must be labelled as such in its type, the exact same function may be evaluated both in a meta-programming sense and in a run-time non-meta-programming sense in the same program - there is no hard line between programming and metaprogramming.

That said, there are some metaprogramming things that standard Haskell can't do, basically because types (and maybe a few other things) aren't first-class values. There are language variants that try to address this, though.

A lot of things I've said about Haskell can be applied in impure functional languages - and sometimes even imperative languages. Haskell is different because you have no choice but to take this approach - it basically forces you to learn this style of working. You can "write C in ML", but you can't "write C in Haskell" - at least not without learning what's going on under the hood.

share|improve this answer

If a pure functional language is such, that only has pure functions (routines that don't have side effects), then it's a little pointless, because it cannot read input or write output ;)

Because this is really for learning, I think isolation isn't necessarily the way to go. Functional programming is a paradigm. It is important to understand which paradigms are suitable for which problems and more importantly, how they can best be combined.

I'm going to say it now: programming fashions are stupid and counterproductive. The only things that matter are that your program is short, easy to write, easy to maintain and works correctly. How you achieve this has nothing to do with programming fads. - Richard Jones

Other than that, if you're looking for "purity" you might want to have a look at Pure. Note however, the extreme ease of calling C routines makes it functionally unpure (but also very powerful).

share|improve this answer

Since learning is your goal, and not writing programs per se, you can't get any purer than Lambda Calculus.

Lambda Calculus was around before computers were invented. It took several skilled logicians working on it to figure out how to do subtraction (for a while it was theorized that only addition and multiplication were possible).

Learning how booleans and numbers and if can be invented from seemingly nothing won't put more gas in your tank, but it will make your tank much bigger.

share|improve this answer
    
Granted, there's probably no purer than that, but we're crossing the math barrier a little too much. I still want to practice programming and learn a new language while absorbing functional principles. Though, I agree that it might be interesting to study lambda calculus just for the sake of better understanding the foundations of the functional paradigm (and having a bigger tank). –  M. Joanis Dec 10 '10 at 17:03
1  
Writing a proof is writing a program and writing a program is writing a proof. When you learn the about the Curry–Howard isomorphism you'll realize you passed that math barrier ten thousand lines ago. –  Macneil Dec 11 '10 at 3:23
    
OK, now I'm confused. How can you have addition and multiplication but not subtraction? X - Y can be trivially composed from addition and multiplication as X + (Y * -1). –  Mason Wheeler Jun 14 '11 at 22:54
    
There's no simple representation of -1. –  Daniel Jun 14 '11 at 23:16
1  
@Mason Wheeler: λ-calculus alone doesn't have numbers, or really any sort of data besides lambda abstractions. Unless specified otherwise, anyone talking about numbers in λ-calculus probably means Church's encoding for natural numbers, where a number n is represented by n-fold function composition. That said, I'm dubious it was that much a struggle to figure out subtraction once someone actually tried; I worked it out on my own in an afternoon given only the definition of addition and knowledge that subtraction was possible. –  C. A. McCann Jun 15 '11 at 3:16

Erlang, Haskell, Scheme, Scala, Clojure, and F#

This question would probably best you help you in your search as well.

share|improve this answer
    
Thanks, interesting question indeed. I have started with PLT-Scheme/Racket, but I haven't looked at SICP yet... Real World Haskell looks pretty interesting to me too. –  M. Joanis Dec 10 '10 at 17:07
    
Scheme encourages a functional style, but it does have set! (among other things)... –  Daniel Jun 14 '11 at 23:18
    
I suggest OCaml, because it is my favorite. And it has a module system, which Haskell and F# miss. –  lukstafi Jul 5 '13 at 21:55

Not the answer you're looking for? Browse other questions tagged or ask your own question.