如何使类型变量不那么严格?

时间:2017-10-02 14:34:40

标签: haskell types polymorphism

我一直在努力实现自动差异化,从post

开始

这就是我所拥有的,到目前为止的工作:

data DX a = DX { val :: a, dx :: DX a }

instance Num n => Num (DX n) where
  fromInteger x = DX (fromInteger x) 0
  DX x₀ x' + DX y₀ y' = DX (x₀ + y₀) (x' + y')
  DX x₀ x' - DX y₀ y' = DX (x₀ - y₀) (x' - y')
  x@(DX x₀ x') * y@(DX y₀ y') = DX (x₀ * y₀) (x * y' + y * x')
  signum (DX x₀ x') = DX (signum x₀) 0
  abs x@(DX x₀ x') = DX (abs x₀) (signum x * x')

instance Fractional n => Fractional (DX n) where
  fromRational n = DX (fromRational n) 0
  x@(DX x₀ x') / y@(DX y₀ y') =
    DX (x₀ / y₀) ((x' * y - x * y') / y ^ 2)

instance Eq a => Eq (DX a) where
  a == b = val a == val b
instance Ord a => Ord (DX a) where
  compare a b = compare (val a) (val b)
instance Show a => Show (DX a) where
  show (DX x (DX x' (DX x'' _))) = show [x, x', x'']

var x = DX x 1

然后,我试图定义牛顿的方法,这就是我陷入困境的地方:

newtons :: (Num a, Fractional a, Ord a) => a -> (a -> a) -> a -> a
newtons eps f guess
  | abs (f guess) < eps   = guess
  | otherwise             = newtons eps f newGuess
    where
      newGuess              = guess - (x₀/x')
      (DX x₀ (DX x' _))     = f (var guess)

我得到的错误是:

randomStuff.hs:75:34:
    Couldn't match expected type ‘a’ with actual type ‘DX a’
      ‘a’ is a rigid type variable bound by
          the type signature for
            newtons :: (Num a, Fractional a) => a -> (a -> a) -> a -> a
          at randomStuff.hs:69:12
    Relevant bindings include
      guess :: a (bound at randomStuff.hs:70:15)
      f :: a -> a (bound at randomStuff.hs:70:13)
      eps :: a (bound at randomStuff.hs:70:9)
      newtons :: a -> (a -> a) -> a -> a (bound at randomStuff.hs:70:1)
    In the first argument of ‘f’, namely ‘(var guess)’
    In the expression: f (var guess)

我对此问题的理解如下:我已将给定函数推断为a -> a类型,但我尝试以DX a -> DX a形式使用它,不允许。

但是我应该能够以某种方式再次使用相同的函数,因为无论类型是什么,只要它在类型类NumFractional中就可以工作。

我的理解是否正确?我该如何解决这个问题?我需要Rank2Types吗?

1 个答案:

答案 0 :(得分:0)

以下类型签名使其有效

newtons :: (Num a, Ord a, Fractional a) => a -> (forall b. (Num b, Ord b, Fractional b) => b -> b) -> a -> a

我可以运行:

*Main> newtons 0.001 (\x -> x^2 - 2) 2
1.4142156862745099

所以,是的,一种合理的解决方法是使用Rank2Types