如何在Haskell中将列表转换为元组?
如何在Haskell中将列表最好地转换为元组:如何在Haskell中将列表转换为元组?,haskell,Haskell,如何在Haskell中将列表最好地转换为元组: [1,2,3,4,5,6] -> (1,2,3,4,5,6) 一般来说,你不能。元组的每个大小都是不同的类型,而任何长度的列表都是单一类型。因此,编写一个接受列表并返回相同长度的元组的函数没有好方法——它没有定义良好的返回类型 例如,您可以具有以下功能: tuplify2 :: [a] -> (a,a) tuplify2 [x,y] = (x,y) tuplify3 :: [a] -> (a,a,a) tuplify3 [x,
[1,2,3,4,5,6] -> (1,2,3,4,5,6)
一般来说,你不能。元组的每个大小都是不同的类型,而任何长度的列表都是单一类型。因此,编写一个接受列表并返回相同长度的元组的函数没有好方法——它没有定义良好的返回类型 例如,您可以具有以下功能:
tuplify2 :: [a] -> (a,a)
tuplify2 [x,y] = (x,y)
tuplify3 :: [a] -> (a,a,a)
tuplify3 [x,y,z] = (x,y,z)
…但不是一个两者兼而有之的人
您可以使用各种元编程编写通用版本,但您很少希望这样做
请注意,同样的问题也适用于其他事情,例如为各种元组编写类实例——看看标准库 元组和列表是完全不同的东西。您最多只能手动编写一个转换函数:
toTuple :: [a] -> (a,a,a,a,a,a)
toTuple [a,b,c,d,e,f] = (a,b,c,d,e,f)
注意类型的不同:列表的单个变量扩展为元组的六个变量。因此,对于每种大小的元组,您都需要一个函数。如果使用准引号,您实际上可以比手动为每种大小的元组编写一个函数做得更好。但是,我想知道您希望在哪里一般地使用它的代码。如果您想要提取可变数量的元素,那么由于类型检查,Template 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)
但总的来说,如果你需要这个答案,那么你在某处问错了问题
如果您只是想要平面随机访问,那么更好的选择可能是使用数组。对于编译时未知的任意长度列表,我认为在Haskell中不可能这样做。模板Haskell不能这样做,因为它只在编译时运行。我遇到了一个案例,我需要做的正是这一点,我必须解决它。数据库库需要不同长度的元组作为查询参数,但我有一个任意长度的列表。因此,我必须绕过库接口。如果能列个清单就好了
基本上,问题在于不同长度的元组是不同的类型。但是Haskell编译器必须知道编译类型在运行时可能存在哪些类型。在运行时将任意长度的列表转换为元组可能会创建一些它在编译时不知道的类型。我发现很难对模板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)
如果你觉得我要建议你用枪指着你的脚,相信你不要开枪
> 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)
这将达到tuple Show和Read的定义长度。你和camccann打败了我。就是这样,他所能做的最好的事情就是N个函数,然后为给定的N个函数调用其中一个函数的处理程序。元组是数学中的列表。他们非常相似。在Haskell的实现中,元组有固定的类型长度,而列表没有,因此转换二者并不容易,但这是一个特定于语言的实现问题。希望今天晚些时候有时间制作一个小示例,并用它编辑我的评论……我相信准旋转是模板Haskell的一部分,这就是我提到的元编程。最后,这仍然是每元组大小生成一个函数,它只是编写编译时代码来为您完成,而不是手工编写。我还没有掌握窍门,所以我期待着看到你的例子!爱德华·克米特击败了我。我以为我以前用过Quasikotes,但我想那只是个问题。抱歉,模板Haskell非常棒,但我希望它更具可读性。再说一次,也许最好不要这样——否则人们会比实际使用更多。显然,
Control.Lens
与map(^..each)
更接近,这也适用于任意元组并不是说“任意元组”的任何内容都与元组的整个点有关。(这就是列表的作用。元组正是在人们想要阻止这种用法时使用的。)由于每个使用惰性模式的方式:ghci>未定义和每个的部分。~[1,2,3,4]:(Int,Int,Int,Int)
产生(1,2,3,4)。所以你可以双向穿9号左右。当然,您需要知道结果元组类型。这怎么可能是数据的真正来源。元组?我是说。。。导出列表中的第二个元素是:,snd-->(a,b)->a
。真的有这种明显的打字错误吗?@Bakuriu:哈,这是一个有趣的打字错误。当然,这只是一条注释——文件末尾附近的snd
上的类型签名是正确的。这也是Data.Tuple的一个相当旧的版本,最近的版本没有这个错误。
> 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)