Getting confusing error messages - could vsCode be related to the issue?

Hello,

I receive the following error when I try to run my code from the terminal:
$ elixir simple.ex
** (FunctionClauseError) no function clause matching in anonymous fn/3 in :elixir_compiler_0.FILE/1

The following arguments were given to anonymous fn/3 in :elixir_compiler_0.__FILE__/1:

    # 1
    2

    # 2
    1

    # 3
    11

simple.ex:1: anonymous fn/3 in :elixir_compiler_0.__FILE__/1
(elixir) lib/enum.ex:771: anonymous fn/3 in Enum.each/2
(elixir) lib/enum.ex:2967: Enum.reduce_range_inc/4
(elixir) lib/enum.ex:1930: Enum.each/2

I am learning elixir and trying to write the fizzbuzz function. Below is my code.

choose = fn
   (0, 0, _)  -> "FizzBuzz"
   (0, _, _)  -> "Buzz"
   (_, 0, x)  -> "#{x}"

end

fizzBuzz = fn
    (n) -> choose.(rem(n, 3), rem(n, 5), n)
end

IO.puts fizzBuzz.(10) #This works
IO.puts fizzBuzz.(11) #This breaks my code.

I am using vsCode. Is that an issue? I had a previous error, where the answer was to switch to vm vagrant box.

At a quick look i’d say that fizzBuzz.(10) results in a call for the first anonymous function with parameters 1, 0, 10 which is matched by:

 (_, 0, x)  -> "#{x}"

On the other hand fizzBuzz.(11) results in a call for the first anonymous function with parameters 2, 1, 11 which is not matched by any of them:

(0, 0, _)  -> "FizzBuzz"
(0, _, _)  -> "Buzz"
(_, 0, x)  -> "#{x}"

If you add a fourth match just as a test:

choose = fn
   (0, 0, _)  -> "FizzBuzz"
   (0, _, _)  -> "Buzz"
   (_, 0, x)  -> "#{x}"
   (2, 1, x)  -> "LET'S TRY THIS #{x}"
end

You’ll get:

$ elixir simple.ex
10
LET'S TRY THIS 11

Edit: spelling

3 Likes

Thank you. It makes sense now.
There is something I am still unclear about.

Why did my choose function not fail with 9, for example?

9 does not match the first line, but it does match the second line.

(0, 0, _) -> "fizzBuzz"
(0, _, _) -> "Buzz"

I am confused as to how Elixir functions work. If i call fizzBuzz.(9), this will in turn call the choose function. The choose function’s first line will not match. It seems to me the first line was ignored. What happens then? When I used 11 for example there were no matching lines. Why then did 11 throw an error?

You have a defect in your code …

It seems to me the first line was ignored. What happens then?

It wasn’t ignored - it didn’t match. All matches are attempted in turn until one succeeds. In your case for “11” it ran out of patterns so it crashed. All those patterns belong to one and the same function, each one defining a function head with an associated clause.


  def to_data(n),
    do: {rem(n, 3), rem(n, 5), n}

  def demo do
    result = Enum.map(1..11, &to_data/1)
    IO.puts("#{inspect(result)}")
  end
[{1, 1, 1}, {2, 2, 2}, {0, 3, 3}, {1, 4, 4}, {2, 0, 5}, {0, 1, 6}, {1, 2, 7}, {2, 3, 8}, {0, 4, 9}, {1, 0, 10}, {2, 1, 11}]
1 Like

Let me clarify.
I am following Dave Thomas’s book Programming Elixir >= 1.6, but I do not quite understand how functions work.

In the book, he has the following example:

handle_open = fn
  {:ok, file} -> "Read data: #{IO.read(file, :line)}"
  {_,  error} -> "Error: #{:file.format_error(error)}"
end

handle_open.(File.open(​"​​code/intro/hello.exs"​))   ​# this file exists​
-> "Read data: IO.puts \"Hello, World!\"\n"

 handle_open.(File.open(​"​​nonexistent"​))           ​# this one doesn't​
 -> Error: no such file or directory"

I do not understand how the parameters work. Is there an implicit if, else statement hidden somewhere?

Yes and no. From JavaScript you may be familiar with destructuring assignment. While useful it has one drawback - when the “shape” of the source value doesn’t “fit” the target structure, the parts in the target structure are simply left undefined.

