Rahul
Rahul

Reputation: 1579

Difference between a List and a Tuple in Erlang

What is the main difference between a list and a tuple in Erlang. How does pattern matching differentiate each.?

Upvotes: 2

Views: 3810

Answers (4)

Pascal
Pascal

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

aronisstav
aronisstav

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

HIRA THAKUR
HIRA THAKUR

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

tkowal
tkowal

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:

  • empty list
  • or it consits of head (first element) and tail.

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

Related Questions