2010-05-15 103 views
5

我有以下Haskell代码:问题Haskell的数类型

fac n = product [1..n] 

taylor3s w0 f f' f'' t h = w1 : taylor3s w1 f f' f'' (t+h) h 
    where hp i = h^i/fac i 
     w1 = w0 + (hp 1) * f t w0 + (hp 2) * f' t w0 + (hp 3) * f'' t w0 

taylor_results = take 4 $ taylor3s 1 f f' f'' 1 0.25 
    where f t x = t^4 - 4*x/t 
     f' t x = 4*t^3 - 4*(f t x)/t + 4*x/t^2 
     f'' t x = 12*t^2 - 4*(f' t x)/t + 8*(f t x)/t^2 - 8*x/t^3 

taylor_results应该是taylor3s的使用情况。但是,数字类型推断有问题。当我尝试编译时,这是我得到的错误:

practice.hs:93:26: 
    Ambiguous type variable `a' in the constraints: 
     `Integral a' 
     arising from a use of `taylor3s' at practice.hs:93:26-51 
     `Fractional a' arising from a use of `f' at practice.hs:93:37 
    Possible cause: the monomorphism restriction applied to the following: 
     taylor_results :: [a] (bound at practice.hs:93:0) 
    Probable fix: give these definition(s) an explicit type signature 
        or use -XNoMonomorphismRestriction 

有人能帮我理解问题是什么吗?

+3

我总是为顶级函数提供显式类型。它使代码更易于阅读,当发生这样的事情时,它有助于缩小问题范围,并帮助编译器提供有意义的错误消息。如果没有这些,你知道在那里有一个类型错误。 – 2010-05-15 07:52:47

+1

是的,我通常也会,但我对数字类型很无知。谁知道可能有这么多不同类型的数字? – mindeavor 2010-05-15 10:47:44

回答

8

既然你混合那些只在积分和操作仅在小数形式提供(具体使用哪种的^第二个操作数必须是完整的可用操作 - 使用**,如果你打算对两个操作数具有相同的浮动类型),haskell推断所有参数和taylor3s的结果的类型为Fractional a, Integral a => a。这不是一个类型错误,因为理论上这样的类型可能存在,但它很可能不是你想要的,因为在实践中这种类型不存在。

你得到一个类型的错误反正原因是,推断出的类型的taylor_results是因此也Fractional a, Integral a => a这是多态的,因此违反了monomorphism restriction

如果你想显式声明taylor_resultstaylor_results :: Fractional a, Integral a => a或禁用单态的限制,整个事情会编译,但无法使用(没有定义,实际上实例积分和分数,这将是废话型)。

请注意,如果你解决这个问题(例如通过更换 ^**)的 taylor_results类型将仍然是多态(它会被推断为 taylor_results :: (Floating a, Enum a) => [a],这实际上是合理的),所以你还是会碰到单态限制。所以您仍然需要关闭限制,明确声明 taylor_results的类型是多态的,或者明确声明 taylor_results的类型是实例化Floating和Enum(例如Double)的特定类型。请注意,除非你使用后者,否则每次使用 taylor_results时都会重新计算(这就是为什么存在单态限制的原因)。

请注意,如果你解决这个问题(例如通过更换^**)的taylor_results最普遍的类型将是(Floating a, Enum a) => [a],但是你(除非你禁用单态的限制)的类型将是[Double]。如果你不想双打,你必须明确声明taylor_results是另一种类型(实例化Floating和Enum)或者是多态的。请注意,如果您声明它是多态的,则每次使用它时都会重新计算taylor_results(这就是为什么存在单态限制的原因)。

+0

+1对于^/**答案。然而,由于使用了0.25(即Double类型),Haskell会将taylor_result推断为taylor_results :: [Double],所以不会有任何单形式限制 – zebrabox 2010-05-15 10:11:56

+0

@zebrabox:'0.25'的类型是'0.25 ::(Fractional t)=> t',不是Double。 taylor_results的推断类型绝对是用'**'替换'^'后的'(浮动a,枚举a)=> [a]'。我其实在ghci中检查过。 – sepp2k 2010-05-15 10:14:39

+1

@zebrabox:呃,我必须纠正自己。 *没有单态限制*推断的类型将是'(Floating a,Enum a)=> [a]'。但是,启用限制后,由于haskell关于Numbers的默认规则,该类型将专用于'[Double]'而不会导致错误。 – sepp2k 2010-05-15 10:22:13

0

看来,Haskell是推断的taylor3s回归为一个Integral类型,但随后的子功能f等被推断为应对Fractional类型的事实违反了推断。

也许通过明确告诉Haskell taylor3s返回类型可能会有所帮助。