Saturday, 30 April 2016

Haskell: tuples


Tuples are just like lists to store collection of data. But following are key differences between list and tuple.

1. Unlike list, tuple is heterogeneous, A tuple can store any kind of data.
Prelude> let emp1 = (1, "Hari Krisna", 23456.789)
Prelude> emp1
(1,"Hari Krisna",23456.789)
 
2. Tuples are immutable, you can't cons (:) to a tuple.

How to define a tuple
You can define a tuple, by using parentheses with elements delimited by commas.

For example, let stud1 = (514, "Sailaja", "Bangalore") defines a student record, where 514 specifies student id, Sailaja specifies student name, Bangalore specifies student address.
Prelude> let stud1 = (514, "Sailaja", "Bangalore")
Prelude> let stud2 = (512, "Krishna", "Ongole")
Prelude> let stud3 = (521, "Hari", "Delhi")
Prelude> 
Prelude> stud1
(514,"Sailaja","Bangalore")
Prelude> stud2
(512,"Krishna","Ongole")
Prelude> stud3
(521,"Hari","Delhi")


tuples within lists
A list can have tuples, all the tuples must follow similar properties.
Prelude> let students = [(1, "ptr", "Nayan"), (2, "Hari Krishna", "Gurram"), (3, "Phalgun", "Garimella")]
Prelude> students
[(1,"ptr","Nayan"),(2,"Hari Krishna","Gurram"),(3,"Phalgun","Garimella")]
Prelude> 
Prelude> students !! 0
(1,"ptr","Nayan")
Prelude> 
Prelude> students !! 1
(2,"Hari Krishna","Gurram")
Prelude> 
Prelude> students !! 2
(3,"Phalgun","Garimella")
Prelude>


You will get error, if a list has tuples of different properties.

For example, sample = [(2, 3), (5, 7, 9)] contains a tuple of two integers (2, 3), and a tuple of 3 integer elements (5, 7, 9), here is a mismatch, because first tuple has 2 integers, where as 2nd tuple has 3 integers so Haskell throws an error.
Prelude> let sample = [(2, 3), (5, 7, 9)]

<interactive>:132:23:
    Couldn't match expected type (t, t1)
                with actual type (Integer, Integer, Integer)
    Relevant bindings include
      sample :: [(t, t1)] (bound at <interactive>:132:5)
    In the expression: (5, 7, 9)
    In the expression: [(2, 3), (5, 7, 9)]
    In an equation for sample: sample = [(2, 3), (5, 7, 9)]


Nested tuples
Just like lists, a tuple can has other tuple in it.
Prelude> ((2, 3), (5, 7), (11, 13))
((2,3),(5,7),(11,13))
Prelude> 
Prelude> (('a', 'e'), ('i', 'o'))
(('a','e'),('i','o'))
Prelude> 
Prelude> ((1, 1), (2, 4), (3, 9), (4, 16))
((1,1),(2,4),(3,9),(4,16))


Retrieving values from a tuple
fst : Get the first element in a tuple
fst takes a tuple with 2 elements and return first element.

snd : get second element in a tuple
snd takes a tuple with 2 elements and return second element.

Note
Both fst, snd are not applicable to tuples that don't contain 2 elements.
Prelude> fst (2, 3)
2
Prelude> snd (2, 3)
3


As you observe the signature of fst and snd functions, they are restricted to the tuples that has only two elements, trying to use for the tuples which don't have exactly two elements throws an error.
Prelude> :t fst
fst :: (a, b) -> a
Prelude> 
Prelude> :t snd
snd :: (a, b) -> b
Prelude>
Prelude> 
Prelude> fst (2, 3, 5)
<interactive>:144:5:
    Couldn't match expected type (a, b0)
                with actual type (Integer, Integer, Integer)
    Relevant bindings include it :: a (bound at <interactive>:144:1)
    In the first argument of fst, namely (2, 3, 5)
    In the expression: fst (2, 3, 5)
    In an equation for it: it = fst (2, 3, 5)
Prelude> 
Prelude> snd (2, 3, 5)

<interactive>:146:5:
    Couldn't match expected type (a0, b)
                with actual type (Integer, Integer, Integer)
    Relevant bindings include it :: b (bound at <interactive>:146:1)
    In the first argument of snd, namely (2, 3, 5)
    In the expression: snd (2, 3, 5)
    In an equation for it: it = snd (2, 3, 5)


zip: Map two lists as list of tuples
Suppose you are maintaining two lists one for countries and other for country capitals. You want to map countries to their capitals; you can do this by using zip function easily. zip takes two lists, it creates a list of tuples by joining the matching elements into pairs.
Prelude> let countries = ["Mali", "Oman", "Russia", "Germany"]
Prelude> let capitals = ["Bamako", "Muscat", "Moscow", "Berlin"]
Prelude> zip countries capitals
[("Mali","Bamako"),("Oman","Muscat"),("Russia","Moscow"),("Germany","Berlin")]


If two lists are of different length, then the longer one gets cut off to match the length of the shorter one.
Prelude> let countries = ["Mali", "Oman"]
Prelude> let capitals = ["Bamako", "Muscat", "Moscow", "Berlin"]
Prelude> zip countries capitals
[("Mali","Bamako"),("Oman","Muscat")]


Previous                                                 Next                                                 Home

No comments:

Post a Comment