Haskell:函数组合导致类型不匹配错误

3

TL;DR: 纯粹由于函数组合,什么原因会导致GHCi出现类型不匹配错误?看到GHCi评估以下代码确实很奇怪:

foldl (a . b . c) crackle pop       <- GHCi evaluates this`

...只是在我们尝试评估以下内容后出现错误:

let snap = a . b . c                <- GHCi evaluates this
foldl snap crackle pop              <- GHCi reports an error (!)

更详细的描述:

我对GHCi中观察到的情况感到困惑,希望有人能够解释一下(图像下面包含了描述):

enter image description here

上面我们看到了什么?:

  • 首先,我们有一个变量b,它被绑定到以下列表:[(2,["Dipak"]), (2,["Andrew"]),(2,["Keone"])]b的类型为[(Int,[String])]。(请参见上面的第一个ghci>提示和结果输出的屏幕截图。)

  • 然后,我们对b执行折叠操作,将其转换为以下类型:Map (Integer, [String])。我们使用基于insertWith (++)的折叠函数,并使用一个起始累加器,这个累加器是一个empty映射。该函数如下(与屏幕截图中第二个ghci>提示之后的内容相同。)(请参见上面的第二个ghci>提示。)

    foldl' (flip $ uncurry (Map.insertWith (++))) (Map.fromList []) b

  • 好的,很酷;到目前为止都很好

  • 由于上面的foldl'函数有点长,我决定组合一个折叠函数(名为foldingFunc),它等于flip $ uncurry (Map.insertWith (++))。这只是foldl'表达式中的第一个参数。 (请参见上面第三个ghci>提示中的let表达式。)

  • 这就是我感到困惑的地方:作为例行检查,我执行与上面相同的foldl',只不过使用foldingFunc(而不是flip $ uncurry (Map.insertWith (++))),这应该只是一种外观上的改变...但现在GHCi报告类型不匹配错误(详细信息如上所述)。

请问有人能帮助我理解为什么函数组合在这种情况下导致了错误(由于类型更改导致)?我应该做些什么不同的事情吗?


2
你是否开启了MonomorphismRestriction?变量bfoldingFunc的类型是什么?(在ghci中使用:t查看它们的类型。) - Rufflewind
刚关掉它,现在它正常工作了。非常感谢。如果你将你的评论复制粘贴到答案中,我会很高兴地接受它。 - iceman
yatima2975 比我先了。 :) - Rufflewind
@Rufflewind:抱歉,在我解释的时候没有看到你的评论 :-) - yatima2975
1
@yatima2975 没事的。你提供了比我更详细的信息! - Rufflewind
1个回答

8

ghci的扩展默认规则和可怕的单态限制又一次联手!

我猜你正在使用稍微过时的ghci,版本为7.6或更早。

发生的情况是,foldingFunction的最通用类型为

foldingFunction :: Ord a => Map a [b] -> (a,[b]) -> Map a [b]

然而,因为这是一个没有参数的顶级定义,并且您的ghci版本仍然具有单态限制,所以这不是一个“好”的类型(由于上下文Ord a而具有多态性),默认规则会生效。 ghci试图找到Ord a的默认实例 - 通常会失败(因为没有类似于Num的约束),但ghci还将()视为可能的默认值。那样就可以了,所以如果要求ghci返回foldingFunction的类型,您会得到以下结果:

foldingFunction :: Map () [b] -> ((), []) -> Map () []

你的类型错误就是来自这里(我希望我猜得对!)。


有几种方法可以解决这个问题:

  1. foldingFunction添加一个参数:如果你使用 foldingFunction m = (flip $ uncurry (Map.insertWith (++))) m 或者可能更好的 foldingFunction m (a,bs) = insertWith (++) a bs m,它就可以开始工作了。
  2. 关闭单态限制,可以在文件顶部添加 {-# LANGUAGE NoMonomorphismRestriction #-} pragma,或者在ghci的命令行输入 :set -XNoMonomorphismRestriction 来交互式地进行操作。
  3. 升级到更新版本的GHC(对于我来说,7.8.3就足够了)。

DMR默认关闭和扩展的默认规则都是比较新的(最近几年)ghci功能,所以你使用的书籍或文本可能太旧了 :)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接