问题描述
import Numeric.AD
导入限定的Data.Vector如V
newtype Mat a = Mat {unMat :: V.Vector a}
scale'f = Mat。 V.map(* f)。 unMat
add'ab = Mat $ V.zipWith(+)(unMat a)(unMat b)
sub'ab = Mat $ V.zipWith( - )(unMat a)(unMat b)
mul'ab = Mat $ V.zipWith(*)(unMat a)(unMat b)
pow'ae = Mat $ V.map(^ e)(unMat a)
sumElems':: Num a =>垫子 - >
sumElems'= V.sum。 unMat
(为了演示目的...我使用hmatrix但认为问题在那里)
和一个错误函数( eq3 ):
eq1':: Num a => [a] - > [Mat a] - > Mat a a
eq1'asφs= foldl1 add'$ zipWith scale'asφs
eq3':: Num a =>垫子 - > [a] - > [Mat a] - > a
eq3'img asφs= negate $ sumElems'(errImg`pow'`(2 :: Int))
where errImg = img`sub``(eq1'asφs)
为什么编译器无法推断出正确的类型?
diffTest :: forall a。 (小数a,Ord a)=>垫子 - > [Mat a] - > [a] - > [[a]]
diffTest mφsas0 = gradientdecent go as0
其中go xs = eq3'm xsφs
确切的错误信息是这样的:
src / Stuff.hs:59:37:
无法推断(a〜Numeric.AD.Internal.Reverse.Reverse sa)
来自上下文(小数a,Ord a)
由类型签名绑定
diffTest ::(分数a,Ord a)=>
垫子 - > [Mat a] - > [a] - > [[a]]
在src / Stuff.hs:58:13-69
或from(reflection-1.5.1.2:Data.Reflection.Reifies
s Numeric.AD.Internal.Reverse .Tape)
由上下文期望的类型绑定:
reflection-1.5.1.2:Data.Reflection.Reifies
s Numeric.AD.Internal.Reverse.Tape =>
[Numeric.AD.Internal.Reverse.Reverse s a]
- > Numeric.AD.Internal.Reverse.Reverse sa
at src / Stuff.hs:59:21-42
'a'是一个刚性类型变量,由
绑定,$ b的类型签名$ b diffTest ::(小数a,Ord a)=>
垫子 - > [Mat a] - > [a] - > [[a]]
at src // Stuff.hs:58:13
预期类型:[Numeric.AD.Internal.Reverse.Reverse s a]
- > Numeric.AD.Internal.Reverse.Reverse s a
实际类型:[a] - > a
相关绑定包括
go :: [a] - > a(绑定在src / Stuff.hs:60:9)
as0 :: [a](绑定在src / Stuff.hs:59:15)
φs:: [Mat a](bound在src / Stuff.hs:59:12)
m :: Mat a(绑定在src / Stuff.hs:59:10)
diffTest :: Mat a - > [Mat a] - > [a] - >
(在src / Stuff.hs:59:1处绑定)
在'gradientDescent'的第一个参数中,即'go'
在表达式中:gradientDescent go as0
功能具有类型
gradientDescent ::(Traversable f,Fractional a,Ord a)=>
(forall s。Reifies s Tape => f(Reverse s a) - > Reverse s a) - >
f a - > [fa]
它的第一个参数需要一个 fr - >的函数; r 其中 r 是 forall s。 (Reverse s a)。 go 的类型为 [a] - > a 其中 a 是 diffTest 签名中绑定的类型。这些 a s是相同的,但 Reverse sa 与 a 。
类型拥有许多类型类的实例,可以让我们将 a 转换为反向sa 或返回。最明显的是小数a => Fractional(Reverse sa),它允许我们将 a s转换为反向sa s与 realToFrac 。
为此,我们需要能够映射函数 a - >>在 Mat a 上获得 Mat b 。最简单的方法是为 Mat 派生一个 Functor 实例。
{ - #LANGUAGE DeriveFunctor# - }
newtype Mat a = Mat {unMat :: V.Vector a}
派生Functor
我们可以将 m 和 fs 放入任何小数a'=>使用 fmap realToFrac 。
diffTest m fs as0 = gradientdecent go as0
其中go xs = eq3'(fmap realToFrac m)xs(fmap(fmap realToFrac)fs)
但隐藏在广告包中有更好的方法。 Reverse sa 通用于所有 s ,但 a 与 diffTest 的类型签名中绑定的那个是相同的 a 。我们真的只需要一个函数 a - > (反过来)。此功能是,其中 Reverse sa 有一个实例。 auto 的类型稍微偏向 Mode t =>>标量t - > t 但是类型标量(反向s a)= a 。专为反向 auto 有类型
auto ::(Reifies s Tape,Num a)=> a - >反向sa
这允许我们将 Mat a $ c $将转换为 Mat(反向sa) s,而不会混淆与 Rational 中的转换。
{ - #LANGUAGE ScopedTypeVariables# - }
{ - #LANGUAGE TypeFamilies# - }
diffTest: :forall a。 (小数a,Ord a)=>垫子 - > [Mat a] - > [a] - > [[a]]
diffTest m fs as0 = gradientdecent go as0
where
go :: forall t。 (标量t〜a,模式t)=> [t] - > t
go xs = eq3'(fmap auto m)xs(fmap(fmap auto)fs)
Given a very simple Matrix definition based on Vector:
import Numeric.AD import qualified Data.Vector as V newtype Mat a = Mat { unMat :: V.Vector a } scale' f = Mat . V.map (*f) . unMat add' a b = Mat $ V.zipWith (+) (unMat a) (unMat b) sub' a b = Mat $ V.zipWith (-) (unMat a) (unMat b) mul' a b = Mat $ V.zipWith (*) (unMat a) (unMat b) pow' a e = Mat $ V.map (^e) (unMat a) sumElems' :: Num a => Mat a -> a sumElems' = V.sum . unMat
(for demonstration purposes ... I am using hmatrix but thought the problem was there somehow)
And an error function (eq3):
eq1' :: Num a => [a] -> [Mat a] -> Mat a eq1' as φs = foldl1 add' $ zipWith scale' as φs eq3' :: Num a => Mat a -> [a] -> [Mat a] -> a eq3' img as φs = negate $ sumElems' (errImg `pow'` (2::Int)) where errImg = img `sub'` (eq1' as φs)
Why the compiler not able to deduce the right types in this?
diffTest :: forall a . (Fractional a, Ord a) => Mat a -> [Mat a] -> [a] -> [[a]] diffTest m φs as0 = gradientDescent go as0 where go xs = eq3' m xs φs
The exact error message is this:
src/Stuff.hs:59:37: Could not deduce (a ~ Numeric.AD.Internal.Reverse.Reverse s a) from the context (Fractional a, Ord a) bound by the type signature for diffTest :: (Fractional a, Ord a) => Mat a -> [Mat a] -> [a] -> [[a]] at src/Stuff.hs:58:13-69 or from (reflection-1.5.1.2:Data.Reflection.Reifies s Numeric.AD.Internal.Reverse.Tape) bound by a type expected by the context: reflection-1.5.1.2:Data.Reflection.Reifies s Numeric.AD.Internal.Reverse.Tape => [Numeric.AD.Internal.Reverse.Reverse s a] -> Numeric.AD.Internal.Reverse.Reverse s a at src/Stuff.hs:59:21-42 ‘a’ is a rigid type variable bound by the type signature for diffTest :: (Fractional a, Ord a) => Mat a -> [Mat a] -> [a] -> [[a]] at src//Stuff.hs:58:13 Expected type: [Numeric.AD.Internal.Reverse.Reverse s a] -> Numeric.AD.Internal.Reverse.Reverse s a Actual type: [a] -> a Relevant bindings include go :: [a] -> a (bound at src/Stuff.hs:60:9) as0 :: [a] (bound at src/Stuff.hs:59:15) φs :: [Mat a] (bound at src/Stuff.hs:59:12) m :: Mat a (bound at src/Stuff.hs:59:10) diffTest :: Mat a -> [Mat a] -> [a] -> [[a]] (bound at src/Stuff.hs:59:1) In the first argument of ‘gradientDescent’, namely ‘go’ In the expression: gradientDescent go as0
The gradientDescent function from ad has the type
gradientDescent :: (Traversable f, Fractional a, Ord a) => (forall s. Reifies s Tape => f (Reverse s a) -> Reverse s a) -> f a -> [f a]
Its first argument requires a function of the type f r -> r where r is forall s. (Reverse s a). go has the type [a] -> a where a is the type bound in the signature of diffTest. These as are the same, but Reverse s a isn't the same as a.
The Reverse type has instances for a number of type classes that could allow us to convert an a into a Reverse s a or back. The most obvious is Fractional a => Fractional (Reverse s a) which would allow us to convert as into Reverse s as with realToFrac.
To do so, we'll need to be able to map a function a -> b over a Mat a to obtain a Mat b. The easiest way to do this will be to derive a Functor instance for Mat.
{-# LANGUAGE DeriveFunctor #-} newtype Mat a = Mat { unMat :: V.Vector a } deriving Functor
We can convert the m and fs into any Fractional a' => Mat a' with fmap realToFrac.
diffTest m fs as0 = gradientDescent go as0 where go xs = eq3' (fmap realToFrac m) xs (fmap (fmap realToFrac) fs)
But there's a better way hiding in the ad package. The Reverse s a is universally qualified over all s but the a is the same a as the one bound in the type signature for diffTest. We really only need a function a -> (forall s. Reverse s a). This function is auto from the Mode class, for which Reverse s a has an instance. auto has the slightly wierd type Mode t => Scalar t -> t but type Scalar (Reverse s a) = a. Specialized for Reverse auto has the type
auto :: (Reifies s Tape, Num a) => a -> Reverse s a
This allows us to convert our Mat as into Mat (Reverse s a)s without messing around with conversions to and from Rational.
{-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeFamilies #-} diffTest :: forall a . (Fractional a, Ord a) => Mat a -> [Mat a] -> [a] -> [[a]] diffTest m fs as0 = gradientDescent go as0 where go :: forall t. (Scalar t ~ a, Mode t) => [t] -> t go xs = eq3' (fmap auto m) xs (fmap (fmap auto) fs)
这篇关于如何对复杂数据类型进行自动区分?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!