File: purity.rst

package info (click to toggle)
toolz 1.1.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 588 kB
  • sloc: python: 4,223; makefile: 137
file content (96 lines) | stat: -rw-r--r-- 2,899 bytes parent folder | download | duplicates (3)
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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
Function Purity
===============

We call a function *pure* if it meets the following criteria

1.  It does not depend on hidden state, or equivalently it only depends on its
    inputs.
2.  Evaluation of the function does not cause side effects

In short the internal work of a pure function is isolated from the rest of the
program.

Examples
--------

This is made clear by two examples:

.. code::

    # A pure function
    def min(x, y):
        if x < y:
            return x
        else:
            return y


    # An impure function
    exponent = 2

    def powers(L):
        for i in range(len(L)):
            L[i] = L[i]**exponent
        return L

The function ``min`` is pure.  It always produces the same result given the
same inputs and it doesn't affect any external variable.

The function ``powers`` is impure for two reasons.  First, it depends on a
global variable, ``exponent``, which can change [*]_.  Second, it changes the
input ``L`` which may have external state.  Consider the following execution:

.. code::

    >>> data = [1, 2, 3]
    >>> result = powers(data)

    >>> print(result)
    [1, 4, 9]
    >>> print(data)
    [1, 4, 9]

We see that ``powers`` affected the variable ``data``.  Users of our function
might be surprised by this.  Usually we expect our inputs to be unchanged.

Another problem occurs when we run this code in a different context:

.. code::

    >>> data = [1, 2, 3]
    >>> result = powers(data)
    >>> print(result)
    [1, 8, 27]

When we give ``powers`` the same inputs we receive different outputs; how could
this be?  Someone must have changed the value of ``exponent`` to be ``3``,
producing cubes rather than squares.  At first this flexibility may seem like a
feature and indeed in many cases it may be.  The cost for this flexibility is
that we need to keep track of the ``exponent`` variable separately whenever we
use ``powers``.  As we use more functions these extra variables become a
burden.

.. [*] A function depending on a global value can be pure if the value never
       changes, i.e. is immutable.

State
-----

Impure functions are often more efficient but also require that the programmer
"keep track" of the state of several variables.  Keeping track of this state
becomes increasingly difficult as programs grow in size.  By eschewing state
programmers are able to conceptually scale out to solve much larger problems.
The loss of performance is often negligible compared to the freedom to trust
that your functions work as expected on your inputs.

Maintaining state provides efficiency at the cost of surprises.  Pure
functions produce no surprises and so lighten the mental load of the
programmer.


Testing
-------

As an added bonus, testing pure functions is substantially simpler than testing
impure ones.  A programmer who has tried to test functions that include
randomness will know this first-hand.