简体   繁体   中英

Convert various length of List to Tuple in Haskell

I want convert list [[1,2,3],[2,3]] to tuple [(1,2,3),(2,3)]

my function:

thr [a,b,c] = (a,b,c)
tupel [] = []
tupel (x:xs) = if length x==3 then thr x:(tupel xs) else (tupel xs)

this work with three Elements.

thr [a,b,c] = (a,b,c)
two [a,b]   = (a,b)
tupel [] = []
tupel (x:xs) = if length x==3 then thr x:(tupel xs) else two x:(tupel xs)

why don´t work this?

Error: Type error in application * Expression: two x: tupel2 xs Term: two x Type: (a,a) * Does not match: (a,a,a)

Ok, let's skip to the end and fire up ghci. What type does [(1,2,3),(1,2)] have?

ghci> :t [(1,2,3),(1,2)]

<interactive>:1:10:
     Couldn't match expected type `(t0, t1, t2)'
                 with actual type `(t3, t4)'
     In the expression: (1, 2)
     In the expression: [(1, 2, 3), (1, 2)]
     In an equation for `it': it = [(1, 2, 3), (1, 2)]

That error isn't because I entered the data wrong, it's because [(1,2,3),(1,2)] isn't valid haskell.

A list in haskell can hold an unlimited number of items, with the caveat that all items must be of the same type.

It may seem weird, but (1,2,3) and (1,2) aren't of the same type. One is a 3-tuple, one is a 2-tuple.

A tuple is sort of the opposite of a list - it can only hold a specific number of items, but they can be of a bunch of different types. Tuple types are defined by the sequence of types given by the items they contain.

So a tuple of 3 integers (or, as ghc will show, number-like things) is of different type than a tuple of 2 integers. We can see this directly using the :t operator in ghci:

ghci> :t (1,2,3)
(1,2,3) :: (Num t1, Num t2, Num t) => (t, t1, t2)
ghci> :t (1,2)
(1,2) :: (Num t1, Num t) => (t, t1)

See that (2,3,4) and (2,3) have types that match (1,2,3) and (1,2) 's respectively:

ghci> :t (2,3,4)
(2,3,4) :: (Num t1, Num t2, Num t) => (t, t1, t2)
ghci> :t (2,3)
(2,3) :: (Num t1, Num t) => (t, t1)

That's because (2,3,4) and (1,2,3) are two values that have the same type. The same is true for (1,2) and (2,3) .

So there is no function to convert [[1,2,3],[1,2]] to [(1,2,3),(1,2)] in haskell because the result of such a function could not possibly type-check.

Tuples have different types, so there's no single (simple) type to give to your tupel function.

However, by stepping back and using a sum type you can encode all the variants you wish to return:

data T a
    = One   a
    | Two   a a
    | Three a a a
    deriving Show

two :: [a] -> T a
two [a,b]   = Two   a b

thr :: [a] -> T a
thr [a,b,c] = Three a b c

tuple :: [[a]] -> [T a]
tuple []           = []
tuple ([a,b]  :xs) = Two   a b   : tuple xs
tuple ([a,b,c]:xs) = Three a b c : tuple xs
tuple (_ : xs)     =               tuple xs

Note how we distinguish between the two and three-element list case via pattern matching.

And secondly, it is good practice to write down your expected type for each function -- this will help resolve confusion in the design, and quickly reveal logical errors like the two different tuple types.

Running this, you can see how it groups things nicely:

*Main> tuple [[1,2,3],[2,3]] 
[Three 1 2 3,Two 2 3]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM