comp.lang.ada
 help / color / mirror / Atom feed
From: Hadrien Grasland <hadrien.grasland@gmail.com>
Subject: Re: Haskell, anyone?
Date: Mon, 16 Nov 2015 02:25:14 -0800 (PST)
Date: 2015-11-16T02:25:14-08:00	[thread overview]
Message-ID: <14533506-4289-4148-b8c4-e970f5778b26@googlegroups.com> (raw)
In-Reply-To: <c6ac0d2f-52af-4aa6-ba6f-34f61e3c93e8@googlegroups.com>

Le dimanche 15 novembre 2015 21:42:27 UTC+1, mockturtle a écrit :
> Dear all,
> I recently read in the Italian version of Linux Format an interview to Katie Miller.  It got me intrigued the fact that when she talks about Haskell, she says things that usually Ada enthusiasts say about Ada ("when it compiles, it runs...", "the number of bugs is reduced...").  I remembered that some time ago I met someone that was enthusiast both about Ada and Haskell (when I said that I program in Ada, he said something "Finally!  Now I need to find someone who likes Haskell."
> 
> The question should be obvious: it seems that Haskell and Ada would attract the same kind of person; does someone here know and like Haskell as well?
> 
> Riccardo

*** Rant warning, all FP fans please close your eyes for a second ***

I've been learning OCaml, a close cousin of Haskell, for about a month now, in an attempt to better understand functional programming's principles, benefits and drawbacks. Here are my thoughts so far :

Functional programming is based on the core tenet that mutable state is evil and should be obliterated. Indeed, in doing so, functional programming proponents make some good point : mutable state makes programs less predictable, less testable, and harder to understand. And by eliminating mutable state, functional programming also puts an end to an endless quarrel between programmers and mathematicians about the meaning of the "=" sign.

Now, that's for the theory. In practice, eliminating state also has strong negative consequences. For one thing, all useful programs have state. If a program does not display anything on the screen, does not write to any file, and in general does not command any external peripheral to *change state*, it is effectively a useless program which wastes CPU cycles for no good purpose. This means that in practice, all functional programmings always make some compromises in their war against mutable state. Typical abstractions include putting an imperative programming backdoor somewhere in the language, as in OCaml, or adding some abstract and opaque "state" type that functions take as a parameter and return as an abstract result.

======

A second problem with programming without mutable state is that if you cannot change your state, you will have to duplicate it, sometimes a lot. For example, consider a pseudo code which computes a running average :

"For all i such that 2 < i < N - 1, B[i] = A[i - 1] + A[i] + A[i + 1]"

Unless your programming language provides syntactic sugar for this specific scenario, you will have to fill in B's elements one by one. But because functional programs cannot change B once they have assigned a value to it, you will need to create a whole lot of copies of B, each with one element changed with respect to the previous one :

- A copy of B with its first element set
- A copy of B with its first and second element set
- A copy of B with its first, second and third element set
- and so on...

If B is big, this means a whole lot of memory traffic, and thus pretty awful performance. Unless, that is, the compiler is clever enough to optimize the copies out and effectively produce an imperative program. Which leads us to the second core tenet of functional programming : "The compiler and the user are both clever enough". This one is very strong, and is not without reminding the usual rethoric of C programmers : "If the user hits himself in the foot with pointers, he's not good enough to handle C".

======

Functional programming language designers' belief that users are genius becomes most obvious when one tries to perform simple tasks with these. For example, let us assume that we have some list of data that we want to display to the user. In any modern imperative language, this takes one to three very simple lines of code :

"For all elements E of A, display E"

In a functional programming program, loops are considered evil, because on their inside they hide some kind of mutable counter which goes against the idea of having no mutable state. So instead, you will often be forced to write something awful like this :

"let f : List a -> List =
.....if a is empty then
.........return empty list
.....else
.........display first element of a
.........return f(rest of a)"

Notice that this example is long, much more difficult to understand, and makes heavy use of recursion (and thus, assumes that the compiler will be clever enough to optimize it out). And if you have some fun, imagine what the functional programmer will have to get through if he has to write the "display" function at some point.

Also, I have cheated by using return statements. Functional programming does not have statements, because statements have some underlying mutable state to them (the program counter) and thus originate from the realm of Satan. To write any complex program in functional programming languages, you are expected to do everything using expressions. So if you have ever suffered the horror of debugging three nested trigraphs in C, imagine how a typical functional programmer feels when he has to debug this :

http://benchmarksgame.alioth.debian.org/u64q/program.php?test=pidigits&lang=ghc&id=4

======

In short, functional programming produces write-only code that pleases mathematicians and puts a lot of pressure on compiler writers. This classifies it as a programming style which is very much squarely aimed at people from academia. What about the claim that functional programs are always correct ?

In a further attempt to please code aesthetes, functional programming languages have very elaborate type inference systems, which are heavily (ab)used by most practitioners. The idea is that you should not have to repeat yourself by writing types over and over again if you already know them. Also, a type inference fan will add, this means that your programs will always get genericity for free : a program which adds floats, will probably also work with ints, and so on.

But there is a price to pay for type inference. And to understand which price, we have to look no further than the most successful implementation of type inference worldwide, C++ templates.

Whenever someone passes the wrong parameter to a C++ template library, that person is inundated by a wall of compiler diagnostics, sometimes thousands of lines long, and full of library implementation details. The reason why this is the case is that because type inference is used througout the whole code hierarchy, compilers can only detect errors at the very bottom of it. The error then needs to bubble up the code and module hierarchy, accumulating an enormous amount of diagnostic noise along the way.

Decades of experience with full type inference suggest that it will always break software abstractions and result in incomprehensible compiler diagnostics, no matter how it is implemented. Which is why even the C++ people are now shifting away from it, adding some extra layers of type check to templates in a future version of the standard with "concepts".

It sounds like functional programmers still have that lesson to learn, however, as even though many FP languages support type annotations, I have yet to encounter real-world functional programs which take the time to use them properly.

======

Even when you have manage to get through unreadable compiler diagnostics and broken software abstractions, even when you do get a functional program with type inference to compile, you still are far from having perfect assurance that your program is incorrect. In fact, because your program is barely readable, as outlined above, you cannot even check it on a basic way by reading through it manually.

The great thing about FP, though, is that the resulting program will be much easier to test, precisely because it has little to no mutable state. But I'm not sure if all the pain you have to go through in order to reach this point is worth it.

======

Now, of course, as I mentioned on top, this post is rantish and I have made a couple of important simplifications. For example, I have ignored a very important piece of syntaxic sugar featured by most functional programming languages, the list comprehension.

A typical list comprehension which filters integer elements according to some criterion, then returns their successor, would look like this :

"[ FOR ALL elem IN source_list WITH filter(elem) DO elem + 1 ]"

Like any data-parallel abstraction, this programming language feature is very nice to use, and will result most of the time in code being simpler and the compiler doing the right thing. However, this only works for simple code that fits within the list comprehension's programming model, which is usually fairly limited. This is why I classify this feature as syntaxic sugar : it is usually not designed for maximum power, only for occasional convenience.

For example, my running average example couldn't be implemented with the list comprehension syntax above, because it is a gather operation, and not a map operation (it accesses multiple source indices). Few functional programming languages in the wild feature list comprehensions that support gather operations.

So, don't only read my somewhat negative opinion, nor that of the Haskell zealots who will try to handwave away all the problems of the functional programming model. Read many arguments and counter-arguments, try it yourself, see how you like it, which problems it fits best, and so on. This is programming we're talking about, after all :)

  parent reply	other threads:[~2015-11-16 10:25 UTC|newest]

