如何在Haskell中最好地将列表转换为元组:
[1,2,3,4,5,6] -> (1,2,3,4,5,6)
答案 0 :(得分:45)
一般来说,你不能。元组的每个大小都是不同的类型,而任何长度的列表都是单一类型。因此,没有好的方法来编写一个获取列表并返回相同长度的元组的函数 - 它没有明确定义的返回类型。
例如,您可以使用以下函数:
tuplify2 :: [a] -> (a,a)
tuplify2 [x,y] = (x,y)
tuplify3 :: [a] -> (a,a,a)
tuplify3 [x,y,z] = (x,y,z)
......但不是一个能完成两者工作的人。
你可以使用各种元编程来编写通用版本,但你很少想要。
请注意,同样的问题适用于其他事情,例如为各种元组编写类实例 - 从标准库中查看the source code for Data.Tuple!
答案 1 :(得分:23)
模板Haskell尽可能接近,因为类型检查是否要提取可变数量的元素,因为(a,b)和(a,b,c)具有不同的类型。
{-# 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)
然后:
$(tuple 6) [1,2,3,4,5,6] == (1,2,3,4,5,6)
$(tuple 3) "abc" == ('a','b','c')
但总的来说,如果你需要这个答案,那么你就会在某个地方提出错误的问题。
如果您只想要平面随机访问,也许更好的选择是使用数组。
答案 2 :(得分:10)
如果我觉得我要建议你用枪指着你的脚并且相信你不要射击。
> 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)
这将完成定义元组显示和读取的长度。
答案 3 :(得分:7)
元组和列表是非常不同的东西。关于您可以做的最好的事情是手动编写转换函数:
toTuple :: [a] -> (a,a,a,a,a,a)
toTuple [a,b,c,d,e,f] = (a,b,c,d,e,f)
注意类型的不同之处:列表的单个变量扩展为元组的六个变量。因此,每个元组大小都需要一个函数。
答案 4 :(得分:5)
我发现很难对Template Haskell操作做出切实的解释,但这是一个演示:
> :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)
答案 5 :(得分:3)
我不认为在Haskell中可以这样做,因为编译时未知的任意长度列表。模板Haskell不能这样做,因为它只在编译时运行。我遇到了一个我需要做的事情,我不得不解决它。数据库库需要查询参数的不同长度元组,但我有一个任意长度的列表。所以我不得不绕过库接口。如果可以列出一个列表会很好。
基本上问题是不同长度的元组是不同的类型。但是Haskell编译器必须在编译类型中知道运行时可能存在哪些类型。在运行时将任意长度的列表转换为元组可能会在编译时创建一些它不知道的类型。
答案 6 :(得分:2)
如果使用准引用as explained here,实际上你可以比每个元组大小手动编写一个函数做得更好。但是,我想知道你希望在一般情况下使用它的代码。