Tuples

advertisement
COMPUTER SCIENCE 123
Foundations of Computer Science
6. Tuples
Summary: This lecture introduces tuples in Haskell.
Reference: Thompson Sections 5.1–2
© R.L. While, 2000–3
Tuples
•
•
Most data comes with a structure
− e.g. amounts of money are expressed in dollars and
cents, i.e. a pair of numbers
In Haskell, this could be expressed as a 2-tuple (or a
pair)
(4, 73)
•
•
A tuple is a sequence of two or more values of any type
enclosed in brackets and separated by commas
− the type of a tuple is determined by the types of its
components
For example:
(4, 73)
(3, True)
(25, "isn't", 's')
("", 1999)
("", "1999")
•
•
::
::
::
::
::
(Int, Int)
(Int, Bool)
(Int, String, Char)
(String, Int)
(String, String)
Note that each of these values has a different type
− the word “tuples” refers to a group of types, not a
single type
Also note that the syntax for the values and for the types
is identical
− in each case, the brackets and commas match
cs123 Foundations of CS
1 of 11
6. Tuples
Tuple operations
•
•
•
The only thing we can do with a tuple is to take it apart!
− of course, once we have taken it apart, we can
process the components using all of the usual
operations
We dissect a tuple by placing it on the left-hand side of an
equation and naming the components
− this is known technically as pattern-matching
Consider a function addCash that adds together two
amounts of money
− e.g. addCash (2, 85) (1, 99) = (4, 84)
addCash :: (Int, Int) -> (Int, Int)
-> (Int, Int)
-- addCash x y returns the normalised sum
-- of cash amounts x and y
addCash (x, x') (y, y')
= (x + y + z `div` 100, z `mod` 100)
where z = x' + y'
•
Consider a function mulCash that multiplies amounts of
money
− e.g. mulCash (2, 99) 4 = (11, 96)
mulCash :: (Int, Int) -> Int -> (Int, Int)
-- mulCash x k returns the normalised
-- product of cash amount x and k
mulCash (x, x') k
= (x * k + z `div` 100, z `mod` 100)
where z = x' * k
•
Note that the first argument to each of these functions has
the type (Int, Int)
− we can’t call either of them with (3, True) or
(25, "isn't", 's') or ("", 1999) or
("", "1999") or …
cs123 Foundations of CS
2 of 11
6. Tuples
Tuples containing tuples
•
•
A tuple can contain values of any type
− including other tuples
For example:
(4, 9, 0)
:: (Int, Int, Int)
(4, (9, 0)) :: (Int, (Int, Int))
((4, 9), 0) :: ((Int, Int), Int)
(3, True, "/", "[a]")
:: (Int, Bool, String, String)
((3, True), "/", "[a]")
:: ((Int, Bool), String, String)
(3, (True, "/"), "[a]")
:: (Int, (Bool, String), String)
(3, True, ("/", "[a]"))
:: (Int, Bool, (String, String))
((3, True), ("/", "[a]"))
:: ((Int, Bool), (String, String))
((3, True, "/"), "[a]")
:: ((Int, Bool, String), String)
(3, (True, "/", "[a]"))
:: (Int, (Bool, String, String))
•
•
•
Again, each of these values has a different type
Again note that the syntax for the values and for the types
is identical
− in each case, the brackets and commas match
Exercise: write down the other four tuple-types that
contain the same values as the seven above
cs123 Foundations of CS
3 of 11
6. Tuples
Examples
•
Consider a function addMarks that takes a name and a
set of assessment marks and calculates a final mark
addMarks :: (String, (Int, Int, Int)) ->
(String, Int)
-- addMarks (n, as) returns a
-- final mark for n
addMarks (n, (a1, a2, ex))
= (n, a1 + a2 + ex)
•
Or suppose we add the rule that a student fails overall if
they fail to submit any piece of the assessment
addMarks :: (String, (Int, Int, Int)) ->
(String, Int)
-- addMarks (n, as) returns a
-- final mark for n, if n worked hard
addMarks (n, (a1, a2, ex))
| a1==0 || a2==0 || ex==0 = (n, 0)
| otherwise
= (n, a1+a2+ex)
•
Tuples can be taken apart in local definitions
mark :: (String, (Int, Int, Int)) -> Int
-- mark (n, as) returns n's mark
mark z = m
where (n', m) = addMarks z
cs123 Foundations of CS
4 of 11
6. Tuples
Type synonyms
•
•
•
•
Readability is the key to good programming
− the easier and more quickly someone else can
understand your program, the better
One important aspect is your choice of names
− the name of a function should always reflect
what the function does
Another key aspect is the names of types
− e.g. what does (Int, Int) mean?
Haskell allows us to rename a type using a type
synonym declaration
− for example
type Cash = (Int, Int)
type
type
type
type
•
•
Name
Marks
StudentEntry
StudentTotal
=
=
=
=
String
(Int, Int, Int)
(Name, Marks)
(Name, Int)
This is almost always a good idea
The type declarations of the functions from above become
addCash :: Cash -> Cash -> Cash
mulCash :: Cash -> Int -> Cash
addMarks :: StudentEntry -> StudentTotal
•
Their specifications and equations are unchanged
cs123 Foundations of CS
5 of 11
6. Tuples
An extended example—rational numbers
•
A rational number is a fraction a b
− often a vulgar fraction, i.e. a >
e.g.
•
•
1
2
32
31
22
7
−
19
99
−
9
1
b
0
1
Rational numbers are used in some languages for doing
exact (or infinite-precision) arithmetic
− with a rational representation, all arithmetic is
performed exactly, and only output involves any
inaccuracy
− using a floating-point representation for arithmetic can
lead to unpredictable inaccuracies
A rational number can be represented as a pair of integers
type Rat = (Int, Int)
cs123 Foundations of CS
6 of 11
6. Tuples
Normalisation
•
A normalised rational number obeys three rules
− the denominator is positive
− a negative rational − a b is represented as
e.g.
−
0
−
19
99
=
−a
b
−19
99
is represented in the form
0
1
zeroRat :: Rat
-- zeroRat returns normalised 0
zeroRat = (0, 1)
−
it is in its lowest terms,
− i.e. a and b have no common factors
a
b
e.g.
•
a
=
b
18
20
z
where
z = gcd(a, b)
z
=
9
10
In Haskell:
normaliseRat :: Rat -> Rat
-- normaliseRat r returns normalised r
normaliseRat (a, b)
| a == 0 = zeroRat
| a /= 0 = (a * signum b `div` z,
b * signum b `div` z)
where z = gcd a b
−
−
−
the guards take care of 0
dividing top and bottom by gcd a b ensures that the
Rat is in its lowest terms
multiplying top and bottom by signum b ensures
that the denominator is positive
cs123 Foundations of CS
7 of 11
6. Tuples
Adding and subtracting rational numbers
•
Addition is defined by the equation
a
b
•
+
c
d
=
ad + bc
bd
In Haskell:
addRat :: Rat -> Rat -> Rat
-- addRat r r' returns r + r'
addRat (a, b) (c, d)
= normaliseRat (a * d + b * c, b * d)
•
Subtraction is defined by the equation
a
b
•
−
c
d
=
ad − bc
bd
In Haskell:
subRat :: Rat -> Rat -> Rat
-- subRat r r' returns r - r'
subRat (a, b) (c, d)
= normaliseRat (a * d - b * c, b * d)
cs123 Foundations of CS
8 of 11
6. Tuples
Multiplying and dividing rational numbers
•
Multiplication is defined by the equation
a
b
•
×
c
d
=
ac
bd
In Haskell:
mulRat :: Rat -> Rat -> Rat
-- mulRat r r' returns r * r'
mulRat (a, b) (c, d)
= normaliseRat (a * c, b * d)
•
Division is defined by the equation
a
b
•
÷
c
d
=
ad
bc
− of course the divisor must not be zero
In Haskell:
divRat :: Rat -> Rat -> Rat
-- pre: r' isn't zero
-- divRat r r' returns r / r'
divRat (a, b) (c, d)
= normaliseRat (a * d, b * c)
cs123 Foundations of CS
9 of 11
6. Tuples
Comparing rational numbers
•
Equality is defined by the equation
a
b
•
c
d
==
iff
==
ad
bc
In Haskell:
eqRat :: Rat -> Rat -> Bool
-- eqRat r r' returns r == r'
eqRat (a, b) (c, d) = a * d == b * c
•
Orderings are defined by the equation
a
b
•
<
c
d
iff
ad
<
bc
In Haskell:
ltRat :: Rat -> Rat -> Bool
-- ltRat r r' returns r < r'
ltRat (a, b) (c, d) = a * d < b * c
cs123 Foundations of CS
10 of 11
6. Tuples
Displaying rational numbers
•
If we just apply show to a Rat, it will appear in tuple
notation
Prelude>
show zeroRat
"(0,1)"
(132 reductions, 229 cells)
•
Better is to define a function showRat that returns a
string using the a / b format
− or just a for integer Rats
showRat :: Rat -> String
-- showRat r returns a string containing r
showRat (a, b)
| b == 1 = show a
| b > 1 = show a ++ " / " ++ show b
cs123 Foundations of CS
11 of 11
6. Tuples
Download