Pure Functions

Contents[Show]

Pure functions are quite similar to mathematical functions. They are the reason that Haskell is called a pure functional programming language.

 

Pure functions

CharakteristikPureFunctionsEng

I compare in the table pure and impure functions.

PureImpureFunctionsEng

 

Pure functions have a crucial drawback. They can not communicate with the outside world. Because functions for input and output, functions for building a state, or functions for creating random numbers can not be pure. The only effect that a pure function can have is according to Simon Peyton Jones to warm up the room. Haskell solves this dead-end by embedded impure, imperative subsystems in the pure functional language. These imperative subsystems are called monads. I will write more about monads in a few seconds.

What is the story of purity in C++? This story is based - similar to Immutable Data - on the discipline of the programmer. I will present in the following program a function, a meta-function, and a constexpr function. All three are pure functions.

 

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// pureFunctions.cpp

#include <iostream>

int powFunc(int m, int n){ 
  if (n == 0) return 1; 
  return m * powFunc(m, n-1); 
}

template<int m, int n>
struct PowMeta{
  static int const value = m * PowMeta<m,n-1>::value;
};

template<int m>
struct PowMeta<m,0>{
  static int const value = 1;
};

constexpr int powConst(int m, int n){ 
  int r = 1;
  for(int k=1; k<=n; ++k) r*= m;
  return r;
}

int main(){
  std::cout << powFunc(2,10) << std::endl;               // 1024
  std::cout << PowMeta<2,10>::value << std::endl;        // 1024
  std::cout << powConst(2,10) << std::endl;              // 1024
}

 

Although the three functions give the same result, they are completely different. powFunc (line 5 - 8) is a classical function. It will be executed at the run time of the program and can get non-constant arguments. On contrary, PowMeta (line 10 - 18) is a meta-function that is executed at the compile time of the program. Therefore, PowMeta needs constant expressions as arguments. The constexpr function powConst (line 20 - 24) can run at compile time and at run time. To be executed at the compile time, powConst needs - accordingly to the meta-function PowMeta - constant expressions as arguments.

And now to something completely different. I will introduce in the next section monads. I will refer to this first definition of monads in later posts and I will show you examples of monads in future C++: std::optional in C++17, the ranges library from Eric Nieber in C++20, and the extended futures in C++20.  But now, I'm talking about the future concept in C++. Or, to say it in the words of Bartosz Milewski: I See a Monad in Your Future.  I strongly encourage you the read the post or watch his video.

Monads

Haskell as a pure functional language has only pure functions. The key of these pure functions is that they will always give the same result when given the same arguments. Thanks to this property which the name referential transparency a Haskell function can not have side effects. Therefore, Haskell has a conceptional issue. The word is full of calculations that have side effects. These are calculations that can fail, that can return an unknown number of results, or that are dependent on the environment. To solve this conceptional issue, Haskell uses monads and embeds them in the pure functional langue.

The classical monads encapsulate one side effect:

  • I/O  monad: Calculations that deal with input and output.
  • Maybe monad: Calculations that maybe return a result.
  • Error monad: Calculations that can fail.
  • List monad: Calculations that can have an arbitrary number of results.
  • State monad: Calculations that build a state.
  • Reader monad: Calculations that read from the environment.

The concept of the monad is from the category theory. The category theory is a part of the mathematic that deals with objects and mapping between the objects. Monads are abstract data types (type classes), which transform simple types into enriched types. Values of these enriched types are called monadic values. Once in a monad, a value can only be transformed by a function composition in another monadic value.

This composition respects the special structure of a monad. Therefore, the error monad will interrupt its calculation, if an error occurs or the state monad builds its state.

To make this happen, a monad consists of three components:

  1. Type constructor: The type constructor defines how the simple data type becomes a monadic data type.
  2. Functions:
    • Identity function: Introduces the simple value into the monad.
    • bind operator Defines how a function is applied to a monadic value to get a new monadic value.
  3. Rules for the functions:
    • The identity function has to be the left and the right identity element.
    • The composition of functions has to be associative.

     

In order for the error monad to become an instance of the type class Monad, the error monad has to support the identity function and the bind operator. Both functions define how the error monad deals with an error in the calculation. If you use error monad, the error handling is done in the background.

A monad consists of two control flows. The explicit control for calculating the result and the implicit control flow for dealing with the specific side effect.

A few months ago, after I published this post in German a reader said: Hey, the definition of a monad is quite simple. "A monad is just a monoid in the category of endofunctors."  I hope you get it.

What's next?

Pure functional languages have no mutable data. Therefore, they use recursion instead of loops. So you know, what the next post will be about.

 

 

 

 

Thanks a lot to my Patreon Supporters: Matt Braun, Roman Postanciuc, Tobias Zindl, Marko, G Prvulovic, Reinhold Dröge, Abernitzke, Frank Grimm, Sakib, Broeserl, António Pina, Sergey Agafyin, Андрей Бурмистров, Jake, GS, Lawton Shoemake, Animus24, Jozo Leko, John Breland, espkk, Louis St-Amour, Venkat Nandam, Jose Francisco, Douglas Tinkham, Kuchlong Kuchlong, Robert Blanch, Truels Wissneth, Kris Kafka, Mario Luoni, Neil Wang, Friedrich Huber, lennonli, Pramod Tikare Muralidhara, Peter Ware, Tobi Heideman, Daniel Hufschläger, Red Trip, Alexander Schwarz, Tornike Porchxidze, Alessandro Pezzato, Evangelos Denaxas, Bob Perry, Satish Vangipuram, Andi Ireland, Richard Ohnemus, Michael Dunsky, Dimitrov Tsvetomir, Leo Goodstadt, Eduardo Velasquez, John Wiederhirn, Yacob Cohen-Arazi, Florian Tischler, Robin Furness, and Michael Young.

 

Thanks in particular to Jon Hess, Lakshman, Christian Wittenhorst, Sherhy Pyton, Dendi Suhubdy, Sudhakar Belagurusamy, Richard Sargeant, and Rusty Fleming.

 

 

My special thanks to Embarcadero CBUIDER STUDIO FINAL ICONS 1024 Small

 

Seminars

I'm happy to give online seminars or face-to-face seminars worldwide. Please call me if you have any questions.

Bookable (Online)

German

Standard Seminars (English/German)

Here is a compilation of my standard seminars. These seminars are only meant to give you a first orientation.

New

Contact Me

Modernes C++,

RainerGrimmSmall

Comments   

0 #1 Maran Pakkirisamy 2017-01-31 11:18
At the last line, did you mean to say,
"Pure functional languages have no MUTABLE data."?
Quote
+1 #2 Rainer Grimm 2017-02-01 07:52
Quoting Maran Pakkirisamy:
At the last line, did you mean to say,
"Pure functional languages have no MUTABLE data."?

Thanks. I will fix it.
Quote

My Newest E-Books

Course: Modern C++ Concurrency in Practice

Course: C++ Standard Library including C++14 & C++17

Course: Embedded Programming with Modern C++

Course: Generic Programming (Templates)

Course: C++ Fundamentals for Professionals

Interactive Course: The All-in-One Guide to C++20

Subscribe to the newsletter (+ pdf bundle)

Blog archive

Source Code

Visitors

Today 1792

Yesterday 8162

Week 18662

Month 136864

All 7404704

Currently are 168 guests and no members online

Kubik-Rubik Joomla! Extensions

Latest comments