Consider the arguments being passed to mult
on each invocation.
When you do Test.mult([1,5,10])
first it checks the first function clause; that is can [1,5,10]
be made to match []
. Elixir will try to make the two expressions match if it can. In this case it cannot so then it tries the next function clause; can [1,5,10]
be made to match [head|tail]
? Yes it can so it assigns the first element (1
) to head and the remaining elements [5,10]
to tail. Then it recursively calls the function again but this time with the list [5,10]
Again it tries to match [5,10]
to []
; again this cannot be made to match so it drops down to [head|tail]
. This time head is 5 and tail is 10. So again the function is called recursively with [10]
Again, can [10]
be made to match []
? No. So again it hits [head|tail] and assigns head = 10 and tail = [] (remember there's always an implied empty list at the end of every list).
Last go round; now []
definitely matches []
so it returns 1. Then the prior head * mult(tail)
is evaluated (1 * 10)
and that result is returned to the prior call on the stack. Evaluated again head (5) * mult(tail) (10) = 50
. Final unwind of the stack head (1) * mult(tail) (50) = 50
. Hence the overall value of the function is 50.
Remember that Elixir cannot totally evaluate any function call until it evaluates all subsequent function calls. So it hangs on to the intermediate values in order to compute the final value of the function.
Now consider your second code fragment in terms of pattern matching. [h|t] = [1,5,10]
will assign h = 1
and t = [5,10]
. h*t
means 1 * [5,10]
. Since those are fundamentally different types there's no inbuilt definition for multiplication in this case.
IO.inspect tail
withIO.inspect tail, charlists: false
and check if any better? – qhwa