2016-10-31 9 views
1

同じ長さのリストのタプルを ([Int], [Int], ..)タプルのリストに変換しようとしています[(Int, Int, ...)]。これは、次のコードで所定の大きさのために行うことができます。同じ長さのリストのタプルを任意のタプルのリストに変換する

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) 

あなたはおそらく見ることができるように、私は、リスト内の項目の多くを必要とするとき、これがかなりあることを行っていない、そしてそれは非常にきれいになりますそれが任意の価値のために働くならば。

私の質問は、任意の長さのタプルに対してこの操作を実行する関数を持っていますか?

+0

タプルサイズはその型を定義しています。代わりにリストを使用してみてはいかがですか? –

+0

私はこの機能を現在の用途を超えて使用するために拡張したいと思っています。現在、既知のサイズの特定のタプルで動作しています。今はまったく異なる問題があり、機能を書き換えたくありません。 –

+3

関数とにかく、タプルの代わりにリストを使うべきです。 2次元リストを使うことができるのであれば、[*なぜタプルを使うのですか?*](http://stackoverflow.com/q/31497468/2751851)、あなたの質問は鏡像です。 – duplode

答えて

3

この種の質問ではいつもそうですが、「すべきか」と「できますか」の答えは異なります。ここで、私は厳密に第二に答えます。

これを解決するための最初の部分は、n-aryタプルの表現、または(特別な音を出すため)製品です。 (全部が自己完結型のままであるように、任意のインポートを使用せず、また、私が現在だマシンで、スタックが不正な動作しているため)のがそれをやってみましょう:

{-# 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] 

はこれが私たちに書くための方法を提供しますこのタイプを使用して

*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]]] 

のようなもの、少なくとも我々はn項ビュン機能zipNのタイプがどうあるべきかについて考え始めることができます。

zipN :: Product '[[a], [b], ...] -> [Product '[a, b, ...]] 

時間しかし、リストのタプルリストProduct '[[a], [b], ...]を要素タプルProduct '[a, b, ...]に何とか変換する必要があります。私は最も簡単な見つけたと、ロックステップでビュン変換し、実際の操作を行うために関連したタイプのファミリを使用している:

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) 

例:

*Main> zipN myLists 
[(1,"Foo",),(2,"Bar",)] 
*Main> :t it 
it :: Num t => [Product '[t, [Char]]] 

注意これは結果という点で、通常のzipのように振る舞うことリストの長さはタプルの最短リストによって指定されます。

関連する問題