Reputation: 2100
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
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
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
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 String
s 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