Pros and cons of the functional paradigm and Haskell

Asked

Viewed 4,078 times

24

I saw that, clearly, the Functional Programming Stop is not at all famous in the world of programming 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 of 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 leave a clue, one of the arguments I heard the most from fans of the functional paradigm was: "Parallelism and threading in functional programming is almost trivial from so simple, while in other languages this is difficult, arduous and due to poor implementation only brings problems".

  • After your question, this one came up, it would be nice to reconcile the ideas, or leave the one more focused on Haskell itself: http://answall.com/questions/13372/programm_functional-e-programm-object-object-que-sao-e-quais-suas (not duplicate, only Inkei to cross-linking for interested parties)

  • 1

    @Bacco In my opinion, it is better to leave as separate questions. I don’t know enough about Haskell to answer, but I do know that he is quite different from the most "popular" functional languages (Lisp, F#) by his rather rigid type system (in addition to being "purely" functional - unlike Lisp, for example, which includes non-functional features). I mean, it’s not just about discussing functional characteristics - that can apply even to imperative languages, such as Python and Ruby - but rather to a language that does not run away from this paradigm even a millimetre.

  • Being "pure" and being "functional" are separate yet related concepts. This means, for example, that Scheme (a type of Lisp) is not "less" functional than Haskell, although only the latter is considered "pure". See http://stackoverflow.com/a/4382400/158074. But, in fact, Common Lisp is no longer considered a functional language, precisely because it admits the imperative style.

4 answers

19

To tell the truth, I think the term "functional programming" is not very precise, and I would prefer to separate Lisps from ML-style typed languages (Haskell, Ocaml, F#, etc). That said, to answer the question "why learn Haskell", I think it best to divide it into two parts.

  1. Functional programming in general

    One thing all functional languages have in common is how functions are first-category values: You can define functions within other functions (accessing function variables from the outside), define functions that receive other functions as parameter or that return functions... This is quite flexible and lets you write many things succinctly.

    Today, 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 the lack of anonymous functions, such as Java and C++ are finally including them. And since we’re talking about imperative programming, to tell you the truth, functional programming doesn’t have to be that different - you can write programs with a pretty imperative face if you use tail recursion (something equivalent to computed files).

  2. ML family languages (Haskell, Ocaml, etc)

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

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

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

    • Parametric polymorphism / Generics. Allows you to express precise types without having to upcasting and downcasting with an Object supertype.

    • Fined unions and "Pattern matching". It is possible to describe types with more than one case (for example, "integer or null value") and it is easy to write programs that deal with all these cases (Pattern matching is a mix of switch with unstructuring). This all avoids exceptions like Nullpointerexceptions, since the type of a nullable variable is not the same as a nonnullable 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 kind notes here and there to make the error messages more understandable.

  3. Haskell, specifically for

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

      • Quickcheck. Generates random inputs to your test cases automatically, based on function types.

      • Hoogle. Search Haskell’s standard library based on the types. An extremely fast and effective way to search for functions, if you know what you want them to receive and return but don’t know their name.

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

      • Haskell uses lazy evaluation, which makes it easy to define their own combinators and flow control structures. For a somewhat forced example, we can define

        meuIfThenElse 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 as well, since the two parameters ifTrue and ifFalse would always be evaluated, rather than a single being. You would need to explicitly wrap them in extra functions:

        function meuIfThenElse(cond, onTrue, onFalse){
            if(cond){ onTrue() } else { onFalse() }
        }
      
    • Due to lazy evaluation, Haskell ends up having to separate functional code without side effects from the code with side effects (which need 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 after you learn how it works it is very useful to have the type system marking which parts of the program can have side effects and which are pure. If a function is pure you can call it without having to worry about when it runs or whether it will change some instance variable of an object of yours.

  • 1

    This answer seems to me quite complete, except for one problem: Haskell definitely nay is part of the ML family! ML certainly had an influence on Haskell (and also on Nemerle and Scala, for example), but to say that they are part of the same family is excessive. See http://en.wikipedia.org/wiki/ML_%28programming_language%29 (in English).

  • @rsenna: I swear I’ve seen people using this terminology (after all, the type system and syntax are very similar) but I edited the answer to be clearer, just in case.

  • 1

    You yourself identify some of the major differences: 1) ML languages are by definition, impure, and the same does not happen with Haskell. 2) ML is ager, Haskell is Lazy. Haskell had sway of various languages: ML, Miranda, Scheme, and even Python. But it is a language different enough to be considered in isolation. If it is necessary to place it in a family, consider that it is the "matriarch" of a new one (to which some other languages already belong, such as the Frege for example) :).

