tags:

views:

307

answers:

4

How can I best convert a list to a tuple in Haskell:

[1,2,3,4,5,6] -> (1,2,3,4,5,6)
+20  A: 

In a general way, you can't. Each size of tuple is a distinct type, whereas lists of any length are a single type. Thus, there's no good way to write a function that takes a list and returns a tuple of the same length--it wouldn't have a well-defined return type.

For instance, you could have functions like:

tuplify2 :: [a] -> (a,a)
tuplify2 [x,y] = (x,y)

tuplify3 :: [a] -> (a,a,a)
tuplify3 [x,y,z] = (x,y,z)

...but not one that does the job of both.

You can write a generic version using various kinds of meta-programming, but you'd rarely want to.

Note that the same problem applies to other things, such as writing class instances for various tuples--take a look at the source code for Data.Tuple from the standard libraries!

camccann
+4  A: 

Tuples and lists are very different things. About the best you can do is to manually write a conversion function:

toTuple :: [a] -> (a,a,a,a,a,a)
toTuple [a,b,c,d,e,f] = (a,b,c,d,e,f)

Notice how different the types are: the single variable of the list expands to six variables for the tuple. So you'll need one function for each size of tuple.

Nathan Sanders
You and camccann beat me. That's it, the best he can do is N functions and then a handler for calling one of these for a given N.
Spidey
@Spidey: Either that or learn how to use Template Haskell!
camccann
+2  A: 

You can in fact do better than manually writing one function per tuple-size if you use quasi-quotation [1]. However, I would wonder about code where you expect to use this generically.

[1] http://www.haskell.org/haskellwiki/Quasiquotation

StevenC
Hoping to work up a little example later today when I have time and edit my comment with it...
StevenC
Quasiquotation being part of Template Haskell, I believe, which is the meta-programming I referred to. In the end this is still producing one function per tuple size, it's just writing compile-time code to do it for you instead of writing them by hand. I've yet to get the hang of TH myself, so I look forward to seeing your example!
camccann
Edward Kmett beat me to it. I thought I'd done it with quasiquotes before, but I guess it was just TH. Sorry.
StevenC
+6  A: 

Template Haskell is as close as you can get due to type checking if you want to extract a variable number of elements, since (a,b) and (a,b,c) have different types.

{-# LANGUAGE TemplateHaskell #-}
import Language.Haskell.TH
tuple :: Int -> ExpQ
tuple n = do
    ns <- replicateM n (newName "x")
    lamE [foldr (\x y -> conP '(:) [varP x,y]) wildP ns] (tupE $ map varE ns)

Then:

$(tuple 6) [1,2,3,4,5,6] == (1,2,3,4,5,6)
$(tuple 3) "abc" == ('a','b','c')

But in general, if you need this answer, then you're asking the wrong question somewhere.

If you just want flat random access, perhaps the better option would be to use an Array.

Edward Kmett