2011-08-16 56 views
12

我已经进入了haskell类型系统的基本原理,并试图获得类型类的精细点。我已经学会了一堆,但是我在下面的代码片断中碰到了一堵墙。Haskell类型系统细微差别

使用这些类和实例的定义:

class Show a => C a where 
    f :: Int -> a 

instance C Integer where 
    f x = 1 

instance C Char where 
    f x = if x < 10 then 'c' else 'd' 

为什么这通过类型检查:

但是这不?

g :: C a => a -> Int -> String 
g x y = show(f y) 

我找到第二个选择更可读,而且似乎只有微小的差别(注类型签名)。然而,试图让过去typechecker结果:

*Main> :l typetests.hs 
[1 of 1] Compiling Main    (typetests.hs, interpreted) 

typetests.hs:11:14: 
    Ambiguous type variable `a0' in the constraints: 
     (C a0) arising from a use of `f' at typetests.hs:11:14 
     (Show a0) arising from a use of `show' at typetests.hs:11:9-12 
    Probable fix: add a type signature that fixes these type variable(s) 
    In the first argument of `show', namely `(f y)' 
    In the expression: show (f y) 
    In an equation for `g': g x y = show (f y) 
Failed, modules loaded: none. 

而我不明白为什么。

注意:请不要问“你在做什么?”我希望很明显,我只是在一个抽象的上下文中进行调整,以便探究这种语言的工作方式。除了学习新东西以外,我没有任何目标。

感谢

+3

血腥地狱!在SO上的第一篇文章中,我在不到24小时内得到了三个伟大而有见地的答案。这个地方很棒。多谢你们 – TheIronKnuckle

回答

21

这是一个有趣的玩具进场的地方。考虑标准的前奏功能asTypeOf

asTypeOf :: a -> a -> a 
asTypeOf = const 

它只是返回它的第一个参数,不管第二个参数是什么。但是它上面的类型签名放置了两个参数必须是相同类型的附加约束。

g :: C a => a -> Int -> String 
g x y = show (f y `asTypeOf` x) 

现在,GHC知道什么类型的f y是。它与g的第一个参数的类型相同。如果没有这些信息,那么你会看到你看到的错误信息。没有足够的信息来确定f y的类型。由于类型很重要(它用于确定哪个实例用于show),因此GHC需要知道您的代码生成类型。

16

g :: C a => a -> Int -> a 
g x y = f y 

f y返回类型由类型签名固定的,所以如果你调用,例如将使用g 'a' 3,instance C Char。但在

g :: C a => a -> Int -> String 
g x y = show(f y) 

有上f返回类型两个约束条件:它必须是C(这样f可以使用)的实例和Show(这样show可以使用)。就这样!在fg的定义中,类型变量名称a的巧合并不意味着什么。因此,编译器无法在instance C Charinstance C Integer(或其他模块中定义的任何实例,因此删除这些实例不会使程序编译)之间进行选择。

21

这是臭名昭着的show . read问题的变种。经典的版本使用

read :: Read a => String -> a 
show :: Show a => a -> String 

这样的组成似乎是一个普通的老字符串转换

moo :: String -> String 
moo = show . read 

,除了有在程序中没有的信息,以确定在中间,因此什么样的类型, read,然后show

Ambiguous type variable `b' in the constraints: 
    `Read b' arising from a use of `read' at ... 
    `Show b' arising from a use of `show' at ... 
Probable fix: add a type signature that fixes these type variable(s) 

请不要说ghci做了一堆疯狂的额外违约,任意解决歧义。

> (show . read) "()" 
"()" 

C类是Read一个变种,只不过它的解码,而不是Int的阅读String,但问题基本上是一样的。

类型系统爱好者会注意到,underconstrained类型变量不是本身大不了。这是不明确的实例推断这是这里的问题。考虑

poo :: String -> a -> a 
poo _ = id 

qoo :: (a -> a) -> String 
qoo _ = "" 

roo :: String -> String 
roo = qoo . poo 

roo建设,这是从来没有确定在中间的类型必须是什么,也不是roo在这种类型的多态。类型推理既不解决也不推广变量!即便如此,

> roo "magoo" 
"" 

它不是一个问题,因为施工是在未知类型参数。类型不能确定的事实导致类型不能问题

但是未知的实例显然很重要。 Hindley-Milner类型推断的完整性依赖于参数性,因此在添加超载时会丢失。让我们不要为此哭泣。