【问题标题】:Why does this typeclass only compile with "-XNoMonomorphismRestriction"?为什么这个类型类只能用“-XNoMonomorphismRestriction”编译?
【发布时间】:2014-09-03 08:51:46
【问题描述】:

我收到了一些奇怪的类型类错误,形式为“没有由表达式类型签名引起的 (Test a0) 实例”。这是我能想到的最简单的违规代码版本:

class Test a where
  test :: a

foo = test

添加类型没有帮助:

foo = test :: Test a => a

但是,添加 Test 实例确实可以编译:

instance Test Int where
  test = 0

这是不可接受的,因为我希望在其他地方声明我的实例。

最后,将-XNoMonomorphismRestriction 传递给 ghc(i) 也允许它编译。虽然现在这已经足够好了,但我不明白这个扩展的作用,为什么它是必要的,或者可能潜伏着什么缺点。

【问题讨论】:

标签: haskell typeclass


【解决方案1】:

作为禁用整个文件的单态限制的替代方法(这相当无害,但可能会导致一些意外的重新计算旨在成为多态的值),添加类型 does 帮助,但您必须将其作为顶层签名:

foo :: Test a => a
foo = test

如果你在test之后添加它,它被认为只是子表达式test上的一个注解,并且不会关闭foo本身的单​​态限制。

【讨论】:

  • 嗯,好的。我没有意识到这两种类型声明的方法是不同的。这很令人困惑,因为所有关于单态限制的资源都建议添加类型声明。
【解决方案2】:

看了this article,终于明白了单态限制。关键是看起来像常量的东西不应该是多态的,因为这可能会导致它们被多次评估(最坏的情况会导致指数级减速)。

在我的实际情况下,“常量”本身就是一个函数(通过柯里化)。我现在在围栏上;我应该诉诸-XNoMonomorphismRestriction,还是添加类型声明?后者似乎不那么激烈/侵入性,但另一方面,我只是不喜欢 MR 对我的类型所做的事情。

【讨论】:

  • 无论如何都建议在顶层添加类型声明,因为它既记录了意图,又通过不让类型推断跨越函数之间的边界来减少类型错误的混淆。
  • “常数”是由于多态性而不是柯里化而变化的。尽管禁用 MR 很常见,但无论如何您都应该在顶级声明中添加类型签名。
  • @VladFiroiu 是的,删除它们以找出 GHCi 认为它们应该是什么当然很方便,但之后再次添加它们被认为是个好主意。另外,我强烈推荐新的-fdefer-type-errors 选项,这样在编程时调整这些东西就不会那么烦人了。
  • 我也听过一些赞成省略类型声明的建议。优点包括使函数尽可能通用,不必写出所有类型类约束(如果我有很多辅助函数会很烦人),以及减少类型级重构的负担。
  • @JohnL 对。我想说的是,在我的例子中,MR 并没有真正节省太多计算时间,因为计算成本主要是应用它的成本。
猜你喜欢
  • 1970-01-01
  • 2014-01-18
  • 1970-01-01
  • 2014-08-12
  • 2016-11-22
  • 1970-01-01
  • 2018-01-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多