将相同长度的列表元组转换为任意的元组列表 - Haskell [英] Convert a tuple of lists of the same length to a list of tuples for arbitrary -- Haskell

查看:143
本文介绍了将相同长度的列表元组转换为任意的元组列表 - 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我发现最简单的是使用一个关联类型系列来完成转换和实际的锁步:

ts :: [*])其中
类型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> zip
,结果列表的长度由元组中最短的列表指定。

I'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-elements Product '[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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