2016-08-31 39 views
4

我不明白,为什么下面的练习“作品”,在从第一原理哈斯克尔编程:数据构造的部分应用程序

type Subject = String 
type Verb = String 
type Object = String 

data Sentence = 
    Sentence Subject Verb Object 
    deriving (Eq, Show) 

s1 = Sentence "dogs" "drool" 
s2 = Sentence "Julie" "loves" "dogs" 

加载到这个ghci中表明,它typechecks就好了,偏偏是那s1的定义更有意义?我对Haskell仍然很陌生,所以起初我认为这是因为在s1 Haskell隐含地让Object字符串变空。但然后...

*Main> s1 

<interactive>:13:1: 
    No instance for (Show (Object -> Sentence)) 
     arising from a use of `print' 
    Possible fix: 
     add an instance declaration for (Show (Object -> Sentence)) 
    In a stmt of an interactive GHCi command: print it 

我还在学习如何正确解释这些错误信息,所以请耐心等待。但有人可以解释什么No instance for (Show (Object -> Sentence))的含义?更具体地说,如何在s1中忽略Object字符串导致这个(Object -> Sentence)的事?

我敢肯定,这是愚蠢的容易,但我不认为这本书已经具备了我这个角度来理解这个...

+4

查找功能柯里并牢记像Sentence这样的数据构造函数与普通函数非常相似。 – Alec

回答

8

,但为什么现在的s1甚至使定义感?

正如@Alec提到的,这就是所谓的钻营。看到正在发生的事情的一种方式是有GHCI告诉你的s1类型是:

ghci> :t s1 
s1 :: Object -> Sentence 

所以s1是服用ObjectSentence功能。考虑另一种方法是先从定义:当你调用s1 x它与调用Sentence

s1 x = Sentence "dogs" "drool" x 

所以:

s1 = Sentence "dogs" "drool" 

,并使用等式推理双方应用于值x前两个函数参数硬编码到"dogs""drool",和x成为第三个参数Sentence功能。

有人能解释一下“没有(Show (Object -> Sentence))的实例”的意思吗?

当你在GHCI中评估一些东西的时候,它基本上和向Haskell询问print那样。也就是说,

ghci> 3+4 

实际上是相同的:

ghci> print (3+4) 

(这条规则并不适用于像getLine甚至print本身IO-行动在这些情况下哈斯克尔刚刚运行IO-动作。)

为了print东西,必须有该类型显示实例。 但正如我们在上面看到的,s1Object -> Sentence类型的函数,并且没有为函数预定义的Show实例。

请注意,有一个显示Sentence值的实例,因为您要求GHC从deriving (Eq, Show)派生出一个值。所以,当你键入在GHCI提示:

ghci> Sentence "Julie" "loves" "dogs" 

你回来:

Sentence "Julie" "loves" "dogs" 

,因为你实际上是在问GHCI运行print (Sentence "Julie" "loves" "dogs")

注意print本身被定义为(link)

print x = putStrLn (show x) 

,并调用show就是为什么值需要有以打印为它定义一个显示实例的原因。

+0

您还可以使用':t Sentence'来查看构造函数的类型为'Subject - > Verb - > Object - > Sentence'; ':t句子“狗”具有类型“对象 - >动词 - >句子”等。 – chepner

0
No instance for (Show (Object -> Sentence)) 
    arising from a use of `print' 
Possible fix: 
    add an instance declaration for (Show (Object -> Sentence)) 
In a stmt of an interactive GHCi command: print it 

为了补充@ ErikR的回答是:你可能会奇怪,为什么GHC没有内置显示功能,即不同于整数和字符串的支持,功能不具备一个实例Show类型类(这些术语将在本书后面进行深入解释,所以不要担心,如果你不明白什么是类型类和实例),除非你自己明确定义它。作为学习Haskell并来自面向对象背景的人,我发现通过将类视为Java类接口,可以更容易地得到类型类的直觉。

那么,为什么没有Show检查功能?所述Haskell wiki提供两个答案:

1.Practically,GHC不跟踪变量名,即以下是编译器是相同的:

addOne num = num + 1 
f x = x + 1 
f y = y + 1 

另外,功能可以被优化,例如下面可以具有等效表示

f x = x - x + x 
f x = x 

2.Theoretically,一个功能是通过其图形定义,即该组(输入,输出)对。例如对于

f x = x + x 

的对是(1,2),(2,4),等等 因此,用相同的图形函数是相同的GHC明智的,例如

f x = x + x 
g y = 2 * y 

但你会预计show fshow g会有所不同,特别是如果您使用重要变量名称而不是x和y。

这就是说,你可以使用杂注(扩展为GHC编译器,包含超过Haskell语言标准的一些功能),这将只显示功能的类型,如this answer解释说:

{-# LANGUAGE ScopedTypeVariables #-} 

import Data.Typeable 

instance (Typeable a, Typeable b) => Show (a->b) where 
    show _ = show $ typeOf (undefined :: a -> b) 

这将让你

> s1 
[Char] -> Sentence 

因为ObjectString别名(使用type关键字,String本身就是[Char]的别名)。 如果你想明确地看到主体和客体之间的区别,你可以转换Object的类型与数据类型构造MkObject

newtype Object = MkObject String deriving (Eq, Show) 

s1 = Sentence "dogs" "drool" 
s2 = Sentence "Julie" "loves" (MkObject "dogs") 

就万事大吉了

> s1 
Object -> Sentence