"Use the below function with two parameters:
nth :: (a,a,a,a,a) -> Int -> a
where the Int value should return the Int-th value of the five-element tuple." I tried:
nth (a,b,c,d,e) x = (a,b,c,d,e) !! x
But GHC gave me an error message:
file.hs:11:21: error:
* Couldn't match expected type `[a1]'
with actual type `(a, b, c, d, e)'
* In the first argument of `(!!)', namely `(a, b, c, d, e)'
In the expression: (a, b, c, d, e) !! x
In an equation for `nth':
nth (a, b, c, d, e) x = (a, b, c, d, e) !! x
* Relevant bindings include
e :: e (bound at file.hs:11:14)
d :: d (bound at file.hs:11:12)
c :: c (bound at file.hs:11:10)
b :: b (bound at file.hs:11:8)
a :: a (bound at file.hs:11:6)
nth :: (a, b, c, d, e) -> Int -> a1
(bound at file.hs:11:1)
What should I do? How should I write the tuple part of this equation? Thanks for your answers in advance!
CodePudding user response:
You can not use (!!) :: [a] -> Int -> a
since, as the signature says, it works on lists, not tuples. You can work with pattern matching and implement this as:
nth :: (a, a, a, a, a) -> Int -> a
nth (a, _, _, _, _) 0 = a
nth (_, b, _, _, _) 1 = b
nth (_, _, c, _, _) 2 = c
nth (_, _, _, d, _) 3 = d
nth (_, _, _, _, e) 4 = e
There have been proposals where a 3-tuple is defined as (a, (b, c))
such that it is thus a recursive structure where an n-tuple is defined as a 2-tuple with an n-1-tuple as second item. But this is not the case (at the moment).
CodePudding user response:
You can avoid some of the repetition from the existing pattern-matching solutions by separating the pattern match for the tuple from the match on n
:
nth :: (a, a, a, a, a) -> Int -> a
nth (a, b, c, d, e) n = case n of
0 -> a
1 -> b
2 -> c
3 -> d
4 -> e
You should also consider what you want to happen when n is not in the range [0, 4]
. As written, you will get a non-exhaustive pattern error at runtime. It would be more honest to either return a Maybe a
or take a more constrained type as input, like
data QuintupleIndex = Zero | One | Two | Three | Four
CodePudding user response:
The (!!)
function only works on lists.
For tuples, at least those of more than 2 elements, the only way to access the elements is by direct pattern matching:
nth :: (a,a,a,a,a) -> Int -> a
nth (a, _, _, _, _) 0 = a
nth (_, a, _, _, _) 1 = a
nth (_, _, a, _, _) 2 = a
nth (_, _, _, a, _) 3 = a
nth (_, _, _, _, a) 4 = a
(note the _
s, which mean "I don't care what this value" is. You could give them a name instead - eg match on (a, b, c, d, e)
on each line and have the returned value being a
on the first line, b
on the second and so on. But it's less visual "noise" to only name the values you care about.)
Also note that this function will crash with a "non-exhaustive patterns" error if the integer argument is anything outside 0-4. But using (!!)
on a list of 5 elements has a similar flaw. You can easily add a default case to the end, although that's not easy when working with a completely generic type a
because there is no value that will work as a return value of any type the function might be called with!
CodePudding user response:
a simple solution using guards is as follows:
nth :: (a,a,a,a,a) -> Int -> a
nth (a, b, c, d, e) i
| i == 0 = a
| i == 1 = b
| i == 2 = c
| i == 3 = d
| otherwise = e