2016-10-31 2 views
1

Ich versuche, ein Tupel von Listen der gleichen Länge zu konvertieren: ([Int], [Int], ..) auf eine Liste von Tupeln [(Int, Int, ...)]. Dies kann für vorgegebene Größen mit dem folgenden Code erreicht werden:auf eine Liste von Tupeln für beliebige - Haskell

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) 

Wie Sie wahrscheinlich sehen können, ist dies nicht recht sein würde, wenn ich viele Elemente in der Liste benötigen, und es viel sauberer sein würde, wenn es für einen beliebigen Wert funktioniert.

Also meine Fragen ist, haben Sie eine Funktion, die diese Operation für Tupel beliebiger Länge preforms?

+0

Die Tupelgröße definiert ihren Typ, warum nicht stattdessen die Liste verwenden? –

+0

Ich möchte diese Funktion für die Verwendung über ihre aktuelle Verwendung hinaus erweitern, derzeit handelt es sich um ein bestimmtes Tupel bekannter Größe, ich habe jetzt ein ganz anderes Problem, und ich möchte die Funktion nicht umschreiben –

+3

Sie müssen die Funktion neu schreiben trotzdem, und Sie sollten Listen anstelle von Tupeln verwenden. Siehe auch [* Warum verwenden wir Tupel, wenn wir eine zweidimensionale Liste verwenden können? *] (Http://stackoverflow.com/q/31497468/2751851), von denen Ihre Frage ein Spiegelbild ist. – duplode

Antwort

3

Wie bei dieser Art von Fragen ist die Antwort auf "sollten Sie" und "können Sie" unterschiedlich. Hier werde ich streng die zweite beantworten.

Der erste Teil der Lösung ist eine Darstellung von n-ary Tupeln, oder (um extra fancy) Produkte zu klingen. Lassen Sie uns das tun (ohne Importe zu verwenden, so dass das Ganze in sich geschlossene bleibt, und auch, weil an der Maschine, die ich aktuell bin, ist misbehaving Stack):

{-# 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 gibt uns einen Weg zu schreiben so etwas wie

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

diese Art verwenden, zumindest können wir anfangen, darüber nachzudenken, was die Art der n-ary Zuziehen Funktion zipN sein sollte:

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

h Trotzdem müssen wir immer noch einen Weg finden, das Tupel-of-lists Product '[[a], [b], ...] in ein Tupel von Elementen zu konvertieren Product '[a, b, ...]. Was ich am einfachsten zu finden ist eine zugehörige Schriftfamilie mit der Umwandlung und der tatsächlichen Zuziehen in Lockstep zu tun:

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) 

Beispiel:

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

Beachten Sie, dass diese wie normale zip, dass verhält sich das Ergebnis Die Listenlänge wird durch die kürzeste Liste im Tupel angegeben.