Why do I receive a FunctionClauseError ("no function clause matching") in this Elixir program, translated from Erlang? [closed]
Asked Answered
B

1

8

**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)>
Brittani answered 12/6, 2015 at 22:26 Comment(4)
Arrrrgh! 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'allBrittani
Happens to the best of us :)Perspire
Maybe 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)Nuptials
So, if I'd paid more attention to the section of the elixir-lang.org site called: 'Erlang/Elixir Syntax: A Crash Course', I'd have seen a section that highlighted this error. On the whole, though, I find the Elixir error messages I've seen, so far, are not very descriptive. Messages remind me of some of the cryptic errors I used to see in Fortran compilers. 'Early Days', I guess.Brittani
Z
11

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.

Zelaya answered 13/6, 2015 at 18:17 Comment(4)
It 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. :DBrat
This is great! It really helps me understand the two languages.Brittani
Well, 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, jpsBrittani
Hmmm; 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.Brittani

© 2022 - 2024 — McMap. All rights reserved.