add pure-functions/index.md (#32887)
A description of the important of pure functions and their limitations in Erlang
This commit is contained in:
committed by
Quincy Larson
parent
d44441d6cb
commit
a8e05e25a3
102
guide/english/erlang/pure-functions/index.md
Normal file
102
guide/english/erlang/pure-functions/index.md
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
---
|
||||||
|
title: Pure Functions
|
||||||
|
---
|
||||||
|
|
||||||
|
## Pure Functions
|
||||||
|
|
||||||
|
The concept of 'pure functions' is not difficult to grasp but it is more difficult to grasp just how important
|
||||||
|
the concept is to functional programming and how programmers reason about code.
|
||||||
|
|
||||||
|
#### More Information:
|
||||||
|
<!-- Please add any articles you think might be helpful to read before writing the article -->
|
||||||
|
|
||||||
|
* [Wikipedia: Pure functions](https://en.wikipedia.org/wiki/Pure_function)
|
||||||
|
* [Learn You Some Erlang: Errors and Exceptions](https://learnyousomeerlang.com/errors-and-exceptions)
|
||||||
|
|
||||||
|
### What is a Pure Function ?
|
||||||
|
|
||||||
|
Think of a subroutine that returns no value at all.
|
||||||
|
Well, if it serves any useful purpose, it must do so by side-effects:
|
||||||
|
it may change global data, it may be a method changing the state of an object, it may do I/O.
|
||||||
|
|
||||||
|
This is technically a (pure) procedure.
|
||||||
|
Pure procedures are rare as usually at least a code indicating success / failure is returned.
|
||||||
|
|
||||||
|
Consider a subroutine that returns a value and has no side-effects (e.g. square_of/1).
|
||||||
|
This is a pure function.
|
||||||
|
|
||||||
|
Most programming languages allow a subroutine to be both a procedure with side-effects and a function with a return value.
|
||||||
|
|
||||||
|
In functional programming languages, functions are pure (or tend to be) and there are no procedures.
|
||||||
|
What are the consequences ?
|
||||||
|
|
||||||
|
### Consequences of using Pure Functions
|
||||||
|
|
||||||
|
A pure function, given the same input, will always produce the same result.
|
||||||
|
This offers compilers more scope for optimisation.
|
||||||
|
|
||||||
|
Compilers can examine an entire program to deduce which functions are pure and which are not.
|
||||||
|
A programmer cannot do this for a program of any size (even one they wrote themselves).
|
||||||
|
|
||||||
|
They can study a subroutine and say "assuming everything else stays the same, it does this" but often checking
|
||||||
|
that everything else stays the same is a lot more effort than studying the subroutine.
|
||||||
|
|
||||||
|
In a language where all functions are pure, the assumption is guaranteed.
|
||||||
|
This simplifies greatly the task of maintaining large applications:
|
||||||
|
you can change an individual function with confidence that there will be no unintended side-effects.
|
||||||
|
|
||||||
|
### Limitations of a Pragmatic Functional Programming Language
|
||||||
|
|
||||||
|
While most functions in Erlang are pure, there are certain features of the language that produce impure functions with side effects:
|
||||||
|
|
||||||
|
* functions may do I/O - I/O has side effects,
|
||||||
|
* actors send messages to one another - see the concurrent half of Erlang,
|
||||||
|
* functions may throw exceptions.
|
||||||
|
|
||||||
|
The first two are generally confined to small sections of code so the impurity is not widespread:
|
||||||
|
printing out some values for debug or logging purposes in one routine
|
||||||
|
does not suddenly mean all the functions around it are under serious threat from side-effects.
|
||||||
|
|
||||||
|
Throwing exceptions is a very bad idea.
|
||||||
|
It is a double-edged side-effect often there to force some function to clean up another function's run-time mess.
|
||||||
|
|
||||||
|
The Erlang philosophy is "Let it crash" so, in general Erlang programmers ignore this side-effect too.
|
||||||
|
|
||||||
|
The "Let it crash" philosophy is controversial.
|
||||||
|
|
||||||
|
In large, concurrent, Erlang applications, the view is that high reliability is achieved by
|
||||||
|
allowing the individual parts of the application to crash and be replaced without stopping the application.
|
||||||
|
By failing early, rather than trying to carry on,
|
||||||
|
the failed part is less likely to compromise the application or its data.
|
||||||
|
Developers can examine the crash and even load a fix without stopping the application.
|
||||||
|
|
||||||
|
Throwing an exception becomes a flag that says "If you want to get to the bottom of this bug, dig here".
|
||||||
|
|
||||||
|
### How to return errors from functions
|
||||||
|
|
||||||
|
Pure functions are all very well but what happens when the arguments to a function means the function cannot determine the result ?
|
||||||
|
|
||||||
|
When it is known that this will happen and the caller may reasonably be expected to go to Plan B,
|
||||||
|
it makes sense for the function to return a 'return code' as well as the 'return value'.
|
||||||
|
|
||||||
|
This can be done using a tuple:
|
||||||
|
|
||||||
|
```Erlang
|
||||||
|
% in the called function ...
|
||||||
|
|
||||||
|
if Y /= 0 -> {ok, X / Y};
|
||||||
|
y == 0 -> {err, 0}.
|
||||||
|
```
|
||||||
|
|
||||||
|
and:
|
||||||
|
|
||||||
|
```Erlang
|
||||||
|
% in the caller ...
|
||||||
|
|
||||||
|
case safe_divide(X,Y) of
|
||||||
|
{ok, Result} -> format("That worked");
|
||||||
|
{_, _} -> format("Oops, again");
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
<!-- EOF -->
|
Reference in New Issue
Block a user