无法理解编码逻辑/原则/惯例 - 为什么需要“显示”?为什么'Show Car'或“Show String”不起作用?

时间:2012-07-22 12:21:10

标签: haskell ghc haskell-platform

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

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


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

哪些基本原则/惯例/逻辑可以提醒我,我只需要在'tellCar'中显示'显示',而不是任何其他选项?我在哪里可以找到资源来学习这些原则/惯例/逻辑?

如果我错误地在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中使用'Show String',则会在编译时收到以下错误消息:

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.  

3 个答案:

答案 0 :(得分:6)

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

请记住Show a的含义是:

  

=>后面的类型规范中,a应该有Show的实例。

这意味着Car数据构造函数的第三个参数必须是具有Show实例的某种类型。

指定(Show Car) => …(Show String) => …毫无意义;那些具体类型可能有也可能没有Show的实例(在这种情况下它们都有),但它并没有解释实际类型Car String String a -> String任何类型。

指定(Show z) => …说:

  

=>后面的类型规范中,z应该有Show的实例。

请注意,后面的类型为Car String String a -> String,我们可以断定 a z从未被提及,因此我们可以忽略(Show z) => … b a是多态的,没有约束! (即你不能依赖它有任何特定的类型类实例,包括Show

答案 1 :(得分:5)

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

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

编写Show String =>Show Car =>没有帮助,错误消息告诉您这是因为String没有类型变量(始终以小写字母开头)。这是因为instance Show StringtellCar范围内可见,或者它不是,您永远不需要将完全具体的实例列为该类型的约束。

原则:您列出的约束必须至少提及=>右侧的一个类型变量。在类型签名中。对于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 = ...

自动生成的代码仅在Showp,q,r个实例时才有效。你的专长

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

提及Car String String a。在Show的{​​{1}}上使用Car String String a会为tellCar选择自动生成的实例,并需要Show (Car p q r)Show String。然后,编译器会从隐式导入的Show a模块中看到Show String的实例,只留下悬空Prelude约束。 Show a上的此约束会感染a的类型。

了解Haskell类型系统的资源是books on Haskell之一。

编辑:Haskell 98报告的精确部分涵盖了section 4.1.3。更多背景信息位于"A History of Haskell"

答案 2 :(得分:4)

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

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

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