Why do I receive a FunctionClauseError ("no function clause matching") in this Elixir program, translated from Erlang?
Just to expand on the problem and why you received the error you did:
Capitalized identifiers are treated as aliases for atoms. For example:
iex(1)> N == :Elixir.N
true
So when you have the following code:
iex(1)> defmodule Test do
...(1)> def foo, do: IO.puts "testing"
...(1)> end
iex(2)> Test.foo
testing
It's the same as saying
iex(3)> :Elixir.Test.foo
testing
Since uppercase identifiers are treated as symbols, you essentially wrote the following program:
defmodule Cater do
def cut(0), do: 1
def cut(:Elixir.N) when :Elixir.N>0, do: :Elixir.N + cut(:Elixir.N-1)
end
This is valid, because you can pattern match on atoms in the argument list, and :Elixir.N > 0
is a valid expression.
iex(1)> N > 0
true
Consider the following Elixir program and output:
iex(1)> defmodule Cater do
...(1)> def cut(0), do: IO.puts "cut(0)"
...(1)> def cut(N) when N > 0, do: IO.puts "cut(N)"
...(1)> end
iex(2)> Cater.cut(0)
cut(0)
iex(3)> Cater.cut(N)
cut(N)
iex(4)> Cater.cut(:Elixir.N)
cut(N)
iex(5)> Cater.cut(1)
** (FunctionClauseError) no function clause matching in Cater.cut/1
iex:2: Cater.cut(1)
So, the reason you got the seemingly strange error message no function clause matching in Cater.cut/1
is that there's technically nothing wrong with your program (except for the actual function body of cut(N)
—it would raise an ArithmeticError
, which Elixir warns you about at compile time); it's perfectly valid, it just doesn't do what you wanted it to do/what you thought it did.
Related videos on Youtube
jpsthecelt
Updated on June 04, 2022Comments
-
jpsthecelt almost 2 years
**So, I've worked with Erlang, before, and am pretty comfortable with it. I am just trying to learn Elixir.
I was recently trying to translate a 'lazy caterers' example into elixir and am befuddled as to why it either doesn't compile, or compiles with a warning and doesn't work. What am I missing, here; Any ideas? The erlang code and 'run' are as follows:**
jps@GRASSKEET ~/dev/erlang $ cat cater.erl -module(cater). -export([cater/1]). cater(0) -> 1; cater(N) when N>0 -> N + cater(N-1). jps@GRASSKEET ~/dev/erlang $ erl Eshell V6.3 (abort with ^G) 1> c("cater.erl"). {ok,cater} 2> cater:cater(10). 56 3>*
When I write Cater.ex like so, it gets an error that doesn't make sense to me:
jps@GRASSKEET ~/dev/elix $ cat Cater.ex defmodule Cater do def cut(0), do: 1 def cut(N) when N>0, do: N + cut(N-1) end jps@GRASSKEET ~/dev/elix $ iex Interactive Elixir (1.0.4) - press Ctrl+C to exit (type h() ENTER for help) iex(1)> c("Cater.ex") Cater.ex:1: warning: redefining module Cater Cater.ex:3: warning: this expression will fail with ArithmeticError [Cater] iex(2)> Cater.cut(10) ** (FunctionClauseError) no function clause matching in Cater.cut/1 Cater.ex:2: Cater.cut(10) iex(2)>
-
jpsthecelt almost 9 yearsArrrrgh! What a moron I am. As soon as I posted this, I had a 'feeling', went back and editted, and 'sure enough', elixir didn't like the fact that my variable-names were capitalized. Once I changed all Ns to n, it properly compiled and ran. So sorry to bother y'all
-
jjbohn almost 9 yearsHappens to the best of us :)
-
Pascal almost 9 yearsMaybe you could change the title, so people can retrieve your post easily: I also had this trouble trying elixir, where everything remind erlang, but everything is different :o)
-
-
José Valim almost 9 yearsIt is also worth pointing out that the exactly same issue would happen going from Elixir to Erlang. If you use Elixir's lowercase variables in Erlang, they will be atoms, and you will have exactly the same error. :D
-
jpsthecelt almost 9 yearsThis is great! It really helps me understand the two languages.
-
jpsthecelt almost 9 yearsWell, I see this question as very helpful to explain the semantic vs. syntactic differences within a new and exciting language; especially from the point-of-view of the beginner's 4-line program that was seemingly correct. I like Jose's note that the same is true in the 'reverse-direction'.I appreciate anyone's ideas to reword it to be clearer -- perhaps 'semantic differences in variable declarations btw. Elixir and Erlang'? TIA, jps
-
jpsthecelt almost 9 yearsHmmm; how about 'atoms vs. variables' in Elixir/Erlang, or 'arth error on elixir/erlang '+' --> BTW, BinaryMuse's explanation was very helpful in understanding why both pascal and I had initially made the same mistake. Finding a way to add this to S/O will help provide a quick solution/explanation for those professional programmers who are 'stumped'. [incidentally, making the reverse edits [all n to N for the erlang program], produced a similar 'arithmentic error in line 4' from erlc). Thx.