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 fromad
has the typeIts first argument requires a function of the type
f r -> r
wherer
isforall s. (Reverse s a)
.go
has the type[a] -> a
wherea
is the type bound in the signature ofdiffTest
. Thesea
s are the same, butReverse s a
isn't the same asa
.The
Reverse
type has instances for a number of type classes that could allow us to convert ana
into aReverse s a
or back. The most obvious isFractional a => Fractional (Reverse s a)
which would allow us to converta
s intoReverse s a
s withrealToFrac
.To do so, we'll need to be able to map a function
a -> b
over aMat a
to obtain aMat b
. The easiest way to do this will be to derive aFunctor
instance forMat
.We can convert the
m
andfs
into anyFractional a' => Mat a'
withfmap realToFrac
.But there's a better way hiding in the ad package. The
Reverse s a
is universally qualified over alls
but thea
is the samea
as the one bound in the type signature fordiffTest
. We really only need a functiona -> (forall s. Reverse s a)
. This function isauto
from theMode
class, for whichReverse s a
has an instance.auto
has the slightly wierd typeMode t => Scalar t -> t
buttype Scalar (Reverse s a) = a
. Specialized forReverse
auto
has the typeThis allows us to convert our
Mat a
s intoMat (Reverse s a)
s without messing around with conversions to and fromRational
.