<jupyter_start><jupyter_text>- title: Immutability Principles- author: <NAME>- date: 2018-09-12- category: Functional Programming- tags: Immutability  Mutability is hard to reason aboutA lot of programming languages support mutability. For example, some objects in Python are mutable:<jupyter_code>x = [1, 2, 3]
x.reverse()
x<jupyter_output><empty_output><jupyter_text>This may not seem problematic at first. A lot of people would argue that it is indeed necessary to program. However, when things can change, we sometimes are forced to understand more details than the bare minimum necessary. For example:<jupyter_code># This function is just for ilustration purposes.
# Imagine a situation where a very long and complex method mutates one of it's arguments...
from typing import List, TypeVar
T = TypeVar('T')

def m1(x: List[T]) -> None:
    """Reverses its argument"""
    x.reverse()
    return None

vowels = ['a', 'e', 'i', 'o', 'u']
m1(vowels)
vowels<jupyter_output><empty_output><jupyter_text>Now, we have to dig into the implementation of `m1`, to understand how the method affects its arguments.A simpler approach is to rely on immutable data structures/variables. This may seem like a more difficult approach, but it makes programming easier in the long run.<jupyter_code># Note: The example above serves to illustrate the problems with mutation.
# Of course, it is not the *only* way to do it on Python.
# For example, a more functional approach would be (using `List[T]`):
def m2(x: List[T]) -> List[T]:
    return x[::-1]

vowels2 = ['a', 'e', 'i', 'o', 'u']

print(m2(vowels2))
print(vowels2) # Remains unmodified<jupyter_output>['u', 'o', 'i', 'e', 'a']
['a', 'e', 'i', 'o', 'u']<jupyter_text>Let's use an immutable approach to the previous problem with `pyrsistent` Python's library:<jupyter_code>from pyrsistent import plist
ns1 = plist([1, 2, 3])
ns1
ns2 = ns1.reverse()
ns2
# Notice that original list remains unmodified (it is an immutable/persistent data structure!)
ns1<jupyter_output><empty_output><jupyter_text>The following script, is a complete application of the concepts just presented.<jupyter_code>from pyrsistent import PRecord, field
from typing import Callable, Optional, TypeVar
from scipy.optimize import newton

import matplotlib.pyplot as plt
import numpy as np


A = TypeVar('A')
B = TypeVar('B')
F1 = Callable[[A], B]
RealF = F1[float, float]


class RootPlot(PRecord):
    def inv(self):
        return self.x_min <= self.x_max, 'x_min bigger than x_max'
    __invariant__ = inv
    x_min = field(type=float, mandatory=True)
    x_max = field(type=float, mandatory=True)
    x_init = field(type=float)
    output_file = field(type=str)

    def plot(self,
             y: RealF,
             dy: Optional[RealF] = None,
             dy2: Optional[RealF] = None) -> None:
        root = newton(func=y, x0=self.x_init, fprime=dy, fprime2=dy2)
        x = np.linspace(self.x_min, self.x_max)
        plt.clf()
        plt.plot(x, np.vectorize(y)(x))
        plt.plot(root, 0.0, 'r+')
        plt.grid()
        plt.savefig(self.output_file)
        plt.close()


def y(x: float) -> float:
    return ((2*x - 11.7)*x + 17.7)*x - 5.0

def dy(x: float) -> float:
    return (6.0*x - 23.4)*x + 17.7

def dy2(x: float) -> float:
    return 12*x - 23.4

p = RootPlot(x_min=0.0,
             x_max=4.0,
             x_init=3.0,
             output_file="simple_plot.png")

# This wouldn't change final result. You would still get a plot
# from 0.0 to 4.0
# p.set(x_init=2.0)
p.plot(y)<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.12380146644106035, 'fraction_numerical': 0.02030456852791878, 'mean_word_length': 3.8127544097693353, 'pattern_counts': {'":': 0, '<': 22, '<?xml version=': 0, '>': 27, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '5', 'dir': 'jupyter-structured-clean-dedup', 'id': '136688', 'license': 'Apache-2.0', 'n_tokens_mistral': 1259, 'n_tokens_neox': 1213, 'n_words': 402, 'path': 'content/immutability-principles.ipynb', 'repo_name': 'oscarvarto/blog', 'size': '3559'}