Srinivas
Srinivas

Reputation: 2100

Type parameters issue in Haskell

I am getting an error when I try to execute this function that uses the type parameter to call the data.

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)

I am getting this error

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

It works if I use the type parameters like below

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

Thanks in advance.

Upvotes: 0

Views: 113

Answers (3)

jakubdaniel
jakubdaniel

Reputation: 2223

You defined the type Car a b c, not Car. What you are trying to use later is just Car, which the compiler warns you about with (for you a bit cryptic) message Expecting three more arguments to 'Car'. It actually makes no sense to expect Car alone to magically work as a type, what would the fields be? It only starts to make sense once you specify what a, b, and c are. So Car can be used to construct a type (say Car String String String) and thus it is called a type constructor. To distinguish between these and to draw an analogy to the value-level constructions, Haskell uses kinds much like it uses types to group individual values.

Car being of kind * -> * -> * -> * means that it takes 3 types in order to produce a concrete 4th type.

To use the compiler magic to auto-derive Show you need to ensure that the constituents also instantiate Show. Without this the compiler cannot be expected to magically come up with a way to convert arbitrary type into string in any reasonable way (as you expect from show). You can achieve this using constraints but as far as I know you can add those only when using a language extension 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

but you still cannot use deriving Show directly, since that seems to work only when the type Car a b c works for any a, b, c, which is not the case here. At least not with ghc-7.10. What this does, is that it merely disallows bad choices of a, b, c when constructing some car. One example of a type without a Show instance is the function type, and it makes sense to disallow it by requesting Show a, Show b, Show c. Unfortunately, you would need to add

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

Upvotes: 3

ThomasD
ThomasD

Reputation: 31

In the type signature myCar :: Car -> String, you have forgotten to add type parameters to the Car type. Since you specify the Car type to take 3 type parameters in:

data Car a b c = ...

at every point in which you use this type, you have to give it 3 type arguments; You can think of Car a b c as a type-level function for which you must supply 3 types before you get a type of kind *. The error you get that says type Car is of kind * -> * -> * -> * means that the Car type is "higher kinded", which is a fancy way of saying that the type needs to be applied, like a function, to 1 or more types before it becomes a type of kind * (a type that takes 0 types as arguments). In this case, you need to apply the type constructor to 3 other types before it becomes a type of kind *.

So, a step in the right direction would be to change the type signature to be something like:

myCar :: Car String String Int -> String

This should resolve your issue.

Upvotes: 2

user2297560
user2297560

Reputation: 2983

You have two problems. Car by itself isn't a type but a type constructor. Also, you need to add a Show constraint to the type parameters in order to make Strings out of them.

Try this:

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)

Upvotes: 3

Related Questions