一些例子中的Haskell类型

时间:2016-02-02 14:28:24

标签: haskell types

我正在学习Haskell并且我是初学者。 我希望我能在StackOverflow上搜索这个问题。 但说实话,我不太确定要搜索什么。

我已经试图在没有太大成功的情况下得到答案 请多多包涵。看来这仍然是非常低的水平 东西。

所以我的ghci交互式会话似乎永远不会输出 "原始类型"比如Int。我不知道怎么做 否则说出来。目前我正试图跟随 关于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

这对我来说非常困惑,所以我希望有人 可以稍微澄清一下这种混乱。

修改

http://book.realworldhaskell.org/read/getting-started.html上它说:" Haskell有几种数字类型。例如,取决于它出现的上下文,诸如1的文字数可以是整数或浮点值。当我们强制ghci来计算表达式3 + 2时,它必须选择一个类型以便它可以打印该值,它默认为Integer。"我似乎无法强迫ghci评估类型。

例如:

Prelude> 3 + 2
5
Prelude> :t it
it :: Num a => a

我期望的地方"整数"是正确的类型。

3 个答案:

答案 0 :(得分:2)

看起来GHCi在这里表现出一些魔力。它正确地将数字默认为Integer s,以便可以打印它们。但是,在出现默认值之前,它会将it绑定到多态类型。

我想你想在默认发生之后看到这种类型。为此,我建议使用Data.Typeable库,如下所示:

> import Data.Typeable
> let withType x = (x, typeOf x)
> withType 5
(5,Integer)

上面,GHCi必须将5默认为Integer,但这会导致typeOf x在违约发生后报告该类型的表示。因此我们得到了想要的类型。

以下也有效,正是因为在违约发生后调用了typeOf

> :type 5
5 :: Num a => a
> typeOf 5
Integer

请记住,typeOf仅适用于单形类型。通常,:type的多态结果更有用。

答案 1 :(得分:2)

这里有很多事情发生。

  1. Haskell中的数字文字是多态的;文字5的类型确实是Num a => a。它可以属于任何符合Num类型类型的类型。

  2. 添加是Num类型类的一部分,因此添加两个数字文字仍为Num a => a

  3. ghci中的交互式评估与评估IO monad中的操作非常相似。当您输入一个裸表达式时,ghci的行为就好像您运行了以下内容:

    main = do
      let it = 5 + 5
      print it
    
    但是,

    当您输入一行时,它必须推断一个类型并编译一些只包含您输入的行末尾的上下文的内容。因此,do不会影响为let-binding推断的类型,因为它不是输入的内容。

  4. 该程序中没有任何内容可以将print约束到itNum的特定实例;这意味着Show仍然是一个多态值。具体来说,GHC将具有类类约束的值编译为接受类型类字典的函数,该字典提供满足约束所需的实例实现。因此,虽然it看起来像一个单态值,但实际上GHC将表示为作为函数。对于足够多的人来说,令人惊讶的是,这种可怕的“单态限制”#34;被发明是为了防止这种意外。它不允许模式绑定(例如这一个),其中标识符绑定到多态类型。

    现在GHC中默认关闭单态限制,自版本7.8以来它在GHCi中默认关闭。

    有关详细信息,请参阅the GHC manual

  5. Haskell为多态数提供了一些特殊的魔力;每个模块都可以创建默认声明,为多态数提供类型默认规则。在你的ghci提示符下,默认规则使得ghci选择了' Int'当它被迫向it提供实例字典以获得IO动作值时。

    以下是Haskell 98 Report

  6. 中的相关部分

    总结一下:show it绑定到表达式it,其类型为5 + 5,因为它是基于多态数字文字的更一般的推断类型。

    多态值表示为等待类型类字典的函数。因此,在特定实例中评估Num a => a并不会强制它变为单态。

    但是,当您隐式it作为ghci交互的一部分时,Haskell的类型默认规则允许它选择特定类型。它选择print it,因此当Int强制使用IntShow时,它会选择Num类型类实例字典。

    我希望这会让它更容易混淆!

    顺便说一下,这里有一个例子,说明如何通过显式请求多态let-binding来获得ghci之外的相同行为。如果没有此上下文中的类型签名,它将推断print it的单态类型并给出类型错误。

    foo

    这将编译并运行,打印以下内容:

    main = do
      let foo :: Num a => a
          foo = 5 + 5
      let bar = 8 :: Double
      let baz = 9 :: Int
    
      print (foo + bar)
      print (foo + baz)
    

    <强>更新

    查看Real World Haskell示例和评论主题,有些人包含了不同的ghci日志以及他们的ghc版本。使用该信息,我查看了ghc发行说明,发现从版本7.8开始,默认情况下在ghci中禁用了单态限制。

    如果你运行以下命令,你将重新启用单态限制,为了友好,ghci将默认绑定到Integer而不是给你一个错误或多态绑定:

    18.0
    19
    

答案 2 :(得分:0)

Haskell中的数字是多态的,固定和任意精度有单独的类型整数,Rational,浮点数和用户定义的数字类型。通过在fromInteger类型类上实现Num方法,可以使用简单的文字实例化所有内容。您给出的值(True, 1, "hello world", 3)有两个整数文字,它们可用于创建两个可能不同类型的数字。胖箭头(Num t, Num t1)之前的类型位置表示,在推断类型中,tt1可以是任何内容,只要它们碰巧有Num在它们上定义了类型类,即它们可以用fromInteger获得。