Accessing pattern matched variable in a different function

How can I access/use the first_word, second_word, third_word variables to refer to their matched pattern in func_2 in the code below?

defmodule Test do
    def main() do 
        func_1(["Peanut","Butter","Cookies"])
    end

    def func_1(list) do
        [first_word, second_word, third_word] = list
    end

    def func_2 do
        #How to access first_word, second_word, third_word in this function?
    end
end
1 Like

func_1 does nothing but return the list.

Test is not an object, it is a module. func_2 has no way to know what happens in func_1, nor main…

There are no objects, no inheritance, no loop, and variables are immutable.

But You have modules, functions, arguments and You use composition everywhere.

2 Likes

oh okay. But say if I want to access a variable outside of a function to manipulate the calculation in that function, is there no way to get that data? like global variables in Python

There is clojure, You can access outside variables from within the function, but no way to modify it from within to the outside… But You can create a function, that takes this variable as input, and return a modified version of it.

iex> a = 1
iex> fun = fn x -> x + a end
iex> a = fun.(a)
2
iex> a = fun.(a)
3

Please don’t think it is a mutation, it is a rebinding. And this would not be possible in Erlang.

There is nothing like a global scope, it is meant to work in complete isolation. The only thing that would look similar is an Agent, a specialized GenServer which could look like a global space.

It’s on purpose… You might not see why now, but You might understand later when You’ll get into OTP.

FP is just a mean to achieve Concurrent programming, where You can run millions of processes in complete isolation. Global shared state is seen has the root of all evil :slight_smile:

1 Like

The only way to get a data from somewhere but the current scope is to spawn the process and store everything you want to be accessible in its state. Then use message passing to update/query this state.

E. g. Agent — Elixir v1.11.3

Short answer: no. Long answer: there is a way, but you should not learn it yet. In the mean time you have some serious unlearning to do:

  • There is no variable, only immutable values.
  • There is no state, only pure functions. (same input → same output)
  • There is no loop, only recursions.

All the prior replies are good advice. I will refactor your example code because perhaps you are not familiar with pattern matching

defmodule Test do
    def main() do 
        func_2(["Peanut","Butter","Cookies"])
    end

     def func_2([first_word, second_word, third_word]) do
        # There is no need for func_1 at all. You can pattern match the parameter to func_2
    end
end
1 Like

Hi @allgeo , let’s take the lessons from Iterating over a list with a certain condition (sorry, I am very new to functional programming) - #7 by BartOtten and apply this to your question from this topic.

Your list is bound to the variable list in Elixir in function1(). There you pattern match the elements of the list, so you get first_word, second_word, third_word variables with are 3 memory address bindings _within the scope of function1 (#memory_address1, #memory_address2, #memory_address3). There is NO way function2 knows the memory addresses function1 used for those variables.

In Elixir the last thing in a function is the result from that function. If you apply that to function1() you’ll see that function1 will return a list which is equivalent to [value of #memory_address1, value of #memory_address2, value of #memory_address3] which happens to be [Peanut, Butter, Cookies] and is exactly the same as the list you put into the function.

How can we let function2 know about the memory addresses used in function1? We can’t. What we can do is bind the result to a new variable (which will be in the scope outside the function, and pass that variable into function2.

In long form:

main_result = main([first_word, second_word, third_word])
function2_result = function2(main_result)
end_result = function2_result

main_result is bound in the global scope, so it can be passed into function2()
function2_result is bound in the global scope, so it can be assigned to variable end_result

In short form:
As using temporary variables is ugly, Elixir has a nice trick. You can pipe |> the result of a function into the next function. In the example could be written as;

end_result = 
   main()
   |> function2()

Which elixir sees as:

end_result = 
   main()
   |> function2(take the result from before the `|>` and use it as variable `list`)