2016-08-02 15 views
0

Ist eine Möglichkeit, eine Liste von Paaren ohne die gleichen Typen in Haskell zu haben und eine Funktion durchqueren zu lassen. Zum Beispiel:Tupel mit verschiedenen Typen

a = [(1, "uno"), (2, True), (3, 5)] 

A wollen von der Art des zweiten Wertes, so etwas wie eine Funktion, eine Funktion verwenden, je, dass die Kombination des Paares f :: [(Int, #)] -> [a].

+0

Ich glaube nicht, dass dies derzeit ohne die ImpredicativeTypes-Erweiterung möglich ist, die derzeit [nicht wirklich funktioniert] (http://stackoverflow.com/q/33741334/465378). –

+5

@AlexisKing 'ImpredicativeTypes' wird dir hier nicht helfen. Impredicativity ermöglicht die Parametrisierung von Typen durch 'forall'-quantifizierte Typen, zB um eine _homogene_ Liste von polymorphen Funktionen zu erstellen. OP möchte eine heterogene Liste von monomorphen Tupeln erstellen. –

+4

@jonaprieto Was versuchst du zu erreichen? Der einfachste Weg besteht darin, einen Summen-Typ zu erstellen und eine Laufzeit-Analyse auf den Werten zu machen: 'a :: [(Int, Boole String)]' –

Antwort

4

Umbrechen Sie einfach die Werte in einer Summenart. Beispiel:

data StringOrBoolOrInt = 
    StringOrBoolOrInt_String String | 
    StringOrBoolOrInt_Bool Bool | 
    StringOrBoolOrInt_Int Int 

a :: [(Int, StringOrBoolOrInt)] 
a = 
    [ 
    (1, StringOrBoolOrInt_String "uno"), 
    (2, StringOrBoolOrInt_Bool True), 
    (3, StringOrBoolOrInt_Int 5) 
    ] 
6

To a first approximation, nicht ausgewertet wird, ist dies nicht möglich. Normalisieren Sie zuerst die Werte, z. durch Anwenden irgendeiner klassenpolymorphen Funktion auf jedes der zweiten Argumente, bevor sie in die Tupel gesetzt werden.

1

Wie andere angegeben haben, wie angegeben, hat dieses Problem keine Lösung. Aber Ihr wirkliches Problem ist, dass Ihre Daten nicht durch eine Liste von Tupeln beschrieben werden - per Definition ist eine Liste homogen (alle Elemente enthalten den gleichen Typ), während Ihre Daten heterogen sind.

Wenn Sie eine Funktion abhängig vom Typ schreiben möchten, müssen Sie den Typ irgendwie auf der Typenebene speichern.

Ihre Beispieldaten werden beschrieben tatsächlich vom Typ Prod ((,) Integer) '[String, Bool, Integer], wo Prod der folgende Typ ist:

data Prod f (xs :: [a]) where 
    P0 :: Prod f '[] 
    (:>) :: f x -> Prod f xs -> Prod f (x ': xs) 

infixr 5 :> 

oder allgemeine Prod ((,) Integer) xs für einige Liste der Typen xs.

Ihr Beispiel Wert ist dann

a = (1, "uno") :> (2, True) :> (3, 5) :> P0 

Sie können auf diese Art verzweigen die normalen Methoden - das heißt eine Typklasse. Angenommen man hat eine solche Klasse:

class HasFoo x where 
    foo :: x -> Integer 

instance HasFoo String where foo = fromIntegral . length 
instance HasFoo Bool where foo = fromIntegral . fromEnum 
instance HasFoo Integer where foo = id 

Sie anwenden können, eine solche foo Funktion auf jedes Element Ihres Produktes

type family All (c :: k -> Constraint) (xs :: [k]) :: Constraint where 
    All c '[] =() 
    All c (x ': xs) = (c x, All c xs) 

-- example operation: add everything 
fooProd :: All HasFoo xs 
     => Prod ((,) Integer) xs 
     -> Integer 
fooProd P0 = 0 
fooProd ((i, x) :> ps) = i + foo x + fooProd ps 

Dieses einige GHC Erweiterungen erfordert, mindestens TypeFamilies, GADTs, ConstraintKinds, DataKinds, PolyKinds.

Verwandte Themen