开发者

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

开发者 https://www.devze.com 2023-01-01 10:22 出处:网络
开发者_如何学JAVAHow can I best convert a list to a tuple in Haskell: [1,2,3,4,5,6] -> (1,2,3,4,5,6)
开发者_如何学JAVA

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

[1,2,3,4,5,6] -> (1,2,3,4,5,6)


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!


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.


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.


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.


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)


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.


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


When dealing with command line arguments you can use getArgs, that function will give you a list with strings:

getArgs :: IO [String] 

Link: https://hackage.haskell.org/package/base-4.16.0.0/docs/System-Environment.html#v:getArgs

When I work with command line arguments I prefer to work with tuples instead of a list, so I convert the list to a tuple. See below:

import System.Environment

main = do
    args <- getArgs
    let (a:b:c) = args
    print a

Calling the program (in PowerShell):

PS C:\Haskell> runghc convertListToTuple goodday to you
"goodday"
0

精彩评论

暂无评论...
验证码 换一张
取 消