【问题标题】:Haskell's type inference strangenessHaskell 的类型推断异常
【发布时间】:2011-07-31 02:49:06
【问题描述】:

看看 ghci 的输出:

Prelude> :t Data.Map.lookup
Data.Map.lookup :: Ord k => k -> Data.Map.Map k a -> Maybe a
Prelude> :t flip Data.Map.lookup
flip Data.Map.lookup :: Ord a => Data.Map.Map a a1 -> a -> Maybe a1
Prelude> let look = flip Data.Map.lookup
Loading package array-0.3.0.2 ... linking ... done.
Loading package containers-0.4.0.0 ... linking ... done.
Prelude> :t look
look :: Data.Map.Map () a -> () -> Maybe a

为什么look 的推断类型与flip Data.Map.lookup 的类型不同?


给你一些背景。最初我有一个小程序,并试图弄清楚它为什么会产生编译器错误:

import qualified Data.Map as M

type A = String
type B = String
data C = C1 | C2 | C3
     deriving (Eq, Ord)
type D = String

z :: A -> M.Map A B -> M.Map B C -> M.Map C D -> Maybe D
z a aToB bToC cToD = look aToB a >>= look bToC >>= look cToD
  where look = flip M.lookup

Ghci 的反应:

Prelude> :load main.hs
[1 of 1] Compiling Main             ( main.hs, interpreted )
Failed, modules loaded: none.

main.hs:10:52:
    Couldn't match expected type `C' with actual type `[Char]'
    Expected type: C -> Maybe D
      Actual type: A -> Maybe a0
    In the return type of a call of `look'
    In the second argument of `(>>=)', namely `look cToD'

我发现这个变体编译得很好(类型定义相同):

x :: A -> M.Map A B -> M.Map B C -> Maybe C
x a aToB bToC = look aToB a >>= look bToC
  where look = flip M.lookup

y :: A -> M.Map A B -> M.Map B C -> M.Map C D -> Maybe D
y a aToB bToC cToD = (x a aToB bToC) >>= look cToD
  where look = flip M.lookup

经过一些实验后发现,如果我明确输入 look 类型 - 第一个版本也可以很好地编译:

z :: A -> M.Map A B -> M.Map B C -> M.Map C D -> Maybe D
z a aToB bToC cToD = look aToB a >>= look bToC >>= look cToD
  where look :: (Ord a) => M.Map a b -> a -> Maybe b
        look = flip M.lookup

这引出了我的第一个问题。

【问题讨论】:

标签: haskell type-inference ghc ghci monomorphism-restriction


【解决方案1】:

默认情况下,顶级绑定是非多态的,除非给出明确的类型说明符;这被称为“monomorphism restriction”。由于没有给出类型说明符,GHC 必须在定义函数时选择一种方法来实例化k。正好选了k = ()

这背后的想法是,多态性会在最终编译的代码中引入大量的 vtable 调用,从而损害性能;除非另有明确说明,否则通过强制在编译时解决这些问题,可以避免这种开销。这一决定颇具争议。 GHC 支持an extension 完全禁用单态限制,通过传递-XNoMonomorphismRestriction

【讨论】:

  • 请注意,正常的默认设置不会到处设置(); GHCi 中有一个扩展的默认模式可以做到这一点。
  • 或者在源文件中添加注释{-# LANGUAGE NoMonomorphismRestriction #-}(只是为了完整性)。
  • 我已经闲逛了太久......我阅读了问题的标题,甚至在我点击链接之前就认为“必须是单态的。”
  • 顺便说一句,虽然对于编译的源文件存在合理的争论,但实际上您实际上从不想要 GHCi 中的单态限制。每个人都应该将:set -XNoMonomorphismRestriction 添加到他们的~/.ghci 文件中。
  • “这背后的想法是,多态性会通过在最终编译的代码中引入大量 vtable 调用来损害性能”这些不是问题 - 或者至少不是最大的问题。引入单态限制的主要原因是,如果没有它,某些表达式将被计算多次,而您并不期望它们。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-22
  • 1970-01-01
相关资源
最近更新 更多