I'm new to Erlang and am trying to write a function that when passed a Point record (an x,y coordinate) and a list of Point records (a list of x,y coordinates), returns true if the Point record with the specified x and y coordinates is an element (i.e. already exists) in the list and false otherwise.
Here's the definition of the point record:
-record(point, {x, y})
This is the signature of the function:
contains_point(Point, List)
I tried looking up similar questions and in the Erlang docs, but haven't found what I'm looking for.
I also tried the following code:
contains_point(Point, List)->
Found = fun(Point) -> lists:member(Point, List) end,
case lists:any(Found, List) of
true ->
yes;
false ->
no
end.
But got the warning messages, "variable 'Point' shadowed in 'fun'" and "variable 'Point' is unused."
Would appreciate any help with this, thank you!
Your function has multiple problems, hinted at by the unused and shadowed variable warnings.
contains_point(Point, List) ->
Found = fun(Point) -> lists:member(Point, List) end,
case lists:any(Found, List) of
true ->
yes;
false ->
no
end.
The lists:any/2
function takes as its first argument a predicate function that's called with each element of the second argument, a list, until either the predicate returns true or the list is exhausted. The predicate here is the anonymous function Found
, which returns the result of passing its list element argument to lists:member/2
. But the lists:member/2
function also traverses its list argument, returning true if its first argument matches a list element or false otherwise, which means the Found
predicate checks the entire list every time lists:any/2
calls it, which is quite inefficient.
Your function also returns yes
or no
, but according to your description it's supposed to return a boolean.
The easiest way to fix your function is to return the result of lists:member/2
, since it traverses a list looking for a match:
contains_point(Point, List) ->
lists:member(Point, List).
Alternatively, if you don't want to use the lists
module, you can write the function to traverse the list itself and check for matches:
contains_point(_, []) -> false;
contains_point(Point, [Point|_]) -> true;
contains_point(Point, [_|Tail]) ->
contains_point(Point, Tail).
Point
value and so they match.Point
doesn't match the head of the list; it calls contains_point/2
recursively with Point
and the tail of list.This approach is essentially what lists:member/2
does.