2017-02-22 78 views
0

当我尝试执行使用类型参数调用数据的此函数时,出现错误。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) 

我收到此错误

* 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) 

感谢。

+1

“我得到这个错误”正确的是,因为写入的代码没有任何意义。 “如果我不使用下面的类型参数,它就可以工作”也完全可以,这绝对是正确的。所以有什么问题? –

+0

道歉,我已经更新了这个问题,它在我尝试使用数据类型时起作用,但在尝试使用类型参数时不起作用。 – Srinivas

+2

再次,问题是什么?你期望'公司'或'模型'不是'字符串','年份'不是'Int'的东西吗?为什么? –

回答

3

您定义的类型为Car a b c,而不是Car。你以后试图使用的仅仅是Car,编译器会警告你(关于你有点神秘)消息Expecting three more arguments to 'Car'。实际上仅仅期望Car作为一种神奇的工作是没有意义的,这些领域会是什么?一旦你指定了a,bc是什么,它才开始有意义。所以Car可以用来构造一个类型(比如Car String String String),因此它被称为类型的构造函数。为了区分这些并且为价值水平结构作类比,Haskell使用种类非常喜欢它使用类型来将个体值分组。

Car是种类* -> * -> * -> *意味着它需要3种类型才能生成混凝土第四种类型。

要使用编译器魔术自动派生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 
3

你有两个问题。本身并不是一种类型,而是一种类型的构造函数。此外,您还需要为类型参数添加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) 
2

在类型签名myCar :: Car -> String,你忘了类型参数添加到Car类型。既然你指定Car类型采取3个类型参数:

data Car a b c = ... 

在每一个在使用这种类型的点,你必须给它3个类型参数;您可以将Car a b c视为一种类型级别的函数,在获得一种类型*之前,您必须提供3种类型的函数。你得到的错误说类型Car是种类* -> * -> * -> *意味着Car类型是“更高亲密度”,这是一种奇怪的方式,表示类型需要像一个函数一样应用于一种或多种类型一种类型*(以0类型作为参数的类型)。在这种情况下,您需要将类型构造函数应用于其他3种类型,然后才能成为类型*

因此,在正确的方向迈出的一步是改变类型签名是这样的:

myCar :: Car String String Int -> String 

这应该解决您的问题。