Haskell函数组成混乱

时间:2013-12-09 12:27:16

标签: haskell

我正在努力学习haskell,而且我一直在学习了解你是一个Haskell的第6章和第7章。为什么以下两个函数定义不能给出相同的结果?我以为(f.g)x = f(g(x))?

Def 1

let{ t :: Eq x => [x] -> Int; t xs = length( nub xs)}
t [1]
1

Def 2

let t = length . nub 
t [1]

<interactive>:78:4:
    No instance for (Num ()) arising from the literal `1'
    Possible fix: add an instance declaration for (Num ())
    In the expression: 1
    In the first argument of `t', namely `[1]'
    In the expression: t [1]

2 个答案:

答案 0 :(得分:9)

问题在于您的类型签名和可怕的单态限制。您的第一个版本中有类型签名,但在第二个版本中没有;具有讽刺意味的是,它会反过来发挥作用!

试试这个:

λ>let t :: Eq x => [x] -> Int; t = length . nub
λ>t [1]
1

单态限制强制看起来不像函数的东西具有单态类型,除非它们具有显式类型签名。您想要 t的类型是多态的:请注意类型变量x。但是,对于单态限制,x被“默认”为()。看看这个:

λ>let t = length . nub
λ>:t t
t :: [()] -> Int

这与上面带有类型签名的版本非常不同!

由于defaulting,编译器为单态类型选择()。默认只是Haskell用于从类型类中选择类型的过程。所有这一切的意思是,在repl中,如果遇到()ShowEq类中的模糊类型变量,Haskell将尝试使用Ord类型。是的,这基本上是随意的,但是无需在任何地方编写类型签名,这对于玩游戏非常方便!此外,默认规则在文件中更为保守,因此这基本上只是在GHCi中发生的事情。

事实上,默认为()似乎主要是让printf在GHCi中正常工作的黑客攻击!这是一个不起眼的Haskell古玩,但在实践中我会忽略它。

除了包含类型签名外,您还可以在repl中关闭单态限制:

λ>:set -XNoMonomorphismRestriction

这在GHCi中很好,但我不会在实际模块中使用它 - 相反,请确保始终在文件中包含顶级定义的类型签名。

编辑:自GHC 7.8.1起,GHCi默认关闭单态限制。这意味着所有这些代码都可以与最新版本的GHCi一起使用,并且您不需要显式设置该标志。但是,对于没有类型签名的文件中定义的值,它仍然是一个问题。

答案 1 :(得分:1)

这是“Dreaded”Monomorphism Restriction的另一个例子,它导致GHCi推断出组合函数的单态类型。您可以使用

在GHCi中禁用它
> :set -XNoMonomorphismRestriction