我正在学习Haskell,我是初学者 . 我希望我能在StackOverflow上搜索这个问题 . 但说实话,我不太清楚要搜索什么 .
我已经试图在没有太大成功的情况下得到答案,所以请耐心等待 . 看来这仍然是低级别的东西 .
所以我的ghci交互式会话似乎永远不会像Int那样输出"primitive types" . 我不想't know how else to put it. At the moment I'试图按照http://book.realworldhaskell.org/read/getting-started.html上的教程进行操作 . 不幸的是,我似乎无法产生相同的结果 .
例如:
Prelude> 5
5
Prelude> :type it
it :: Num a => a
我必须具体说:
Prelude> let e = 5 :: Int
Prelude> e
5
Prelude> :type it
it :: Int
这对我来说非常混乱,所以我希望有人可以稍微澄清这种混乱 .
EDIT:
在http://book.realworldhaskell.org/read/getting-started.html它说:"Haskell has several numeric types. For example, a literal number such as 1 could, depending on the context in which it appears, be an integer or a floating point value. When we force ghci to evaluate the expression 3 + 2, it has to choose a type so that it can print the value, and it defaults to Integer."我似乎无法强迫ghci评估类型 .
例如:
Prelude> 3 + 2
5
Prelude> :t it
it :: Num a => a
我期望“整数”是正确的类型 .
3 回答
这里有很多事情要做 .
Haskell中的数字文字是多态的;文字
5
的类型确实是Num a => a
. 它可以属于任何符合Num
类型类的类型 .Addition是
Num
类型类的一部分,因此添加两个数字文字仍然是Num a => a
.ghci中的交互式评估与评估IO monad中的操作非常相似 . 当你输入一个裸表达式时,ghci的行为就好像你运行了类似下面的内容:
但是,它并不完全相同,因为在这样的程序中,推理可以在整个
do
表达式主体上找到特定类型 . 当您输入一行时,它必须推断一个类型并编译一些只包含您输入的行末尾的上下文的内容 . 所以print
没有't affect the type inferred for the let-binding, as it'不是你输入的东西 .it
约束到Num
或Show
的特定实例;这意味着it
仍然是一个多态值 . 具体来说,GHC将具有类类约束的值编译为接受类型类字典的函数,该字典提供满足约束所需的实例实现 . 因此,虽然it
看起来像一个单态值,但它实际上由GHC表示为一个函数 . 对于足够多的人来说,令人惊讶的是,为了防止出现这种意外,发明了可怕的"Monomorphism Restriction" . 它不允许模式绑定(例如这一个),其中标识符绑定到多态类型 .现在GHC中默认关闭单态限制,自版本7.8以来它在GHCi中默认关闭 .
有关详细信息,请参阅the GHC manual .
show it
以获得IO动作值 .这是Haskell 98 Report中的相关部分 .
总结一下:
it
绑定到表达式5 + 5
,其类型为Num a => a
,因为这是基于多态数字文字的更一般的推断类型 .多态值表示为等待类型类字典的函数 . 因此,在特定实例中评估
it
并不会强制它变为单态 .但是,Haskell的类型默认规则允许它在作为ghci交互的一部分隐式
print it
时选择特定类型 . 它选择Int
,因此当print it
强制执行Show
和Num
时,它选择Int
类型类实例字典 .我希望这会让它更容易混淆!
顺便说一下,这里有一个例子,说明如何通过显式请求多态let-binding来获得ghci之外的相同行为 . 如果没有此上下文中的类型签名,它将推断
foo
的单态类型并给出类型错误 .这将编译并运行,打印以下内容:
UPDATE:
查看Real World Haskell示例和评论主题,有些人包含了不同的ghci日志以及他们的ghc版本 . 使用该信息,我查看了ghc发行说明,发现从版本7.8开始,默认情况下在ghci中禁用了Monomorphism Restriction .
如果你运行以下命令,你将重新启用单态限制,为了友好,ghci将默认绑定到Integer而不是给你一个错误或多态绑定:
似乎GHCi在这里表现出一些魔力 . 它正确地将数字默认为
Integer
s,以便可以打印它们 . 但是,在出现默认值之前,它将it
绑定到多态类型 .我猜你想看到默认发生后的类型 . 为此,我建议使用
Data.Typeable
库,如下所示:在上面,GHCi必须将
5
默认为Integer
,但这会导致typeOf x
在违约发生后报告该类型的表示 . 因此我们得到了想要的类型 .以下也有效,正是因为
typeOf
在违约发生后被调用:请记住,
typeOf
仅适用于单形类型 . 通常,:type
的多态结果更有用 .Haskell中的数字是多态的,固定和任意精度的整数,Rational,浮点数和用户定义的数字类型都有单独的类型 . 通过在
Num
类型类上实现fromInteger
方法,可以使用简单的文字实例化所有内容 . 你给出的值,(True, 1, "hello world", 3)
有两个积分文字,它们可以用来创建两个可能不同类型的数字 . 胖箭头之前的类型位(Num t, Num t1)
表示在推断类型中,t
和t1
可以是任何东西,只要它们碰巧在它们上定义了Num
类型类,即它们可以用fromInteger
获得 .