Pattern matching is often used for destructuring BUT if the “shape” of the source value doesn’t fit the pattern (or more simply the values don’t match) the match fails.

iex(1)> {a,b} = 3
** (MatchError) no match of right hand side value: 3
    (stdlib) erl_eval.erl:453: :erl_eval.expr/5
    (iex) lib/iex/evaluator.ex:249: IEx.Evaluator.handle_eval/5
    (iex) lib/iex/evaluator.ex:229: IEx.Evaluator.do_eval/3
    (iex) lib/iex/evaluator.ex:207: IEx.Evaluator.eval/3
    (iex) lib/iex/evaluator.ex:94: IEx.Evaluator.loop/1
    (iex) lib/iex/evaluator.ex:24: IEx.Evaluator.init/4
iex(1)> {a,b} = {2,4}
{2, 4}
iex(2)>

On that second try the match succeeded (so the value that is returned, is the value that matched; and yes coming from mainstream languages that looks like an assignment but in fact = is the match operator - always (in that context). And a result of a successful match is that the names in the pattern are bound to their respective values, i.e. there are no variables, nothing varies).

So pattern matching is a conditional construct.

  def choice(n) do
    case({rem(n,3),rem(n,5), n}) do
      {0, 0, _} -> "FizzBuzz" # 1. divisible by 3 and 5
      {0, _, _} -> "Fizz"     # 2. divisible by 3
      {_, 0, _} -> "Buzz"     # 3. divisible by 5
      {_, _, x} -> "#{x}"     # 4. just a number
    end
  end

  def demo do
    result = Enum.map(1..11, &choice/1)
    IO.puts("#{inspect(result)}")
  end

So what is happening in that case expression is that a tuple is created and then a pattern match is performed and whatever pattern matches first selects the clause that is evaluated.

  def choice_tuple({0, 0, _}),
    # 1. divisible by 3 and 5
    do: "FizzBuzz"

  def choice_tuple({0, _, _}),
    # 2. divisible by 3
    do: "Fizz"

  def choice_tuple({_, 0, _}),
    # 3. divisible by 5
    do: "Buzz"

  def choice_tuple({_, _, x}),
    # 4. just a number
    do: "#{x}"

  def choice(n),
    do: choice_tuple({rem(n, 3), rem(n, 5), n})

  def demo do
    result = Enum.map(1..11, &choice/1)
    IO.puts("#{inspect(result)}")
  end

… does exactly the same thing but the pattern match is spread over 4 separate function clauses (belonging to the same function choice_tuple/1)

  def choice(0, 0, _),
    # 1. divisible by 3 and 5
    do: "FizzBuzz"

  def choice(0, _, _),
    # 2. divisible by 3
    do: "Fizz"

  def choice(_, 0, _),
    # 3. divisible by 5
    do: "Buzz"

  def choice(_, _, x),
    # 4. just a number
    do: "#{x}"

  def choice(n),
    do: choice(rem(n, 3), rem(n, 5), n)

  def demo do
    result = Enum.map(1..11, &choice/1)
    IO.puts("#{inspect(result)}")
  end

… gets rid of the tuple and spreads the values over 3 arguments. It’s still all pattern matching. Note that we have two separate choice functions here: choice/1 (with an arity of one) and choice/3 (with an arity of three).

2 Likes

I see. I believe I understand.

However your examples have raised more questions.

What is a function clause? It seems to that you are defining the same function and changing the parameters four different times. (Am I misinterpreting what you wrote?)

In C# for example there is polymorphism, but functions have different reference memory values for each function of differing arity. This is how the interpreter is able to determine the correct function to call. In your second and third examples, how does elixir determine the correct choice of function given that they all have the same arity?

It doesn’t - you’re still thinking of them as separate functions. Start thinking of it as a single function where each clause adds another piece of a case expression (same name and arity - same function).

The interpreter simply tries the patterns in order (pattern matching is highly optimized on the BEAM). The first one that succeeds has its expression evaluated (which becomes the return value).

If none succeeds the process crashes because it can’t find a match - that is the problem you experienced in your opening post.

Function declarations also support guards and multiple clauses.

3 Likes

Thank you @peereynders you have been very helpful.

1 Like