Passing list to function results in no case clause matching

121 Views Asked by At

I am attempting to pass a list into a function and I am just now learning erlang. So I am new. I get this error in my shell when I attempt to build my erl file.

exception error: no case clause matching [{atom,{3,9},lists}]
  in function  erl_parse:build_attribute/2 (erl_parse.yrl, line 1395)
  in call from erl_parse:yeccpars2_654/7 (erl_parse.yrl, line 127)
  in call from erl_parse:yeccpars0/5 (/daily_build/otp_src/bootstrap/lib/parsetools/include/yeccpre.hrl, line 57)
  in call from epp:parse_file/1 (epp.erl, line 364)
  in call from epp:parse_file/1 (epp.erl, line 366)
  in call from epp:parse_file/2 (epp.erl, line 337)
  in call from compile:do_parse_module/2 (compile.erl, line 1037)
  in call from compile:parse_module/2 (compile.erl, line 1011)

Here is my code that is causing it.

It is in my for function, the rest of the code is just test work as I am practicing.

 % hello world program
-module(helloworld).
-import(lists).
-import(io,[fwrite/1]).
-export([start/0,greet/2,for/3]). 


greet(male, Name) ->
    io:format("Hello, Mr. ~s!\n", [Name]);
    greet(female, Name) ->
    io:format("Hello, Mrs. ~s!\n", [Name]);
    greet(_, Name) ->
    io:format("Hello, ~s!\n", [Name]).

for(Nums <- [H|T], Idx, Target) ->
    Val = lists:nth(Idx, Nums),
    S = if Val == Target -> Idx;
       Idx >= len(Nums) -> -1;
       true -> for(Nums, Idx + 1, Target);
    end,
    S.
    
   

start() -> 
   fwrite("Hello, world!\n").

Also, I am curious that is actually going to return recursively.

2

There are 2 best solutions below

0
legoscia On BEST ANSWER

The problem is this line:

-import(lists).

As noted in this answer, the one-argument form of the -import directive was removed in Erlang R16B (released in 2013). These days -import directives require two arguments, the module name and a list of functions to import, like the one on the line below:

-import(io,[fwrite/1]).

In general, importing functions is discouraged in Erlang. It is often clearer to include the module name every time you're calling a function. For example, when reading the start function:

start() -> 
   fwrite("Hello, world!\n").

the call to fwrite looks like a local function call, and it's only by looking at the -import directive that you realise that it's actually a call to io:fwrite.

So I would recommend removing both -import directives, and changing the start function to call io:fwrite explicitly, like this:

start() -> 
   io:fwrite("Hello, world!\n").
1
Yuri Ginsburg On

Also, I am curious that is actually going to return recursively.

It looks that you want to find the index ofelement of list Nums that is equal to Target if such exists and return -1 otherwise. Something like this.

-module(find).
-export([find/2, start/0]).

find([H|T], Target) -> f([H|T], Target, 0).

f([], _, _) ->  -1;  % not found 

f([H|T], Target, Idx) -> 
    if 
        H == Target -> Idx;  % found
        true -> f(T, Target, Idx+1) % keep searching
    end 
.

start() -> 
    io:fwrite("~w~n", [find([1, 2, 3], 3)]),
    io:fwrite("~w~n", [find([1, 2, 3], 5)]).

Output.

2
-1
ok

UPD Answering the questions from comments. Let's look how we call f function looking for target 5.

f([1, 2, 3], 5, 0)
f([2, 3], 5, 1)
f([3], 5, 2)
f([], 5, 3)

Last call matches f([], _, _) and returns -1. So no indexing occurs and no "index out of range" happens.

But if you try to call lists:nth(4, [1, 2, 3]) you will get something like

** exception error: no function clause matching lists:nth(1,[]) (lists.erl, line 170)