将相同长度的列表元组转换为任意的元组列表 - Haskell [英] Convert a tuple of lists of the same length to a list of tuples for arbitrary -- Haskell
问题描述
我试图将相同长度的列表元组转换为列表:
([Int],[Int],..)
的元组 [(Int,Int,...)]
。这可以通过以下代码完成预定的大小:
buildList ::([a],[a],[a ],[a],[a],[a],[a],[a]) - > [(a,a,a,a,a,a,a)]
buildList([],[],[],[],[],[],[],[])= []
buildList(a:as,b:bs,c:cs,d:ds,e:es,f:fs,g:gs,h:hs)=(a,b,c,d, e,f,g,h):buildList(as,bs,cs,ds,es,fs,gs,hs)
正如你可能看到的那样,当我需要列表中的很多项目时,这并不会很漂亮,如果它适用于任意值,它会更清晰。
所以我的问题是,你有一个函数对任意长度的元组进行这个操作吗?
像这种问题一样,对'你应该'和'你可以'的答案是不同的。在这里,我将严格回答第二个问题。
解决这个问题的第一部分是n元组或者(听起来更花哨)的产品。让我们这样做(不使用任何导入,以至于整个事物仍然是独立的,也是因为在我现在使用的机器上,Stack是不正确的):
{ - #语言DataKinds,KindSignatures,TypeOperators,GADTs# - }
{ - #语言FlexibleInstances,FlexibleContexts# - }
{ - #语言TypeFamilies# - } - - 稍后需要
data产品(ts :: [*])其中
Nil :: Product'[]
Cons :: t - >产品ts - >产品(t':ts)
实例显示(Product'[])其中
显示Nil =()
instance(Show t,Show Product ts))=> Show(Product(t':ts))其中
show(Cons x xs)= let'(':s = show xs
in concat [(,show x,,,s ]
所以这给了我们写一些类似于
* Main> myPair = Cons 1 $ ConsFoo$ Cons True Nil
* Main>:t myPair
myPair :: Num t = > Product'[t,[Char],Bool]
* Main> myLists = Cons [1,2] $ Cons [Foo,Bar,Baz] Nil
* Main> ;:t myLists
myLists :: Num t => Product'[[t],[[Char]]]
使用这种类型,至少我们可以开始考虑n元拉链函数 zipN
应该是什么类型:
zipN :: Product'[[a],[b],...] - > [Product'[a,b,。 ..]]
然而,我们仍然需要一种方式来转换那个元组列表 Product'[[a],[b],...]
转换为元素元组 Product'[a,b,... ]
。W我发现最简单的是使用一个关联类型系列来完成转换和实际的锁步:
类型Unlists ts :: [*]
zipN :: Product ts - > [Product(Unlists ts)]
instance IsLists'[] where
type Unlists'[] ='[]
zipN Nil = []
实例(IsLists ts)=> IsLists([t]':ts)其中
类型Unlists([t]':ts)= t':Unlists ts
- 处理尾部特别确保我们不' t结束了压缩所有
- 用空的列表来自zipN []
zipN(Cons xs yss)= case $ y
无 - > map(`Cons` Nil)xs
_ - > zipWith Cons xs(zipN yss)
示例:
*主> zipN myLists
,结果列表的长度由元组中最短的列表指定。
[(1,Foo,),(2,Bar,)]
* Main> :t it
it :: Num t =>请注意,它的行为类似于普通的<$ c $ [$ t $ [
$ c> zipI'm trying to convert a tuple of lists of the same length:
([Int], [Int], ..)
to a list of tuples[(Int, Int, ...)]
. This can be accomplished for predetermined sizes with the following code:buildList :: ([a], [a], [a], [a], [a], [a], [a], [a]) -> [(a, a, a, a, a, a, a, a)] buildList ([], [], [], [], [], [], [], []) = [] buildList (a:as, b:bs, c:cs, d:ds, e:es, f:fs, g:gs, h:hs) = (a, b, c, d, e, f, g, h) : buildList (as, bs, cs, ds, es, fs, gs, hs)
As you can probably see, this isn't going to be pretty when I need a lot of items in the list, and it would be much cleaner if it worked for any arbitrary value.
So my questions is, do you have a function that preforms this operation for tuples of arbitrary length?
解决方案As is usual with this kind of questions, the answer to 'should you' and 'can you' are different. Here, I will answer strictly the second.
The first part of solving this is a representation of n-ary tuples, or (to sound extra fancy) products. Let's do that (without using any imports so that the whole thing remains self-contained, and also because on the machine I'm currently on, Stack is misbehaving):
{-# language DataKinds, KindSignatures, TypeOperators, GADTs #-} {-# language FlexibleInstances, FlexibleContexts #-} {-# language TypeFamilies #-} -- This will be needed later data Product (ts :: [*]) where Nil :: Product '[] Cons :: t -> Product ts -> Product (t ': ts) instance Show (Product '[]) where show Nil = "()" instance (Show t, Show (Product ts)) => Show (Product (t ': ts)) where show (Cons x xs) = let '(':s = show xs in concat ["(", show x, ",", s]
So this gives us a way to write something like
*Main> myPair = Cons 1 $ Cons "Foo" $ Cons True Nil *Main> :t myPair myPair :: Num t => Product '[t, [Char], Bool] *Main> myLists = Cons [1, 2] $ Cons ["Foo", "Bar", "Baz"] Nil *Main> :t myLists myLists :: Num t => Product '[[t], [[Char]]]
Using this type, at least we can start thinking about what the type of our n-ary zipping function
zipN
should be:zipN :: Product '[[a], [b], ...] -> [Product '[a, b, ...]]
however, we still need a way to somehow convert that tuple-of-lists
Product '[[a], [b], ...]
into a tuple-of-elementsProduct '[a, b, ...]
. What I've found easiest is using an associated type family to do the conversion and the actual zipping in lockstep:class IsLists (ts :: [*]) where type Unlists ts :: [*] zipN :: Product ts -> [Product (Unlists ts)] instance IsLists '[] where type Unlists '[] = '[] zipN Nil = [] instance (IsLists ts) => IsLists ([t] ': ts) where type Unlists ([t] ': ts) = t ': Unlists ts -- Handling the tail is special to ensure we don't end up zipping everything -- with the empty list coming from zipN [] zipN (Cons xs yss) = case yss of Nil -> map (`Cons` Nil) xs _ -> zipWith Cons xs (zipN yss)
Example:
*Main> zipN myLists [(1,"Foo",),(2,"Bar",)] *Main> :t it it :: Num t => [Product '[t, [Char]]]
Note that this behaves like regular
zip
in that the result list's length is specified by the shortest list in the tuple.这篇关于将相同长度的列表元组转换为任意的元组列表 - Haskell的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!