【问题标题】:Haskell: Why is there no type mismatch (and why does this compile)?Haskell:为什么没有类型不匹配(为什么会编译)?
【发布时间】:2012-04-10 15:40:01
【问题描述】:

我太困了,写了以下代码(为了显示混乱而修改):

fac s = take 10 [s, s `mod` 1 ..]

maxFactor x = if (s == [])
              then x
              else head    <-- this should be 'head x' instead of just 'head'
  where s = fac x

但是,这个加载到 ghci 中(并编译)就好了。当我执行maxFactor 1 时,它会抱怨(当然):

<interactive>:0:1:
    No instance for (Integral ([a0] -> a0))
      arising from a use of `maxFactor'
    Possible fix:
      add an instance declaration for (Integral ([a0] -> a0))
    In the expression: maxFactor 1
    In an equation for `it': it = maxFactor 1

<interactive>:0:11:
    No instance for (Num ([a0] -> a0))
      arising from the literal `1'
    Possible fix: add an instance declaration for (Num ([a0] -> a0))
    In the first argument of `maxFactor', namely `1'
    In the expression: maxFactor 1
    In an equation for `it': it = maxFactor 1

但是,我不理解这种行为:

fac的类型是:

fac :: Integral a => a -> [a]

maxFactor的类型是:

maxFactor :: Integral ([a] -> a) => ([a] -> a) -> [a] -> a

这是否意味着以下:

  1. fac 的第一个输入必须是类型类 Integral(例如,fac 10);
  2. 因为在maxFactor的定义中,有fac x,x也必须是类型类Integral,因此,maxFactor的类型将以maxFactor :: (Integral a) =&gt; a -&gt;之类的东西开头……然后是一些东西别的?但是,如果是这样的话,那为什么这段代码会编译,因为maxFactor的返回可以是xhead,按照这种推理,它们的类型不一样?

我在这里错过了什么?

提前感谢您的任何意见!

【问题讨论】:

  • 这种问题可能以更简单的方式出现。我怀疑(但我不是专家)只要类型检查器无法充分减少表达式,就会发生这种情况。例如, foo x = 1 + x; bar = foo head -- 会失败,但是 foo x = 1 + x; bar x = foo head -- 将编译。
  • @Sarah:由于单态限制,您提供的示例没有进行类型检查;如果添加 pragma,它会进行类型检查(不过有一个微妙的问题:GHCi 推断类型 Num ([a] → a) ⇒ [a] → a 并且您不能使用此类型声明 bar,您需要 FlexibleContexts)。
  • 不管怎样,如果你使用-Wall 编译(或将其添加到默认的 ghci 选项中,以便 ghci 使用-Wall“编译”)你会收到一个警告,因为你没有不要在maxFactor 上添加类型签名。然后,大概你会写maxFactor :: Integral a =&gt; a -&gt; a,它会编译失败。

标签: haskell types ghc typeclass ghci


【解决方案1】:

您已经正确注意到,在maxFactor 内部使用函数fac 会在x 的类型上添加Integral a 约束。所以x 需要是Integral a =&gt; a 类型。

此外,编译器发现maxFactor 要么返回head,其类型为[a]-&gt;a,要么返回x。因此x 必须有更具体的类型Integral ([a]-&gt;a) =&gt; ([a]-&gt;a),所以maxFactor 有类型

maxFactor :: Integral ([a] -> a) => ([a] -> a) -> ([a] -> a)

这正是你得到的。到目前为止,这个定义没有任何“错误”。如果您设法编写了Integral 类型([a]-&gt;a) 的实例,则可以毫无问题地调用maxFactor。 (显然maxFactor 不会按预期工作。)

【讨论】:

    【解决方案2】:

    maxFactor 中,编译器推断函数参数x 必须与head 具有相同的类型(在您的if 子句中)。由于您还在x 上调用fac(这反过来又调用mod)它推断x 也是一些Integral 类类型。因此,编译器推断类型

    maxFactor :: Integral ([a] -> a) => ([a] -> a) -> [a] -> a
    

    这需要一些类似head 和类似整数的参数......这不太可能是真实的。

    我认为您可以将该代码加载到 GHCi 中这一事实更像是解释器的一个怪癖。如果你只是编译上面的代码,它会失败。

    编辑:我想问题是类型检查器可以理解您的代码,但是可能没有任何合理的方式来使用它。

    【讨论】:

    • 其实它可以编译(我的版本是 7.2.1) :( 现在这是 GHC 中的一个错误吗?我想知道...但是,谢谢!
    • @ZiyaoWei 如果您尝试添加那些推断的类型声明,则不会。
    • @ZiyaoWei:这不是错误。 GHC 无法知道永远不会有函数 [a]-&gt;aIntegral 的实例。
    • 对我来说也很可疑。当然,你永远不可能在你编译的程序中真正使用它。
    • @ZiyaoWei 如果你想要一个函数属于Integral 类,那就去做吧:instance Integral ([a]-&gt;a)(你需要 FlexibleInstances 来编译它)。您还必须创建它和Num 的实例。正是您希望方法执行的操作,好吧,我将把它留给您。
    猜你喜欢
    • 2019-07-16
    • 2016-04-16
    • 2014-01-18
    • 1970-01-01
    • 2020-11-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多