## Haskell – 9 – elementi fondamentali – 3

Continuo da qui, copio qui, scrollare fino a “Tuples: Combining Different Data Items”.

Tuples: combinare elementi di dati diversi
So far, we have seen how to pass multiple values to a function, but not how a function can return more than one result value. We can achieve this by using tuples:

`addMul :: Num a => a -> a -> (a, a)`
`addMul x y = (x + y, x * y)`

A tuple combines multiple components (two integer values, in the above example) into one compound value. The compound value can be manipulated as a single entity and, in particular, be returned as a value from a function.

However, the construction of a compound value is only half of the story. We also need a method for decomposing such values. We achieve this by using a notation dual to that of tuple construction:

`fst (x, y) = x`
`snd (x, y) = y`

Note: Both `fst` and `snd` are already defined in the `Prelude`.

In the argument of `fst`, we do not use a variable to refer to the compound argument as a whole. Instead, we decompose the pair into its components `x` and `y` — this is also called decomposition by pattern matching.

``````Prelude> :l addMul
[1 of 1] Compiling Main             ( addMul.hs, interpreted )
(11,30)
11
30``````

The combined use of addMul and fst behaves as follows:

``````fst (addMul 5 6) ⇒  fst (5 + 6,  5 * 6)
⇒  fst (11,  30)
⇒  11``````

The types of `fst` and `snd`. So far, we omitted the type annotations from the definitions of `fst` and `snd`. Generally, the Haskell system will automatically infer the types of definitions that lack a signature — however, it is good style to explicitly provide signatures. In all our previous definitions, the type was determined by the operations we applied to the arguments. For example `max` was restricted to work on types which are members of the type class `Ord`, since we needed the operator `>=`, which can only compare certain types of values. The functions `fst` and `snd` are different, though. We don’t actually apply any function or operation to `x` or `y`, so they could be values of any type. In fact, `x` and `y` don’t even have to have the same type. Hence, we can just use type variables to represent the types of `x` and `y` without having to add any type class restrictions:

``````fst :: (a, b) -> a
fst (x, y)  = x

snd :: (a, b) -> b
snd (x, y)  = y``````

Functions like `fst` and `snd`, which can handle arguments of any type are called (parametric) polymorphic functions.

Example: points. Tuples are not just useful to return multiple results, but also for the representation of data items that cannot be modeled by one primitive value alone. A useful example is given by the points in a 2-dimensional Cartesian coordinate system: they can be represented by a pair of integer values. To avoid having to write the less informative `(Int, Int)` whenever we denote the type of a point, we can introduce a new type name — similar to the introduction of names for repeatedly used values, which we discussed earlier

`type Point = (Int, Int)`

With this definition, we define some simple operations on points:

``````-- origin of the coordinate system
--
origin :: Point
origin  = (0, 0)

-- move a given point to the right
--
moveRight :: Point -> Int -> Point
moveRight (x, y) distance  = (x + distance, y)

-- move a given point to upwards
--
moveUp :: Point -> Int -> Point
moveUp (x, y) distance  = (x, y + distance)``````

Example: colour points. When we extend points to include a colour, another important property of tuples becomes obvious: tuple components may be of different types. Hence, if we denote colour values with a textual (string) representation, we have

``````-- we represent colours by strings
--
type Colour = String

-- new name for the type of colour points
--
type ColourPoint = (Int, Int, Colour)``````

which enables the following operations on colour points:

``````-- origin of the coordinate system in a given colour
--
origin :: Colour -> ColourPoint
origin colour  = (0, 0, colour)

-- move a colour point vertically and horizontally
--
move :: ColourPoint -> Int -> Int -> ColourPoint
move (x, y, colour) xDistance yDistance
= (x + xDistance, y + yDistance, colour)

-- compute the distance between two colour points
--
distance :: ColourPoint -> ColourPoint -> Float
distance (x1, y1, colour1) (x2, y2, colour2)
= sqrt (fromIntegral (dx * dx + dy * dy))
where
dx = x2 - x1
dy = y2 - y1``````

Note how we use a `where` clause in the last definition to avoid repeating the expressions `x2 - x1` and `y2 - y1`. The standard function `fromIntegral` converts any integral type to any other numeric type. Its signature is

`fromIntegral :: (Integral a, Num b) => a -> b`

Important symmetries in Haskell. If we compare the syntax of values and types of tuples, we see that they correspond. For example, consider

`(10, 15, "green") :: (Int, Int, String)`

If we replace the values `10`, `15`, and `"green"` with their respective types `Int`, `Int`, and `String`, we obtain the type of the tuple. Moreover, we have a correspondence between term construction and term decomposition (also called pattern matching). Consider,

`startPoint = (0, 0, "black")`
`colourOfPoint (x, y, colour) = colour`

If we replace the components in the tuple construction (`0`, `0`, and `"black"`) by variable names (in this case `x`, `y`, `colour`), we arrive at the pattern that can be used to decompose the corresponding tuple.

Nomi speciali per alcune tuples
The following table lists a number of tuple types and their names:

``````# Expression          	    Name
0 () 	                    Unit
1 n/a 	                    n/a
2 (x_1, x_2) 	            Pair
3 (x_1, x_2, x_3)           Triple
4 (x_1, x_2, x_3, x_4) 	    Quadruple
5 (x_1, x_2, x_3, x_4, x_5) Quintuple
⋮
n (x_1,..., x_n)            n-tuple``````

🤢

Posta un commento o usa questo indirizzo per il trackback.