当我尝试执行使用type参数调用数据的函数时,我收到错误。
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)
我收到此错误
* Expecting three more arguments to `Car'
Expected a type, but `Car' has kind `* -> * -> * -> *'
* In the type signature:
myCar :: Car -> String
如果我使用下面的类型参数
,它会起作用data Car = Car { company :: String
, model :: String
, year :: Int
} deriving (Show)
提前致谢。
答案 0 :(得分:3)
你有两个问题。 Car
本身并不是一种类型,而是一种类型构造函数。此外,您需要在类型参数中添加Show
约束,以便使String
成为它们。
试试这个:
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)
答案 1 :(得分:3)
您定义了类型Car a b c
,而不是Car
。您稍后尝试使用的只是Car
,编译器会警告您(对于您有点神秘)消息Expecting three more arguments to 'Car'
。仅仅期望Car
单独作为一种类型神奇地工作是没有意义的,这些领域是什么?只有在您指定a
,b
和c
后,才会开始有意义。因此Car
可用于构造类型(比如Car String String String
),因此它被称为类型构造函数。为了区分这些并且与值级构造进行类比,Haskell使用种就像使用 types 来对单个值进行分组一样。
Car
属于* -> * -> * -> *
意味着它需要3种类型才能生成具体的第4种类型。
要使用编译器魔术自动派生Show
,您需要确保成分也实例化Show
。如果没有这个,编译器就不能期望以任何合理的方式将任意类型转换为字符串(正如您期望的那样show
)。您可以使用约束来实现此目的,但据我所知,只有在使用语言扩展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
但您仍然无法直接使用deriving Show
,因为这似乎只适用于Car a b c
类型适用于任何a
,b
,c
的情况,这不是这种情况。至少没有ghc-7.10
。这样做的原因是,它只是在构造一些汽车时不允许选择a
,b
,c
。没有Show
实例的类型的一个示例是函数类型,通过请求Show a, Show b, Show c
来禁止它是有意义的。不幸的是,您需要添加
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
答案 2 :(得分:2)
在类型签名myCar :: Car -> String
中,您忘记将类型参数添加到Car
类型。由于您指定了Car
类型以获取3个类型参数:
data Car a b c = ...
在您使用此类型的每个点,您必须给它3个类型参数;您可以将Car a b c
视为类型级函数,在获得类型*
之前,必须提供3种类型。您收到的类型为Car
的错误* -> * -> * -> *
表示Car
类型为“更高级别的”,这是一种说法需要应用类型的奇特方式,像一个函数,在它成为一种类型*
(一种类型为0的类型作为参数)之前的1种或更多种类型。在这种情况下,您需要将类型构造函数应用于其他3种类型,然后才能成为类型*
的类型。
因此,正确方向的一个步骤是将类型签名更改为:
myCar :: Car String String Int -> String
这可以解决您的问题。