2017-02-22 13 views
0

Ich erhalte einen Fehler, wenn ich versuche, diese Funktion, die den Typ-Parameter verwendet, um die Daten aufzurufen.Typ Parameter Problem in Haskell

data Car a b c = Car { company :: a 
       , model :: b 
       , year :: c 
       } deriving (Show) 

myCar :: Car -> String 
myCar (Car {company = c, model = m, year = y}) = "This " ++ C++ " was made in " ++ m ++ " " ++ show (y) 

Ich erhalte diese Störung

* Expecting three more arguments to `Car' 
    Expected a type, but `Car' has kind `* -> * -> * -> *' 
* In the type signature: 
    myCar :: Car -> String 

Es funktioniert, wenn ich die Parameter des Typs wie unter

data Car = Car { company :: String 
       , model :: String 
       , year :: Int 
       } deriving (Show) 

Vielen Dank im Voraus verwenden.

+1

„Ich erhalte diese Fehlermeldung“ Zu Recht hinzuzufügen, da der Code geschrieben macht keinen Sinn. "Es funktioniert, wenn ich die Typparameter wie unten nicht verwende" Auch vollkommen OK, das ist absolut das Richtige zu tun. Also, was ist das Problem? –

+0

Entschuldigung, ich habe das Problem aktualisiert, es funktioniert, wenn ich versuche, Datentypen zu verwenden, aber nicht, wenn ich versuche, Typparameter zu verwenden. – Srinivas

+2

Noch einmal, was ist das Problem? Erwarten Sie, dass "Firma" oder "Modell" etwas anderes als "String" und "Jahr" etwas anderes als "Int" ist? Warum? –

Antwort

3

Sie haben den Typ Car a b c, nicht Car definiert. Was Sie später verwenden möchten, ist nur Car, worüber der Compiler Sie warnt (für Sie ein wenig kryptisch) Nachricht Expecting three more arguments to 'Car'. Es macht eigentlich keinen Sinn, zu erwarten, dass Car alleine magisch als Typ funktionieren würde, was wären die Felder? Es beginnt erst Sinn zu ergeben, wenn Sie angeben, was a, b und c sind. So Car kann verwendet werden, um einen Typ zu konstruieren (sagen Car String String String) und so heißt es Typ Konstruktor. Um zwischen diesen zu unterscheiden und eine Analogie zu den Konstruktionen auf Werteebene zu ziehen, verwendet Haskell Arten ähnlich wie Typen, um einzelne Werte zu gruppieren.

Car von der Art * -> * -> * -> * bedeutet, dass es 3 Arten benötigt, um einen konkreten 4. Typ zu erzeugen.

Um den Compiler Magic zu verwenden, um Show automatisch abzuleiten, müssen Sie sicherstellen, dass die Komponenten auch instanziieren. Ohne dies kann der Compiler nicht erwarten, dass er auf magische Weise einen Weg findet, beliebige Typen in Zeichenketten umzuwandeln (wie Sie es von show erwarten). Sie können dies mit Einschränkungen erreichen aber soweit ich weiß, können Sie diese nur hinzufügen, wenn eine Spracherweiterung GADTs

{-# LANGUAGE GADTs #-} 
data Car a b c where 
    Car :: (Show a, Show b, Show c) 
     => { company :: a, model :: b, year :: c } 
     -> Car a b c 

verwenden, aber man kann immer noch deriving Show nicht direkt verwenden, da das scheint nur zu arbeiten, wenn der Typ Car a b c funktioniert für alle a, b, c, was hier nicht der Fall ist. Zumindest nicht mit ghc-7.10. Was dies tut, ist, dass es nur schlechte Entscheidungen von a, b, c bei der Konstruktion eines Autos verbietet. Ein Beispiel für einen Typ ohne eine Instanz ist der Funktionstyp, und es ist sinnvoll, ihn zu sperren, indem Sie anfordern. Leider müssten Sie

instance (Show a, Show b, Show c) => Show (Car a b c) where 
    show (Car a b c) = "Car " ++ show a ++ " " ++ show b ++ " " ++ show c 
3

Sie haben zwei Probleme. Car selbst ist kein Typ, sondern ein Typkonstruktor. Außerdem müssen Sie den Typparametern eine Show Einschränkung hinzufügen, um String s daraus zu machen.

Versuchen Sie folgendes:

myCar :: (Show c, Show m, Show y) => Car c m y -> String 
myCar (Car c m y) = "This " ++ (show c) ++ " was made in " ++ (show m) ++ " " ++ (show y) 
2

In der Art Signatur myCar :: Car -> String, haben Sie vergessen, um Typ-Parameter an die Car Typ. Da Sie die Car Typ angeben 3 Parameter Typ in nehmen:

data Car a b c = ... 

an jedem Punkt, in dem Sie diese Art zu verwenden, müssen Sie es 3 Typargumente geben; Sie können sich Car a b c als eine Typ-Level-Funktion vorstellen, für die Sie 3 Typen bereitstellen müssen, bevor Sie eine Art von Art * erhalten. Der Fehler Car von Art * -> * -> * -> * bedeutet, dass der Car Typ "höher kinded" ist, was eine phantastische Art zu sagen ist, dass der Typ wie eine Funktion auf 1 oder mehrere Typen angewendet werden muss, bevor es wird eine Art von Art * (ein Typ, der 0 Typen als Argumente akzeptiert). In diesem Fall müssen Sie den Typkonstruktor auf 3 andere Typen anwenden, bevor er zu einem Typ von Typ * wird.

So wäre ein Schritt in der richtigen Richtung sein, die Art Signatur zu ändern, so etwas wie zu sein:

myCar :: Car String String Int -> String 

Ihr Problem lösen soll.