How do I convert a list to a tuple in Haskell?

后端 未结 7 682
隐瞒了意图╮
隐瞒了意图╮ 2020-12-01 07:55

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

[1,2,3,4,5,6] -> (1,2,3,4,5,6)
相关标签:
7条回答
  • 2020-12-01 08:17

    I don't think it's possible to do this in Haskell, for a list of arbitrary length not known at compile time. Template Haskell can't do it because it operates only at compile time. I ran into a case where I needed to do precisely this, and I had to work around it. A database library expects different-length tuples for query arguments, but I have an arbitrary-length list. So I have to skirt around the library interface. It would be nice if it could take a list.

    Basically the issue is that different-length tuples are different types. But the Haskell compiler has to know at compile type what types might exist at runtime. Converting an arbitrary-length list into a tuple at run time could create some type it didn't know about at compile time.

    0 讨论(0)
  • 2020-12-01 08:24

    If feel like I am about to advise you to point a gun at your foot and trust you not to shoot.

    > list2Tuple lst = read $ "(" ++ (init.tail.show) lst ++ ")"
    > list2Tuple [1,2,3] :: (Int, Int, Int)
    (1,2,3)
    > list2Tuple [1,2,3,4] :: (Int, Int, Int, Int)
    (1,2,3,4)
    

    This will work up to the what ever length of tuple Show and Read are defined for.

    0 讨论(0)
  • 2020-12-01 08:24

    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.

    0 讨论(0)
  • 2020-12-01 08:25

    I find it difficult to make cogent explanations of Template Haskell manipulations, but here is a demonstration:

    > :m +Language.Haskell.TH
    > :set -XTemplateHaskell
    > runQ [| [1,2,3,4,5,6] |] >>= putStrLn . pprint
    [1, 2, 3, 4, 5, 6]
    > runQ [| [1,2,3,4,5,6] |] >>= \ (ListE exps) -> putStrLn (pprint (TupE exps))
    (1, 2, 3, 4, 5, 6)
    
    0 讨论(0)
  • 2020-12-01 08:36

    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.

    0 讨论(0)
  • 2020-12-01 08:39

    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!

    0 讨论(0)
提交回复
热议问题