comp.lang.ada
 help / color / mirror / Atom feed
From: Paul Rubin <no.email@nospam.invalid>
Subject: Re: Haskell, anyone?
Date: Mon, 16 Nov 2015 15:23:16 -0800
Date: 2015-11-16T15:23:16-08:00	[thread overview]
Message-ID: <87si45msuz.fsf@nightsong.com> (raw)
In-Reply-To: 14533506-4289-4148-b8c4-e970f5778b26@googlegroups.com

Hadrien Grasland <hadrien.grasland@gmail.com> writes:
> *** Rant warning, all FP fans please close your eyes for a second ***

I peeked ;).  The post is full of errors and misconceptions that might
clear up with more experience.

> Functional programming is based on the core tenet that mutable state
> is evil and should be obliterated.

Ermph, that's an overstatement, I'd say that the tenet is to separate
effects from denotational values.  State mutation (like i/o) is
considered an effect so FP tries to use it sparingly.  But Ocaml has
reference cells whose contents you can write to in ordinary expressions,
and Haskell has cells you can access with i/o-like actions, plus ways
to thread state through purely functional code.  

> in practice, all functional programmings always make some compromises
> in their war against mutable state.

We would say in Haskell that the Haskell program computes a pure value
called an i/o action (e.g. an action that prints something) and the
runtime then executes the action.

> "For all i such that 2 < i < N - 1, B[i] = A[i - 1] + A[i] + A[i + 1]"
> - A copy of B with its first element set
> - A copy of B with its first and second element set...

No of course you wouldn't do anything like that.  An idiomatic Haskell
two-liner if A is a list would be

    b = zipWith2 add3 a (tail a) (tail (tail a)) where
      add3 x y z = x+y+z

or you could write something similar using recursion.  For immutable
arrays, you'd use toList and fromList in combination with something like
that.  There are also mutable array types which would let you write an
imperative-looking loop.

> "The compiler and the user are both clever enough". 

It's true that there are FP idioms you have to get used to if you're
coming from imperative programming.

> "For all elements E of A, display E"
> In a functional programming program, loops are considered evil,

Typcally you'd write something like "mapM_ display a" which is
Haskell for running the display action over all the elements of a.
You don't even need that intermediate variable E cluttering your code.

> "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,

That doesn't look like Ocaml to me, but I don't know Ocaml that well.
The Haskell implementation if you didn't want to use mapM_ would be:

   f :: [a] -> IO ()
   f [] = return ()
   f (x:xs) = display x >> f xs

which is probably shorter than comparable imperative code.  Note that
the type annotation (first line) is not required, since the compiler can
figure it out if you omit it.

> 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

I'd say that code has been golfed a bit (since one of the benchmark
metrics is how short the code is) and also has a few speed optimizations
that clutter things a little, but it is fairly straightforward Haskell,
and the main obstacle to debugging is probably understanding the
algorithm.  I'd guess that the sub-expressions were written and tested
separately before being combined to that big function.  That's not so
safe in imperative coding since the side effects of the different
sub-expressions could interfere when you combine them.  But it's less of
a problem in FP code that has no side effects.

The Ada equivalent is here:

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

It's 5x-10x as much code, depending on how you count.  It's a pretty
safe bet that the Haskell version took less time to code and debug.

> What about the claim that functional programs are always correct ?

That's silly, there's no such claim.  There's a justified claim that FP
makes it easy to avoid certain classes of bugs that happen all the time
in imperative programs, but that's much weaker.  You can also use FP
techniques in imperative programming to avoid some of those bugs, and I
do that all the time these days.  That's why I think it's worth learning
some FP even if you real work uses imperative languages.

> 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,

Oh that's way overblown, those awful diagnostics are because C++
templates are basically glorified macros and C++ does a lot of automatic
type coercions (like adding int to float gives float), bloating the
number of combinations of type assignments in a big expression.  GHC's
error messages can be messy and hard to understand, but it's nothing
like C++ template errors.  GHC messages are often "error at line 145,
blah blah blah blah [long-winded traceback]" where the blah blah blah
isn't that informative, but the line number is usually accurate, so you
just look at line 145 and figure out what is wrong (that takes some
experience, I admit).  Haskell has no automatic conversions (int plus
float is a type error), which simplifies things too.

> 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. 

It's not exactly like that, it's a unification algorithm so it's like
discovering that a crossword puzzle has no solution.  I've been told
that ML/Ocaml programs are still ok relying on inference since ML's type
system was historically simpler than Haskell's.  Haskell programmers
generally will write annotations (polymorphic ones when appropriate) on
top-level functions, while usually letting the compiler infer types for
the stuff inside the functions.

> 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".

That idea (bounded polymorphism aka type classes) has been in Haskell
since forever, and the idea is to make the types more precise, not
particularly to clean up error messages.

> 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.

Just what real-world functional programs have you looked at?  Again I
know that Ocaml programs tend to use less of them than Haskell programs
but that's because they're of apparently less benefit in Ocaml.

> 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.

I've generally found it easier to code stuff in Haskell than in
low-level imperative languages, because of the higher abstraction,
shorter code, and larger amount of runtime services integrated with the
language.  The main cost is that the Haskell code runs slower and uses
more memory, but it still suffices for lots of things.

> For example, my running average example couldn't be implemented with
> the list comprehension syntax above, because it is a gather operation,

   averages = [x+y+z | x:y:z:_ <- tails a]

works for me.  Maybe that's nicer than the zipWith2 version I gave
earlier.

> 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. 

The problem isn't that your opinion is negative, it's that it's
uninformed.  There are some well-informed critiques of Haskell around
including Bob Harper's (he's a designer of SML and rails against Haskell
all the time) and Ben Lippmeier's (he designed a language called
Disciple that tries to address what he sees as Haskell shortcomings,
that is quite interesting).  But I think you've only taken a superficial
look at the topic and come away with some strong opinions that aren't
validly grounded in facts.


  parent reply	other threads:[~2015-11-16 23:23 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
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 [this message]
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