简体   繁体   English

“ ..没有实例”,GHC7.8.3上的Haskell'98代码

[英]“No instance for .. ”, Haskell'98 code on GHC7.8.3

I'm trying out the attached code for linear regression with automatic differentiation . 我正在尝试使用自动微分进行线性回归的附加代码。 It specifies a datatype [Dual][2] made of two Floats, and declares it to be instance of Num, Fractional and Floating. 它指定由两个Float组成的数据类型[Dual] [2],并将其声明为Num,Fractional和Floating的实例。 As in all fitting/regression tasks, there's a scalar cost function, parametrized by the fitting parameters c and m, and an optimizer which improves on estimates of these two parameters by gradient descent. 像在所有拟合/回归任务中一样,存在一个由拟合参数c和m参数化的标量成本函数,以及一个优化器,该优化器通过梯度下降改进了这两个参数的估计。

Question I'm using GHC 7.8.3, and the authors explicitly mention that this is H98 code (I mentioned it in the title because it's the only substantial difference I can think of between my setup and the Author's, however plz correct if wrong). 问题我使用的是GHC 7.8.3,作者明确提到这是H98代码(我在标题中提到了它,因为这是我可以想到的设置与作者设置之间的唯一实质性区别,但是如果出错,请plz正确) 。 Why does it choke within the definition of the cost function? 为什么它在成本函数的定义之内cho塞? My understanding is: the functions idD and constD map Floats to Duals, g is polymorphic (it can perform algebraic operations on Dual inputs because Dual inherits from Num, Fractional and Floating), and deriv maps Duals to Doubles. 我的理解是:函数idD和constD将Floats映射为Duals,g是多态的(由于Dual从Num,Fractional和Floating继承,因此它可以对Dual输入执行代数运算),并且将Duals映射为Doubles。 The type signature for g (the eta-reduced cost function wrt the data) was inferred. 推断出g的类型签名(数据减少了eta的成本函数)。 I tried omitting it, and making it more general by substituting a Floating type constraint to the Fractional one. 我尝试省略它,并通过将Floating类型约束替换为Fractional约束使它更通用。 Moreover, I tried converting the numeric types of c and m inline with (fromIntegral c :: Double), to no avail. 而且,我尝试将(fromIntegral c :: Double)内联的c和m的数字类型转换为无效。

Specifically this code gives this error: 具体来说,这段代码给出了以下错误:

No instance for (Integral Dual) arising from a use of ‘g’
In the first argument of ‘flip’, namely ‘g’
In the expression: flip g (constD c)
In the second argument of ‘($)’, namely ‘flip g (constD c) $ idD m’

Any hints, please? 有什么提示吗? I'm sure it's a very noob question, but I just don't get it. 我敢肯定这是一个非常菜鸟的问题,但我只是不明白。

The complete code is the following: 完整的代码如下:

