Bartłomiej Szałach
Bartłomiej Szałach

Reputation: 2453

Erlang illegal pattern while working with list of records

I am trying to write simple address book in Erlang. I have started with:

-record(entry, {name, surname, phone, email}).

createAdressBook() -> [].

addContact(Name, Surname, AdressBook) ->
  case isAlready(Name, Surname, AdressBook) of
    false -> [#entry{name = Name, surname = Surname}|AdressBook];
    _ -> {error, "This entry already exists"}
  end.

isAlready(_, _, []) -> false;
isAlready(Name, Surname, [#entry{name = Name, surname = Surname}|_]) -> true;
isAlready(Name, Surname, [_|T]) -> isAlready(Name, Surname, T).

However, after a while, I decided that I'd like to keep name and surname together. After changing the code into following it raises a compilation error (illegal pattern in the second line of new isAlready/3.

-record(entry, {person, phone, email}).

createAdressBook() -> [].

addContact(Name, Surname, AdressBook) ->
  case isAlready(Name, Surname, AdressBook) of
    false -> [#entry{person = Name ++ " " ++ Surname}|AdressBook];
    _ -> {error, "This entry already exists"}
  end.

isAlready(_, _, []) -> false;
isAlready(Name, Surname, [#entry{person = Name ++ " " ++ Surname}|_]) -> true;
isAlready(Name, Surname, [_|T]) -> isAlready(Name, Surname, T).

What am I doing wrong and what is the proper why to check if string1 + " " + string2 is the head of the list?

Upvotes: 1

Views: 473

Answers (3)

Kai Zhou
Kai Zhou

Reputation: 37

when pattern matching wiht ++, the heading element must be known when compiling. For example,

TitledName = "Mr. Black",
"Mr. "++LastName= TitledName

It is like:

[$M, $r, $., $\s|LastName]= TitledName.

Upvotes: 2

Bartłomiej Szałach
Bartłomiej Szałach

Reputation: 2453

Just before zxq9 posted his answer I had found another solution is to keep name and surname as the tuple inside the record's person field.

-record(entry, {person, phone, email}).

createAdressBook() -> [].

addContact(Name, Surname, AdressBook) ->
  case isAlready(Name, Surname, AdressBook) of
    false -> [#entry{person = {Name, Surname}}|AdressBook];
    _ -> {error, "This entry already exists"}
  end.

isAlready(_, _, []) -> false;
isAlready(Name, Surname, [#entry{person = {Name, Surname}}|_]) -> true;
isAlready(Name, Surname, [_|T]) -> isAlready(Name, Surname, T).

Upvotes: 2

zxq9
zxq9

Reputation: 13154

You are trying to perform an operation in the function head, not just match when you use ++. So that won't work. Instead, use the opportunity in the calling function to create your Person value just once, and use it consistently from there:

-record(entry, {person, phone, email}).

createAdressBook() -> [].

add_contact(Name, Surname, AdressBook) ->
  Person = Name ++ " " ++ Surname,
  case is_already(Person, AdressBook) of
    false -> [#entry{person = Person}|AdressBook];
    _ -> {error, "This entry already exists"}
  end.

is_already(_, []) -> false;
is_already(Person, [#entry{person = Person}|_]) -> true;
is_already(Person, [_|T]) -> is_already(Person, T).

Alternately, you can use a property of records and tuple indexes to use a search function instead of writing your own:

is_already(Person, AddressBook) ->
    case lists:keyfind(Person, #entry.person, AddressBook) of
        #entry{} -> true;
        false    -> false
    end.

As a style note -- you notice I changed the function names from isAlready to is_already. In Erlang upper case words have a special meaning, and to prevent confusion we simply use all_lower_and_underscores for function names, and AllUpperCamelCase for variables.

Upvotes: 3

Related Questions