Pure Versus Impure Functions

I'm brand new to functional programming, and I sometimes find the concepts to be a little abstract for me to grasp, being that I'm more of a concrete thinker. The purpose of this post is to help solidify some of the understandings I have gained by studying functional programming, and hopefully help others on a similar journey.
Pure Functions
In functional programming, a pure function is a function that, given the same input, will always return the same output without producing any side effects. It won't modify any external state, nor will it produce a different output when called multiple times with the same arguments. For example, it won't modify an existing variable outside its scope or print to the console. Here is example of a pure function:
def add_one_pure(num_list):
# This line creates a new list with each number incremented by one. The new_list is internal to the function itself. It does reach out to any external varibles. It internally interates thourgh the input and produces a new list self contained wiht in the function itself.
new_list = [num + 1 for num in num_list]
return new_list
# Example of how to use it
numlist = [1, 2, 3, 4]
updated_list = add_one_pure(numlist)
# the print staements here are outside the function.
print(f"Original list: {numlist}")
print(f"New list: {updated_list}")
Impure Functions
On the other hand, an impure function might change an external state (like modifying the value of a variable), print to the console, or produce a different output for the same input. These are all examples of side effects.
Example of an impure function:
def add_one_impure(num_list):
# Adds one to each number in a list by modifying the list in place. This is an impure function as it has a side effect: it mutates the list outside its scope.
for i in range(len(num_list)):
num_list[i] += 1
# We don't return anything since the purpose is to modify the original list.
# Example of how to use it
numlist_impure = [1, 2, 3, 4]
print(f"Original list before the function call: {numlist_impure}")
add_one_impure(numlist_impure)
print(f"List after the impure function call: {numlist_impure}")
Notice how the numlist_impure variable is permanently changed after the function call.
Conclusion
Understanding the difference between pure and impure functions is crucial in functional programming. Pure functions are more predictable and easier to test because they don't have hidden side effects. You can always count on the same input to produce the same output. Impure functions, while necessary for tasks like I/O and interacting with external systems, can make code harder to debug and reason about. By being mindful of when and where you introduce side effects, you can write cleaner, more reliable code.






