3

我现在正在和 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)

注意我dx这次在derv1函数中使用了。我是 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'
4

3 回答 3

6

由于单态限制,您会得到错误。由于您没有为其提供类型签名,dx因此最终会像Double在这种情况下那样推断出来。您可以给出明确的多态签名,例如

dx :: Fractional a => a
dx = 0.0000001

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

{-# LANGUAGE NoMonomorphismRestriction #-}
于 2012-07-21T07:09:50.393 回答
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。

于 2012-07-21T08:13:36.883 回答
2

由于单态性限制,类型dx默认为 Double。因此,当您除以dxin 时deriv1,Haskell 会推断出另一个操作数/和结果也必须具有 Double 类型。但是由于您的类型签名说a,您会得到您所做的错误。

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

于 2012-07-21T07:09:53.773 回答