在Haskell中键入参数问题

时间:2017-02-22 14:36:37

标签: haskell

当我尝试执行使用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)

提前致谢。

3 个答案:

答案 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单独作为一种类型神奇地工作是没有意义的,这些领域是什么?只有在您指定abc后,才会开始有意义。因此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类型适用于任何abc的情况,这不是这种情况。至少没有ghc-7.10。这样做的原因是,它只是在构造一些汽车时不允许选择abc。没有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

这可以解决您的问题。