2

下面给出的代码编译,好的。

data Car p q r = Car {company :: p  
                     , model :: q  
                     , year ::r  
                     } deriving (Show)


tellCar :: (Show a) => Car String String a -> String

有哪些基本原则/约定/逻辑可以提醒我只需要在“tellCar”中使用“Show a”,而不是任何其他选项?我在哪里可以找到资源来学习这些原则/约定/逻辑?

如果我在 tellCar 中错误地使用了“Show Car”,编译时会收到以下错误消息:

*Main> :load "/home/optimight/baby.hs"  
[1 of 1] Compiling Main             ( /home/optimight/baby.hs, interpreted )  

/home/optimight/baby.hs:96:18:  
    Expecting three more arguments to `Car'  
    In the type signature for `tellCar':  
      tellCar :: Show Car => Car String String a -> String  
Failed, modules loaded: none.  

如果我在 tellCar 中错误地使用了“Show z”,编译时会收到以下错误消息:

*Main> :load "/home/optimight/baby.hs"  
[1 of 1] Compiling Main               ( /home/optimight/baby.hs, interpreted )

/home/optimight/baby.hs:96:1:  
    Ambiguous constraint `Show z'  
      At least one of the forall'd type variables mentioned by the constraint  
      must be reachable from the type after the '=>'  
    In the type signature for `tellCar':  
      tellCar :: Show z => Car String String a -> String  
Failed, modules loaded: none.   

如果我在 tellCar 中错误地使用了“显示字符串”,编译时会收到以下错误消息:

Prelude> :load "/home/optimight/baby.hs"  
[1 of 1] Compiling Main             ( /home/optimight/baby.hs, interpreted )  

/home/optimight/baby.hs:96:1:  
    Non type-variable argument in the constraint: Show String  
    (Use -XFlexibleContexts to permit this)  
    In the type signature for `tellCar':  
      tellCar :: Show String => Car String String a -> String  
Failed, modules loaded: none.  
4

3 回答 3

6
于 2012-07-22T13:29:52.773 回答
5

主要思想:类型签名中 => 之前列出的每个约束都用于将一个或多个类型变量限制在类型签名中 => 的右侧。

原则:类型签名中的约束总是在某处有一个类型变量。

Show String =>orShow Car =>没有帮助,错误消息告诉你这是因为String没有类型变量(总是以小写字母开头)。这是因为要么instance Show String在范围内可见要么不可见tellCar,并且您永远不需要将完全具体的实例列为类型中的约束。

原则:您列出的约束必须在类型签名中的 => 右侧至少提及一个类型变量。使用 LANGUAGE 扩展,约束可能会提到零个或多个仅存在于类型签名中 => 左侧的额外类型变量。

写作tellCar :: Show z => Car String String a -> String违反了这一点,因为a它是 => 的 RHS 上唯一的类型变量,并且Show z没有提及a. 这Show z不限制类型变量a

更具体地说,对于您编写deriving (Show)的自动生成实例的情况:

instance (Show p, Show q, Show r) => Show (Car p q r) where
  showsPrec = ...

Show自动生成的代码仅在有p,q,r. 你的专业

tellCar :: (Show a) => Car String String a -> String

提到Car String String a。使用Showon Car String String aintellCar选择自动生成的实例 forShow (Car p q r)并创建对 and 的Show String需要Show a。然后编译器Show String从隐式导入的Prelude模块中看到一个实例,只留下悬空Show a约束。这个约束a会感染tellCar.

了解 Haskell 类型系统的资源是有关 Haskell 的书籍之一。

编辑:涵盖此内容的 Haskell 98 报告的确切部分似乎是第 4.1.3 节。更多背景在“Haskell 的历史”中

于 2012-07-22T13:42:49.640 回答
4

您只需要对多态类型变量进行约束,因为该函数不知道类型将是什么,并且您为编译器提供了使其知道它将起作用的最少信息。

Show Car =>(或Show String)实际上并不意味着任何约束。编译器已经知道Car p q r有一个 Show 实例。如果Car p q r 没有Show 实例,那么编译器也已经知道了!因此,如果允许这种约束,它要么是多余的,要么是矛盾的。

的错误Show z是为了帮助你。您正在约束一个未在类型签名中使用的变量,因此几乎可以肯定这是一个错误。

于 2012-07-22T12:43:36.113 回答