functional-programming – Pros and cons of the functional paradigm and the Haskell

Question:

I saw that, clearly, the Functional Programming paradigm is not at all famous in the programming world in general. However, talking to a few fans of languages ​​like Lisp, Ocaml, F#, Haskell, etc. I saw arguments that almost convinced me to learn the purely functional language that seems to be the most influential and popular at the moment: Haskell.

So the question is fundamentally this: What are the pros and cons of functional programming? What are the pros and cons of Haskell? Why should I learn Haskell?

Just to give you a hint, one of the arguments I heard the most from fans of the functional paradigm was: "Parallelism and threading in functional programming is almost trivial because it's so simple, while in other languages ​​it's difficult, arduous and due to poor implementation only brings problems".

Answer:

As a matter of fact, I think the term "functional programming" is not very accurate, and I would prefer to separate Lisps from ML-style typed languages ​​(Haskell, Ocaml, F#, etc). That said, to answer the "why learn Haskell" question, I think it's best to split it into two parts.

  1. Functional programming in general

    One thing all functional languages ​​have in common is the way functions are first-rate values: You can define functions inside other functions (accessing function variables from the outside), define functions that take other functions as a parameter, or that return functions… This is quite flexible and allows you to write a lot of things succinctly.

    These days, this point of functional programming is no longer such an important distinction, as many "imperative" languages ​​have first-class functions, and even languages ​​notable for their lack of anonymous functions such as Java and C++ are finally including them. And since we're talking about imperative programming, to be honest, functional programming doesn't even have to be all that different – you can write programs with a very imperative face if you use tail recursion (which is equivalent to computed gotos).

  2. Languages ​​of the ML family (Haskell, Ocaml, etc)

    The most unique factor about Haskell and its primal languages ​​(Ocaml, F#, etc) is certainly the type system, extremely powerful and flexible, but still relatively easy to use. I would say that it's worth learning a language like that just for that. Some of the most important points:

    • The type system is completely static. Many errors that are caught at runtime in other languages ​​are caught at compile time in Haskell.

    • Variables will always be initialized (it is not possible to access an uninitialized variable).

    • Parametric polymorphism / generics. Lets you express precise types without having to upcast and downcast with an Object supertype.

    • Tagged unions and "pattern matching". It is possible to describe types with more than one case (eg "integer or null value") and it is easy to write programs that handle all of these cases (pattern matching is a mixture of switch and destructuring). This all avoids exceptions like NullPointerExceptions, as the type of a nullable variable is not the same as the type of a non-nullable variable.

    • Type inference is powerful and if you want you can write any program without using any type annotations, which avoids hassles like MyClass myClass = new MyClass . That said, it's still a good idea to put some type annotations here and there to make error messages more understandable.

  3. Haskell, specifically

    • Haskell is one of the functional languages ​​with the most active community. It will be easier to find documentation, libraries and introductory books for Haskell. In particular, Haskell has some really cool libraries, which are not common in other languages:

      • Quickcheck . Generate random entries for your test cases automatically, based on the types of functions.

      • Hoogle . Searches the standard Haskell library based on types. An extremely fast and efficient way to look up roles if you know what you want them to get and return but don't know their names.

      • Parser Combinators . A flexible way to write your own parsers but one that would be difficult and ugly to implement in conventional languages.

      • Haskell uses lazy evaluation, which makes it easy to define your own combiners and flow control structures. For a slightly far-fetched example, we can define

        myIfThenElse cond ifTrue ifFalse = if cond then ifTrue else ifFalse

      In Haskell, this function behaves exactly like an if. In a language with strict evaluation, this function would not work so well, as the two parameters ifTrue and ifFalse would always be evaluated, instead of a single being. You would need to explicitly wrap them up in some extra functions:

       function meuIfThenElse(cond, onTrue, onFalse){ if(cond){ onTrue() } else { onFalse() } }
    • Due to lazy evaluation, Haskell ends up having to separate working code without side effects from code with side effects (which needs to be executed in a precise order). A lot of people find this confusing at first (having to use monads to print and read values) but once you learn how it works it's pretty useful to have the type system checking which parts of the program might have side effects and which ones are pure. If a function is pure you can call it without having to worry about when it runs or if it will change some instance variable of your object.

Scroll to Top