Thread overview: 54+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-11-15 20:42 Haskell, anyone? mockturtle
2015-11-15 20:51 ` Paul Rubin
2015-11-15 20:53 ` Nasser M. Abbasi
2015-11-15 21:50 ` Mark Carroll
2015-11-15 22:11 ` mockturtle
2015-11-15 22:48   ` Nasser M. Abbasi
2015-11-15 23:05     ` Mark Carroll
2015-11-16  4:11       ` Paul Rubin
2015-11-16  5:17         ` Nasser M. Abbasi
2015-11-16  5:48           ` Paul Rubin
2015-11-16  5:59             ` Nasser M. Abbasi
2015-11-16  6:47               ` Paul Rubin
2015-11-16  8:45           ` Simon Wright
2015-11-16 14:38             ` Brian Drummond
2015-11-15 23:19     ` Jeffrey R. Carter
2015-11-16  9:36       ` J-P. Rosen
2015-11-16 18:14         ` Jeffrey R. Carter
2015-11-16  3:59   ` Paul Rubin
2015-11-16  8:33   ` Dmitry A. Kazakov
2015-11-16  9:33     ` mockturtle
2015-11-16  9:45       ` Paul Rubin
2015-11-16 10:25 ` Hadrien Grasland [this message]
2015-11-16 11:19   ` Simon Wright
2015-11-16 11:25     ` Hadrien Grasland
2015-11-16 13:59   ` G.B.
2015-11-16 20:24   ` Jeffrey R. Carter
2015-11-16 23:23   ` Paul Rubin
2015-11-17  8:26     ` Dmitry A. Kazakov
2015-11-17  9:10       ` Mark Carroll
2015-11-17 20:09         ` Dmitry A. Kazakov
2015-11-17 10:49     ` Hadrien Grasland
2015-11-17 12:01       ` G.B.
2015-11-17 16:43         ` Hadrien Grasland
2015-11-17 18:04           ` Paul Rubin
2015-11-17 21:42             ` Hadrien Grasland
2015-11-18  4:36               ` Paul Rubin
2015-11-18  8:48                 ` Hadrien Grasland
2015-11-18  9:23                   ` Paul Rubin
2015-11-18 10:44                     ` Hadrien Grasland
2015-11-18 11:02                       ` Dmitry A. Kazakov
2015-11-18 12:41                         ` G.B.
2015-11-18 23:06                       ` Randy Brukardt
2015-11-19  8:56                         ` Hadrien Grasland
2015-11-19  9:19                           ` Hadrien Grasland
2015-11-19 21:27                           ` Randy Brukardt
2015-11-24 12:03                           ` Jacob Sparre Andersen
2015-11-19  7:22                       ` Paul Rubin
2015-11-19  9:39                         ` Hadrien Grasland
2015-11-17 13:01       ` Thomas Løcke
2015-11-17 16:45         ` Hadrien Grasland
2015-11-18  0:11       ` Paul Rubin
2015-11-18  9:44         ` Hadrien Grasland
2015-12-06 12:59   ` David Thompson
2015-12-07  7:25     ` Hadrien Grasland
replies disabled

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox