Reputation: 2453
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
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
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
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