Is Haskell or Scala a better language

Tech blog

"Functional programming has no relevance in practice: it is only used by academics to polish up their papers at universities". Functional programming was often ridiculed with such statements. However, I believe that just being aware of functional programming can make us better developers. With this article I would like to invite you to look outside the box.

Classification of functional programming

Basically, we developers all want the same thing: Solving problems! To do this, we usually tell the computer what to do. We call it imperative programming: "Increment the number in the memory location i. "" Give me memory for 20 numerical values ​​of length long. "" Iterate over all objects in the list Customers and remove empty entries. "" ... "

As an alternative to this style or paradigm, there are declarative programming styles. To solve a problem declaratively, we describe the solution and let the computer find a suitable way. Functional programming is a type of declarative programming in which the solution to a problem is described by functions that a computer then solves for us. The mathematician Alonzo Church laid the foundation for functional programming in 1930 with the lambda calculus, a formal language for investigating functions. So the approaches are not that modern at all ...

Functions vs. Methods vs. Procedures

There is much confusion and controversy about the differences between these programmatic means (see Function vs. Method and Function vs. Procedure). I distinguish them as follows: Methods are a means of object orientation and always belong to a class or an instance, whereas functions and procedures can stand on their own.

What then distinguishes procedures from functions? Functions always have a return value, procedures never. It is immediately clear that procedures are only useful if they influence the system status (spoiler: by a side effect). Functions are not allowed to do that. Examples include:

  1. class Incrementable {
  2. privateint x;
  3. // method (with side effect)
  4. publicint inc () {
  5. return x ++;
  6. // method (without side effect)}
  7. publicint inc (int x) {
  8. return x + 1;
  9. // procedure (with side effect)
  10. void increment () {
  11. int inc (int x) {
  12. return x +1;

What makes a programming language functional?

From my point of view, there are two things that make a programming language functional. First, Functions are first-class citizens, that means: Functions can be assigned to variables just like other values, passed as parameters and are possible return values ​​of methods or other functions. When functions receive or return functions other than parameters, they are also referred to as higher-order functions (higher order functions).

Second: Avoiding or encapsulating a changeable state and side effects, for example through immutable data types and monads. A language like Haskell avoids all side effects or safely encapsulates them through certain mechanisms such as monads. This is why Haskell is called purely functional designated. That means programming without assignment, exceptions and loops and and and.

Can you still write meaningful programs at all? Yes! Because I'm a Haskell noob and I tend to be with functional style programming languages a la ClojureScala, Java and C # know my way around, I dedicate myself to these here. These languages ​​support the functions as first-class citizens as well as immutable data types and thus enable the use of the most important concepts of functional programming.

Benefits of functional programming

Deal with the system state

The first argument in favor of functional programming is often the minimization of problems with mutable global state listed. The mutable global state is not not correct in itself, but it makes it difficult to keep an eye on all changing actors and to ensure consistency as the system grows. This means that programming errors creep in extremely quickly.

Why is that? Global and changeable resembles a "law-free zone", because you can read and write from anywhere in the system; Status means: set of values ​​at a certain time. The combination of both creates invisible semantic dependencies between many parts of the system. The effects then only show up at runtime and no longer at development time.

If we are honest, however, this changing global state can be found in almost every system that we or others develop with Java and Co. Every programmer who has worked with threads and written their own locking mechanisms knows how dangerous it is mutable global state is. And who does not know the problem of having to transfer an entire system to a certain state for the simple unit test of a method, since the result of this method depends on the state of the rest of the system. Compared to Java, C # and Co., "more functional" languages ​​such as Clojure and Haskell offer mechanisms to better deal with the system state. These include, among other things immutable datastructures, software transactional memory and Monads (e.g. state monad). Rich Hickey, who created the Clojure programming language, sums up the topic State pretty well put together: "State - You're doing it wrong".

Glue for software

Functional programming also offers two new types of Glue can be configured with the software (John Hughes). In object-oriented programming, we often make use of design patterns such as Strategy, Template, Command, etc .: Who does not know the Gang of Four. These design patterns enable established solution strategies to be reused to solve our domain-specific problems. With these strategies we implement the problem solutions through objects and their communication with each other. Such reuse also exists in the functional world, but on a lower level. Since we mostly only use existing data types (list, map, set) for our problems there, the solutions arise, for example, through given functionality (iteration, filter, transformation) for these data types, which is enriched with problem-specific behavior ("filter all men under 25 "," multiply each number by 2 "). Such an adhesive are functions of a higher order, the higher order functions. In addition to simple data, this type of function can also receive or return blocks of logic (functions) (see,, ...). Mario Fusco shows in his lecture [g ∘ f patterns] how easy it is to simplify many Gang of Four design patterns by using higher-order functions. As an example, this should give us this Strategy Pattern serve:

  1. Function toUpperCase =
  2. text -> text.toUpperCase ();
  3. Function inBrackets =
  4. text -> "[" + text + "]";
  5. BiFunction , String> format =
  6. (text, strategy) -> strategy.apply (text);
  7. format.apply ("Watch out!", toUpperCase); // WATCH OUT!
  8. format.apply ("Functional Style Rocks", inBrackets); // [Functional Style Rocks]
  9. format.apply ("Another one", text -> text + "..."); // Another one ...
  10. </string,function<string,string></string,string></string,string>

With the second component gluelazy evaluation you can describe calculations that are only carried out when they are really needed - and only then. This allows functions to be linked in an efficient way. Here is a small example:

  1. // endless stream of even numbers stream
  2. evenNumbers = Stream.iterate (2, n -> n +2);
  3. .limit (5)
  4. .collect (Collectors.toList ()); // <2,4,6,8,10>

Streams in Java 8 are inherent lazy. They make it possible to define infinite sequences of data. Since these are only evaluated when it is really necessary, they are called LazySequences. In this example we define the infinite sequence of natural, even numbers (evenNumbers) as a stream using Seed or initial value and UnaryOperator or construction rule for further elements. This stream is "lazy", since at this point we have only described how this stream is can be calculated. These values ​​are only calculated when a special function is used in the Java environment terminal operation wants to consume at least one of these values ​​(in this case). The consuming function collect and the generating function evenNumbers were cleverly "glued" together here. Clever because the producer only generates results when the consumer needs them. Languages ​​like Scala, Clojure and Haskell support lazyness much better than Java, which is why this functional means is used much more there.

Pure functions are honest!

Functions, without side effects (eng. pure functions), map certain inputs to certain outputs. No more and no less. In this context, referencial transparency is also used, which means something like "an expression can be replaced by its result". At every point in the system where a function is called with the same parameters, it returns the same value. This means that functions can be viewed independently of the rest of the system. This simple property enables better testability, simplifies understanding and facilitates maintenance / further development of the system. Here is another small example:

  1. // referential transparent
  2. int increment (int x) {
  3. return x +1;
  4. int six = increment (5);
  5. int incrementByCurrent (int x) {
  6. current = current + x;
  7. return current;
  8. int something = incrementByCurrent (5);

Every call of a function can be replaced by its result at all points in the entire program (e.g. is always the same). This does not apply to, because the result of e.g. depends on all previous calls to this method and thus the result of the call can often be determined at runtime (debugging). In addition to the advantages mentioned, referential transparency also enables the performance optimization memoization. The calculated results of a function are temporarily stored. When it is called up again with the same parameters, the result can then be returned immediately.

Functional programming in practice

In this part I would like to go into how functional approaches can be integrated into our development day.

This integration is not primarily about technologies or language features, it is about rethinking certain situations (functional thinking). I would like to do this using Java Version 8. Most of the examples can be translated into other languages ​​and can usually be implemented there more elegantly. In Java 8 several innovations from the functional programming were included. Including the Streams, Lambda Expressions and functional interfaces. Streams simplify the processing of collections of data through higher-order functions (map, filter, reduce).

  1. List
    verfUndRedu = new ArrayList
    ();
  2. for (Item Item: All Item) {
  3. if (article.isavailable ())
  4. if (article.isRabbatiert ())
  5. availableUndReduced.add (article);
  6. // functional approach through the use of streams
  7. List
    verfUndRedu = allArtikel.stream ()
  8. .filter (Article :: isRabbated)
  9. .filter (Article :: isavailable)
  10. .collect (Collectors.toList ());
  11. </artikel></artikel></artikel>

Lambda expressions are a powerful extension of the language to include anonymous functions. Since Java 8, interfaces with only one method are considered functional interface and can be easily implemented using a lambda expression. A nice example of the combination of lambda expressions and functional interfaces offers the creation of threads:

  1. publicvoid run () {
  2. Price.calculate ();
  3. // Lambda Expression to implement a functional interface
  4. Thread t = newThread (() -> Price.calculate ());
  5. // Method Reference for the implementation of a functional interface

Runnable has been a Java 8 since functional interface and can thus be implemented directly using a lambda expression or a method reference. This makes the code much more readable.

Recursion, as a functional equivalent to loops, often enables a more intuitive description of the solution and in many cases can increase the readability of our code. Let's take a look at two variants to output all files in a given path:

  1. publicstaticvoid printFiles (String curPath) {
  2. Stack fileStack = new Stack ();
  3. fileStack.push (newFile (curPath));
  4. while (! fileStack.empty ()) {
  5. File currentFile = fileStack.pop ();
  6. if (currentFile.isDirectory ()) {
  7. for (File f: currentFile.listFiles ())
  8. fileStack.push (f);
  9.             }
  10. else
  11. System.out.println (currentFile);
  12. printFiles ("C: /");
  13. // by recursion and higher order function
  14. publicstaticvoid consumeFiles (String curPath, Consumer fn) {
  15. File curFile = newFile (curPath);
  16. if (curFile.isDirectory ()) {
  17. for (File child: curFile.listFiles ())
  18. consumeFiles (child.getAbsolutePath (), fn);
  19. fn.accept (curFile);
  20. consumeFiles ("C: /", f -> System.out.println (f.getName ()));
  21. </file></file></file>

The second variant is not only more readable but also more versatile: It uses a higher-order function that only takes care of the interaction via files. The behavior per file is passed as a parameter, which allows full flexibility for the user of the function. Even if there are countless other application examples for functional programming, I would like to close this section here to give an outlook.

Functional or object-oriented?

In most cases, I think it makes little sense to develop software in a purely functional or purely object-oriented manner. Each paradigm has its strengths and thus a right to exist. In my opinion, object orientation shows its strengths in the structuring or architecture of systems. Normally, our problem domains are characterized by nouns that can easily be mapped into classes and instances. Functional programming, on the other hand, has its strengths in the processing of data, concurrency and complex mathematical calculations. In these areas, functional code is often more concise, easier to read, less error-prone and easier to test.

In order to move a little in the direction of the functional style in the Java world, I can recommend the Vavr library. It offers a clean implementation of interfaces for functions (lambdas), better streams, immutable data types (with map, filter and reduce without streams), better implementation of optionals (serializable), the data type tuple and much more. For interested developers, it is also worth taking a trip to the functional style programming languageClojure. It is not for nothing that the designer of the language, Rich Hickey, is praised by many greats in the development scene, such as Robert C. Martin, for his good ideas and his ease of implementation in this language. Clojure offers everything that is necessary for writing software that is ready for the market (see the example in Otto's blog) and also has an extremely simple syntax - one slide is sufficient for an explanation. Even without the daily use of functional programming, it is worthwhile to understand this different approach and to include it as an additional tool in your developer toolbox.

Tweet Share Share on LinkedIn