Reputation: 1579
What is the main difference between a list and a tuple in Erlang. How does pattern matching differentiate each.?
Upvotes: 2
Views: 3810
Reputation: 14042
I'll try to answer when to use tuple or list. Both of them are collection of erlang terms, and as they are not mutable as any other erlang variable, the difference is not fixed size or not.
Tuple : You will use a tuple when you know how many terms it will contain when you write your program, when all the terms have a special meaning and you will be able to access them using their position. A good example can be the coordinates of a point P={X,Y,Z}.
When you think that future evolution of your application may introduce new term in the collection, you will probably choose a record: a named tuple with some syntax facility to access each element by name, an example is a record representing an employee (name, address, birth, code, list of skills) maybe you will add later a phone number, an email...
A frequent usage is to return multiple values or tagged values ({ok,Value}, {error,Reason}).
List : A list can be defined recursively: it is either the empty list [], or a construction of 2 elements, the Head and the Tail, where the head can be any erlang term, and the tail is a list (I am speaking of proper list only). You will use this when you cannot know when you write your program how many term this list will contain. A server may store in a list the name of connected client. you will generally look in a list recursively, so the elements are very often consistent (list of name, list of pid...) or "typed" using tuple like in proplist.
Those 2 elements are the basic bricks for more complex data structure (like trees°
Upvotes: 2
Reputation: 7914
They are different data types, with different implementations and cost of operations:
Tuples, are usually used to represent a collection of a fixed number of values of possibly different types, where you want to be able to access any of the values in constant time. They are also used to distinguish between a normal return (e.g. {ok, Value}
) from an error return (e.g. error
) without using an exception.
Lists, are usually used to represent a collection of an arbitrary number of values of the same type, where you want to be able to handle the elements in an iterative fashion (e.g. with a map
or fold
operation).
Patterns that match tuples (e.g. {A,B,C}
), usually match against a specific size of tuple and/or specific values for some of the elements.
Patterns that match lists (e.g. [H|T]
), usually match against the first and rest elements.
Upvotes: 5
Reputation: 17757
Essentially,both are used for completely different purpose.
Tuples
1.syntax : {a ,b, c .. z}.
2.Purpose : When you want some data to be grouped in a certain pattern,you will use a tuple.
eg.I need yesterdays sunset and sunrise time,I am more likely to use a tuple here rather than a list,record,ordict etc because it fits the bill perfectly.
{sunrise,7.00},{sunset,18.30}
3.Pattern Matching : Tuple supports Pattern Matching.This is how its done
tuplePatternMatching({A,B},{C,D}) ->
io:format("~p ~p",A @ B),
io:format("~p ~p",C @ D) . #sunrise @ 7 #sunset at 18.30
List
1.syntax : [a ,b, c .. z].
2.Purpose : Generally,we use it when we want some data,sharing common nature is to be grouped together.
eg.I need sunset time of last 7 days,I am more likely to use a List here rather than a tuple,record,ordict etc.
Sunset = [18,18.01,18.02,18.03,18.04,18.05,18.06]
3.Pattern Matching,Recursion,Operations : List too supports Pattern Matching,but we use it for different purposes as well. It consist of head and tail.This forms the basis of Recursion in a language like Erlang which does not support looping construct like while/for.
Head in above list is 18 Tail is the remaining part : 18.01,18.02,18.03,18.04,18.05,18.06
Sunset = [ 18 | 18.01,18.02,18.03,18.04,18.05,18.06] # i.e [ A | B,C] = [A,B,C]
Sample program to print every element :
SunsetFunction([]) -> ok;
SunsetFunction([H|T) ->
io:format("~p ~p",H),
SunsetFunction(T).
A list can consist of any datatype :
[Atom,{Tuple,Var},List] eg. ['hello@rahul',{rahul,Coder},[20,30,40]]
Upvotes: 2
Reputation: 9289
The link provided by @Arunmu answers the first part of question. You can differentiate between those data structures using guards:
do_something(List) when is_list(List) ->
io:format("I got the list ~p", [List]);
do_something(Tuple) when is_tuple(Tuple) ->
io:format("I got tuple ~p", [Tuple]).
But in practice, you usually design your functions in such a way, that you know, if it takes tuple or list and use pattern match to get elements. You can pattern match list like this, if you know how many elements it has:
[A, B, C] = [1, 2, 3] # A becomes 1, B becomes 2, C becomes 3
But usually, you can take advantage of lists recursive nature. Every lists is either:
This are the patter matches, you will often use:
[H | T] = [1, 2, 3] # H becomes 1, T becomes [2, 3]
[H2 | T2] = [1] # H becomes 1, T becomes []
[H3 | T3] = [] # gives error badmatch
So functions for processing lists are usually recursive:
do_stuff([]) ->
finished; # there are no more elements
do_stuff([H | T]) ->
do_something_with(H),
do_stuff(T).
So you don't have to know, what the length of list is to process all the elements. When you use tuples, you know, how big they are. Typical pattern matches are:
{A, B} = {lol, rotfl} # A becomes lol, B becomes rotfl
{A, _} = {troll, trololo} # A becomes troll
Tuples are very often used for tagging things. When you receive message from another process, you use receive
receive
Request -> do_something_with(Request)
end.
But we don't know, if the request is valid or maybe some other process send something by mistake. We can tag the Request with atom request
and make sure, that calling process always specifies its own pid:
receive
{request, Pid, Request} ->
Response = do_something_with(Request),
Pid ! Response;
_ -> ignore_message
end.
Upvotes: 10