Hi all, the question seems like a simple question, but it has thrown me for a long time. I have a loop in which I loop through an element of the map list and I need to add the current item to the new list.
For a better understanding, here is a simpler example:
current_list = []
for x <- 1..10 do
current_list = [x | current_list]
end
I expect to get [1,2,3,4,5,6,7,8,9,10] in current_list, but got []
What am I doing wrong? Thanks in advance!
The current_list inside the for-loop is not the same variable as the current_list outside the for-loop. Actually, the current_list inside each loop is different.
I bet you’ve heard that in Elixir, everything is immutable, which means if a list is empty, it stays empty for the rest of its life. You can’t stuff things into it, or remove things from it, or change any of its elements.
So, the correct way is:
current_list = []
current_list =
for x <- 1..10, reduce: current_list do
acc -> [x | acc]
end
IMHO, newbies should stay away from if, for or with until being comfortable with functional style programming. They are only syntactical sugar to make things shorter; they don’t provide any vital functionalities.
IDK, if is such a common core construct it feels like it would be off-putting to try to learn a lang where that was discouraged. In fact I’d say it’s the ideal candidate from which to learn this functional scoping lesson!
Right! The combination of lexical scoping, expression return values, resulting in do/end variables being local and needing to assign out of them, is what’s the useful take-away.
I think if is great lesson in this, because
newcomers will often reach for it early
trying to re-assign something out of scope (which is commonly possible in other lexically scoped languages; that’s kind of what I meant by “functional” lexical scoping)
possibly discover after the assigning-result refactor that if they want the fallback case to be non-null, they also can return out of else
which sets them up for success when the conditional branching becomes more comples and they needbti reach for case; they will have acquired the understanding they need to succeed
I suppose the compiler could warn on reassignment of shadowed variables. There are legitimate use-cases for it though, especially in more involved conditional bodies. Especially in reduces!
That’s true. I suppose the way to capture the anti-shadowing sentiment that this is bad practice would be:
def transform(results) do
results = if some_check(results) do
results = Enum.map(&something) #warning: variable used in inner scope shadows outer scope
use_and_return_interim_results(results)
else
[]
end
use_and_return_ulitimate_results(results)
end
Piping or renaming the variable would fix.
I don’t actually care much for this. It feels like such a warning should exist at the Credo level rather than the compiler, anyways.