I think the main difficulty in converting your example to a functional style is how to express the idea of a for loop which builds up a result as it goes along, without using a mutable variable to store this result. Here's an attempt to explain how that the ideas in the parent are helpful in solving that problem.
You can think of the body of a for loop in python as the body of a function. In that case, a for loop is like the built-in map function, which applies that function to every element of the list. So convert your for loop into:
def body(email):
domain = email.split("@")[1]
if domain not in domains:
domains.append(domain)
And instead of a for loop we can use the standard function, 'map'.
domains = []
map(body, emails)
Now, obviously the data here isn't immutable. But what if, instead of changing 'domains' every time the function is called, we passed in the current value of 'domains', and returned a changed value, like so:
def body(domains, email):
domain = email.split("@")[1]
if domain not in domains:
return domains + [domain]
else:
return domains
Then, we could apply this function to each element of the list in turn, passing the current list of domains at each stage to the body. This is the standard function 'reduce' in Python (which the parent calls by its other common name, 'fold'):
domains = reduce(body, emails, [])
You could think of 'reduce' in python being implemented like:
def reduce(func, l, currentResult):
for item in list:
currentResult = func(currentResult, item)
return currentResult
Or, it could also be implemented recursively, which means it wouldn't need to use mutation internally:
def reduce(func, l, currentValue):
if len(l) == 0:
return currentValue
else:
return reduce(func, l[1:], func(currentValue, l[0]))
Many for loops that build up a result can be expressed instead using 'reduce', so reduce is one of the most important building blocks of functional programming.