Haskell类型错误:推断类型的多态性低于预期

时间:2012-07-21 07:02:20

标签: haskell

我现在正在和Haskell搞乱,为了我的生活,我无法弄清楚为什么以下有效......

square :: (Num a) => a -> a 
square x = x * x 
dx = 0.0000001
deriv1 :: (Fractional a) => (a -> a) -> (a -> a)
deriv1 g = (\x -> ((g (x + 2) - (g x)) / 0.0000001 ))   
main = printf "res==%g %g\n" (square 5.12::Double) ((deriv1 square) 2::Float)

但这并不......

square :: (Num a) => a -> a 
square x = x * x 
dx = 0.0000001
deriv1 :: (Fractional a) => (a -> a) -> (a -> a)
deriv1 g = (\x -> ((g (x + 2) - (g x)) / dx ))          
main = printf "res==%g %g\n" (square 5.12::Double) ((deriv1 square) 2::Float)

注意我这次在derv1函数中使用了dx。我是Haskell的新手,所以任何关于类型的深入讨论都可能会让我快速地掠过我,我会死于旋转。我迫切需要一些类似命令性答案的东西,或者在我的Haskell职业生涯早期几乎肯定会失去我。

我收到的错误消息是:

Inferred type is less polymorphic than expected
  Quantified type variable `a' is mentioned in the environment:
    dx :: a (bound at sicp-1.40.hs:12:0)
When trying to generalise the type inferred for `deriv1'
  Signature type:     forall a. (Fractional a) => (a -> a) -> a -> a
  Type to generalise: (a -> a) -> a -> a
In the type signature for `deriv1'
When generalising the type(s) for `deriv1'

3 个答案:

答案 0 :(得分:6)

由于monomorphism restriction,您收到错误。由于您没有为dx提供类型签名,因此在这种情况下最终会将其推断为Double。您可以提供明确的多态签名,如

dx :: Fractional a => a
dx = 0.0000001

或者您可以通过在源文件的顶部包含此行来禁用单态限制

{-# LANGUAGE NoMonomorphismRestriction #-}

答案 1 :(得分:4)

避免结束单态限制的最好方法是将dx置于本地:

deriv1 :: (Fractional a) => (a->a) -> a->a
deriv1 g = (\x -> ((g (x + dx) - (g x)) / dx ))
   where dx = 0.0000001

请注意,我也为2更改了dx,这在您的定义中有点不对。 (不是编程方面,而是数学方面。)

顺便说一句,你也可以写这个

deriv1 g x = (g (x + dx) - g x) / dx

Haskell会自动将其转换为lambda。

答案 2 :(得分:2)

由于单态限制,dx的类型默认为Double。因此,当您在dx中除以deriv1时,Haskell会将另一个操作数推断为/,结果也必须具有Double类型。但是,由于您的类型签名显示为a,因此您会收到错误。

您可以通过明确声明dx具有类型Fractional a => a或禁用单态限制来解决此问题。