12

Good answers have already been given, but there are still some questions left to be answered by the PO, which I will try to address here

What are the pros and cons of functional programming [in relation to parallelism and threading]?

The issue here is not so much the functional vs. imperative, but rather mutability vs. immutability.

Imperative languages tend to make great use of structures and objects mutable, with state change. A property of an object, encapsulated by a pair of methods get and set is an example of this.

This style of programming is usually simple, in an environment single-threaded, but gains orders of magnitude of complexity when considering multi-processed environments. For, if more than one process can read and change a variable, it is necessary to control the accesses simultaneous read and write to memory (through the use of semaphores, for example). And this control, because it is very complex, is also very susceptible to problems such as deadlocks, low performance and other implementation errors.

Functional languages tend to use only structures and objects immutable. This means that created objects are never changed again (if an information needs to be changed, it implies creating a new object, and do not change the old).

This style is much more expensive, from the point of view of memory consumption, but it has a great advantage: all the difficulties associated with memory reading and writing control cease to exist (but, of course, some new difficulties also arise).

Hence, in part, the predilection of functional languages for lists, because they are structures that can be easily manipulated, without giving up the immutability (it is possible to "add" an item to a list simply by creating a new "head" that points to the old list - that is, a new list object is created, but without having to copy the items from the old list to the new one, saving processing).

'Cause I should learn Haskell?

That’s a trick question, because I don’t think so that you should learn Haskell (at least not now)!

You (OP) don’t seem to have much knowledge about functional languages. And Haskell is for sure one of the most complex and difficult programming languages to learn. In addition to immutability, you would have to learn concepts such as lazyness, purity, type-classes, monads, monoids, transactional memory... And believe me, this is all the stranger than the fact that it’s functional. : P (In my opinion, it’s more or less like wanting to learn quantum physics, without having learned classical Newtonian physics: it’s possible, it’s just not sensible).

There are much more accessible options:

  • Scheme is a multi-paradigm Lisp language, suitable for students, that makes strong use of functional concepts, and is relatively easy to learn (if you ignore the parentheses).
  • Clojure is more of a Lisp dialect. Some claim that it is even more modern and more functional than Scheme, with the advantage of running on the JVM. Personally, I haven’t had the opportunity to learn Clojure in more depth, but it seems to be one of the most interesting languages to use today.
  • Scala is a language that I have professional experience with, and therefore can speak better. At first glance it looks a lot like Java and Ruby, but from "inside" you can see that it was very inspired by Haskell. It is not fully functional, and is far from pure, but is usually a good option for those who have experience in OOP languages like Java or C#. Libraries like the Lift (a web framework) also allows you to see, in practice, the advantages (and disadvantages) of functional style in areas typically dominated by traditional object orientation.
  • F# is, like Scala, another example of functional hybrid x objects. But F# "picks up heavier" on the functional side, for being a superset of Ocaml. It can also help to get the "prerequisites" needed to learn Haskell (for example, the computation Expressions of F# are monads, which in turn are very important to understand Haskell).

