In FP, we frequently talk about purity & impurity of values.
In this brief post, we’ll brush up our concepts of the same, along with some examples.
What could an impure value be?
@ val pureFunctionValue: Int => String = (i) => s"$i was entered"
pureFunctionValue: Int => String = ammonite.$sess.cmd7$$$Lambda$2092/943512909@25533bba
@ pureFunctionValue(42)
res8: String = "42 was entered"
@ val impureFunctionValue: Int => String = (i) => { println("now executing some side effecting code"); s"$i was entered" }
impureFunctionValue: Int => String = ammonite.$sess.cmd9$$$Lambda$2116/1958462067@a0d875d
@ impureFunctionValue(42)
now executing some side effecting code
res10: String = "42 was entered"
As we can see, a value is pure, if it conforms very strictly to its type. In case of pureFunctionValue
the declared type said that it was a function which takes an Int and returns a String, and that was indeed what it did. It could take an Int and it gave us back a reference to a String value and did nothing else.
In case of impureFunctionValue
the declared type said that it was a function which takes an Int and returns a String. Indeed we could feed it an Int, but when we did so, it did something else apart from returning us a String. It printed stuff out to the console. This, friends, was not expressed in the type, thus it is a side-effect of the function and thus the value in question is impure, and not exactly a function in the mathematical sense.
Another Impure Value
@ val randomValuesGenerator = new scala.util.Random
randomValuesGenerator: scala.util.Random = scala.util.Random@13087c75
@ randomValuesGenerator.nextInt
res20: Int = -1981430922
@ randomValuesGenerator.nextInt
res21: Int = 666650962
Here, randomValuesGenerator
is an impure value again. Because, when we called the same function again on it, a different result was returned. Thus, nextInt
is not really a function on randomValuesGenerator
in the mathematical sense, because, otherwise, in all its invocations, it would’ve returned us the exact same result. Thus it is an impure value because it doesn’t exactly do what it says it does.
Let’s convert randomValuesGenerator.nextInt
to a function value and see what its type is:
@ val x = randomValuesGenerator.nextInt _
x: () => Int = ammonite.$sess.cmd22$$$Lambda$2151/374123858@738ae785
So apparently, randomValuesGenerator.nextInt
is a function, to which we can apply the unit value and get back an Int. Let’s do it.
@ x()
res24: Int = -2068951855
@ x()
res25: Int = -1255655781
As we can see, we applied the same value ()
(the only instance of Unit
, by the way) to x and got back different results. It’s doing something else apart from returning us an Int. Maybe it’s mutating its own internal state. That, friends, is a side effect that x is performing on itself. Hence, x is an impure value and not exactly a function in the mathematical sense. IOW, x is a liar!
There. We built a little model for thinking about pure/impure values and we’ll use it for thinking about more complex FP ideas.
If you guys want to explore further into this topic, you can explore What Purity Is and Isn’t.
Stay tuned for more!
1 thought on “Pure vs. Impure values3 min read”
Comments are closed.