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

Opt*_*ght 2 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
Run Code Online (Sandbox Code Playgroud)

什么是基本原则/惯例/逻辑可以提醒我,我只需要在'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.  
Run Code Online (Sandbox Code Playgroud)

如果我错误地在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.   
Run Code Online (Sandbox Code Playgroud)

如果我错误地在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.  
Run Code Online (Sandbox Code Playgroud)

Ash*_*she 6

tellCar :: (Show a) => Car String String a -> String
Run Code Online (Sandbox Code Playgroud)

请记住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)


Chr*_*icz 5

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

原则:类型签名中的约束总是在某处具有类型变量.

Show String =>Show 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 = ...
Run Code Online (Sandbox Code Playgroud)

自动生成的代码仅在有Show实例时才有效p,q,r.你的专业

tellCar :: (Show a) => Car String String a -> String
Run Code Online (Sandbox Code Playgroud)

提及Car String String a.使用Showon Car String String ain tellCar选择自动生成的实例Show (Car p q r)并创建需要Show StringShow a.然后,编译器Show String从隐式导入的Prelude模块中看到一个实例,只留下悬空Show a约束.这种约束a会影响其类型tellCar.

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

编辑:Haskell 98报告的精确部分涵盖了这一点,见4.1.3节.更多背景是"哈斯克尔的历史".