Apart from these, it is possible to use the main functional concept, first-class functions, in Ruby, Python and even C# (3.0+) and Java (8.0+).

  • 1

    I do not know if I agree that Haskell is hard to learn. For those who want to learn Haskell and can read English there is the Learn you a Haskell which is excellent. In Portuguese there is the "Haskell: A practical approach" and other books. The basics of the language are quite simple, but the advanced parts of the language are really difficult. But I would say the same for C++. The biggest difference for me is that Haskell doesn’t have much learning material, it’s harder to find someone to answer your questions, etc.

  • @Darque: there is not much to argue here, since we are dealing only with opinions. But I think you can objectively disagree on one point with what you said: that only the "advanced parts" of Haskell are really difficult. No, Haskell can’t be accused of being unequal, she’s equally difficult at all. : ) Nothing is more basic, perhaps, than I/O, but compare the way of doing I/O in C++ and Haskell: it is possible to do I/O in C++ without even knowing what a template or class is; but it is not possible to do I/O in Haskell without knowing, at least superficially, what is a monad.

  • Dude, Java doesn’t have first-class functions. All that is in it are functional interfaces: Interfaces with only one method, and it is very common to use the interface as a utility to simulate procedures alone. But this is a verbiage, hard to maintain and inflexible solution: A delegate in C# can receive a method with any number of parameters, a functional interface in Java will always have its internal method with the same signature.

  • @Sid huh? Are you sure you’re responding to the right person?? : Q I barely spoke of Java in my answer!! (5 min later) Ah understood, it’s about the end. You’re outdated: Java 8 has first-class functions (but the version I pointed out was wrong; Ambdes Expressions were introduced in version 8, corrected).

  • @rsenna I was responding to yourself, haha. Is that at the end you said that Java 8 has first-class functions. Dude, are you sure he has? These Java 8 Expressions for me are kind of like syntactic sugar for anonymous classes. And even if in Java 8 every method that fits into an interface within java.util.Function is automatically referenced as an interface that implements such a thing, it still doesn’t fit within the first-class Function definition, it’s not?

  • @rsenna and as I said before, in Javascript and C# you can always reassign the function-object with different signature functions. In Java, functional interfaces hold your original signature and working with this kind of thing is strange, despite solving thousands of headaches and problems you have in Java, such as the need to pass procedures to a method.

  • @Sid okay, I got it. About Java being "syntactic sugar": what you’re saying makes perfect sense, but I don’t think it alone "belittles" the Java implementation. A lambda in Java is a first-class Function, since it is an object; it is also a closure, since it retains the referenced "free-variables". If in the end this generates an anonymous class, patience. By the way, Both of which refer to free-variables are treated very similarly in C#.

  • @sid (cont.) What you said about functional interfaces is much more important, in my opinion. In fact, it seems to be a very large limitation, when compared to the way we use Flaps in C#. It seems to me that it is possible to minimize this problem through Casts, but I’m not sure (I work with C# and Scala, but my experience with Java is much more limited).

  • So I prefer to conclude that ultimately, Java 8 has no real first-class functions. And one of the things that enrages me the most in Java is just this: The slowness that language has to acquire Features present in other languages. However it is a language where thanks to the almost zero presence of constructions that require symbols, it is easy to write readable code in this language, although more laborious.

  • And at the end of the day, are all these "pussies" really necessary? I say: C remains practically the same for more than 30 years and even today does his work with mastery. And it needs to stay that way because it is not possible to add Features to the C that create a considerable overhead. And even if C doesn’t have OOP, closures, Amblas, GC and so on, it’s still possible to simulate much of it (mostly OOP) and do things the way they should be done.

  • @Sid Your quotes are correct, but your conclusions don’t always make sense. Opinions we all have, let’s stick to the facts, okay? Java is different from C#, Scala and other languages, and it better be that way. It’s good to have a choice, because programming languages are for humans. Machines only need binary code. Everything else is "freshness", be it first-class functions, classes or passing parameters by stack. But it is this "freshness" that really matters, at least for us programmers.

Show 6 more comments

7

I will not guarantee that I will answer your question with the excellence you expect.

First of all, you can never learn something new. To tell you the truth, it’s healthy to get out of the comfort zone. Getting out of it will always make us come back better than when we left.

One thing is to apply this kind of paradigm to the market that is totally dominated by OOP, Web and Mobile. This can be a barrier, since most IT companies work with rice beans (CRUD, small screen that pulls data from here, print report from there...).

A very positive point of functional programming is the possibility of working with lists and performing absurd calculations by writing very little code. We do a lot of writing very little, I think that’s one of the strongest points of this type of language.

Finally, we are in the age of integration. There are no barriers that will prevent you from integrating Haskell with another market language. Today for everything there is a way. :)

I hope I’ve helped.

  • By the way, what are lists in functional programming? I have seen this term constantly but never understood it completely. Lists just a way to represent a data structure in these languages? Like C structs and OOP objects?

  • 3

    @Sid, so there’s a question for that and not an account, right?

  • @Sid the Haskell lists are basically linked lists, one of the data structures that are easy to translate from imperative paradigm to functional.

0

Browser other questions tagged

You are not signed in. Login or sign up in order to post.