{-# LANGUAGE NoMonomorphismRestriction #-}

module ADfw (Dual(..), f, idD, cost) where

data Dual = Dual Double Double deriving (Eq, Show)

constD :: Double -> Dual
constD x = Dual x 0

idD :: Double -> Dual
idD x = Dual x 1.0

instance Num Dual where
  fromInteger n             = constD $ fromInteger n
  (Dual x x') + (Dual y y') = Dual (x+y) (x' + y')
  (Dual x x') * (Dual y y') = Dual (x*y) (x*y' + y*x')
  negate (Dual x x')        = Dual (negate x) (negate x')
  signum _                  = undefined
  abs _                     = undefined

instance Fractional Dual where
  fromRational p = constD $ fromRational p
  recip (Dual x x') = Dual (1.0 / x) (- x' / (x*x))

instance Floating Dual where
   pi = constD pi
   exp   (Dual x x') = Dual (exp x)   (x' * exp x)
   log   (Dual x x') = Dual (log x)   (x' / x)
   sqrt  (Dual x x') = Dual (sqrt x)  (x' / (2 * sqrt x))
   sin   (Dual x x') = Dual (sin x)   (x' * cos x)
   cos   (Dual x x') = Dual (cos x)   (x' * (- sin x))
   sinh  (Dual x x') = Dual (sinh x)  (x' * cosh x)
   cosh  (Dual x x') = Dual (cosh x)  (x' * sinh x)
   asin  (Dual x x') = Dual (asin x)  (x' / sqrt (1 - x*x))
   acos  (Dual x x') = Dual (acos x)  (x' / (-sqrt (1 - x*x)))
   atan  (Dual x x') = Dual (atan x)  (x' / (1 + x*x))
   asinh (Dual x x') = Dual (asinh x) (x' / sqrt (1 + x*x))
   acosh (Dual x x') = Dual (acosh x) (x' / (sqrt (x*x - 1)))
   atanh (Dual x x') = Dual (atanh x) (x' / (1 - x*x))

-- example
-- f    = sqrt . (* 3) . sin
-- f' x = 3 * cos x / (2 * sqrt (3 * sin x)) 

-- linear fit sum-of-squares cost
-- cost :: Fractional s => s -> s -> [s] -> [s] -> s
cost m c x y = (/ (2 * (fromIntegral $ length x))) $
               sum $ zipWith errSq x y
  where
    errSq xi yi = zi * zi
      where
        zi = yi - (m * xi + c)

-- test data
x_ = [1..10]
y_ = [a | a <- [1..20], a `mod` 2 /= 0]

-- learning rate
gamma = 0.04

g :: (Integral s, Fractional s) => s -> s -> s
g m c = cost m c x_ y_

deriv (Dual _ x') = x'

 z_ = (0.1, 0.1) : map h z_

 h (c, m) = (c - gamma * cd, m - gamma * md) where
   cd = deriv $ g (constD m) $ idD c
   md = deriv $ flip g (constD c) $ idD m

 -- check for convergence
 main = do
   take 2 $ drop 1000 $ map (\(c, m) -> cost m c x_ y_) z_
   take 2 $ drop 1000 $ z_

where the test data x_ and y_ are arrays and the learning rate gamma a scalar. 其中测试数据x_和y_是数组,学习率gamma是标量。

[2]: The two fields of a Dual object are in fact adjoint one with the other, if we see the derivative as an operator [2]:如果我们将导数视为运算符,则对偶对象的两个字段实际上彼此相邻

In the original code, I don't see a type signature for g . 在原始代码中,我没有看到g的类型签名。 In your code, you have specifically written 在您的代码中,您专门编写了

g :: (Integral s, Fractional s) => s -> s -> s

The error message says there's no Integral instance for Dual . 错误消息指出Dual没有Integral实例。 The code manually defines instances for Num and Fractional , but not Integral . 该代码手动定义了NumFractional实例,但没有Integral实例。

I'm not actually sure why g needs to be Integral . 我实际上不确定为什么g必须是Integral If you remove that constraint, the code may even work... 如果您删除该约束,则该代码甚至可以工作...

EDIT: It seems the Integral instance is necessary because of your use of mod to generate test data. 编辑:由于您使用mod生成测试数据,因此似乎需要Integral实例。 I'm not really sure what this huge block of code does, but I suspect if you apply fromIntegral to convert everything to (say) Double , then it may work. 我不确定这块巨大的代码是做什么的,但是我怀疑如果您应用fromIntegral将所有内容都转换为(例如) Double ,那么它可能会起作用。

(I suspect making Dual an instance of Integral is probably not what the original authors intended. Then again, I don't really understand the code, so...) (我怀疑使Dual成为Integral的实例可能不是原始作者想要的。然后,我也不是很了解代码,所以...)

First, (Integral s, Fractional s) makes no sense; 首先, (Integral s, Fractional s)没有意义; Integral is for Euclidean domains (ones with div and mod ), while Fractional is for fields (ones with / ). Integral适用于欧几里得域(带有divmod ),而Fractional适用于字段(带/ )。 If you have true division all your remainders are going to be zero... . 如果您有真正的除法,那么您所有的余数都将为零...。

I think the problem is y_ 's attempt to filter to odd numbers. 我认为问题是y_尝试过滤为奇数。 Haskell 98 defines a 'stepped' range form for numbers, so you could write y_ as [1,3..19] . Haskell 98为数字定义了“步进”范围形式,因此您可以将y_写为[1,3..19] That should allow y_ to be used at the type [Dual] , which should allow g to use it without needing the Integral constraint. 那应该允许y_[Dual]类型上使用,这应该允许g在不需要Integral约束的情况下使用它。

Edit: Ørjan Johansen points out that you need an Enum instance for Dual as well, which is actually fairly easy to implement (this is pretty standard for numeric types; I basically copied GHC's instance for Double (which is identical to its instance for Float , for example)): 编辑:ØrjanJohansen指出,您还需要DualEnum实例,这实际上很容易实现(对于数字类型,这是相当标准的;我基本上为Double复制了GHC的实例(这与Float实例相同,例如)):

instance Enum Dual where
    succ x              = x + 1
    pred x              = x - 1
    toEnum              = fromIntegral
    fromEnum (Dual x _) = fromEnum x
    enumFrom            = numericEnumFrom
    enumFromTo          = numericEnumFromTo
    enumFromThen        = numericEnumFromThen
    enumFromThenTo      = numericEnumFromThenTo

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM