Reputation: 490
This question is a follow up on the question Haskell can't deduce type equality. I have tried implementing a basic polynomial approximator using the Trainable type described in my previous question with the following code:
module MachineLearning.Polynomial
(polynomial,
polynomialTrf
) where
import MachineLearning.Training
import MachineLearning.Utils
polynomialTrf :: Floating n => [n] -> n -> n
polynomialTrf coeff var = helper 0 coeff var 0 where
helper _ [] var acc = acc
helper 0 (c:cs) var acc = helper 1 cs var c
helper deg (c:cs) var acc = helper (deg+1) cs var (acc+(c*(var^deg)))
polynomialCost :: Floating n => n -> n -> [n] -> n
polynomialCost var target coeff = sqcost (polynomialTrf coeff var) target
polynomialSV :: (Floating n) => Trainable n n
polynomialSV = Trainable polynomialTrf polynomialCost
Here sqcost
is just sqcost a b = (a-b) ^ 2
. I get the following error message from the compiler:
src/MachineLearning/Polynomial.hs:18:26:
Could not deduce (n1 ~ n)
from the context (Floating n)
bound by the type signature for
polynomialSV :: Floating n => Trainable n n
at src/MachineLearning/Polynomial.hs:18:1-53
or from (Floating n1)
bound by a type expected by the context:
Floating n1 => [n1] -> n -> n
at src/MachineLearning/Polynomial.hs:18:16-53
`n1' is a rigid type variable bound by
a type expected by the context: Floating n1 => [n1] -> n -> n
at src/MachineLearning/Polynomial.hs:18:16
`n' is a rigid type variable bound by
the type signature for polynomialSV :: Floating n => Trainable n n
at src/MachineLearning/Polynomial.hs:18:1
Expected type: [n] -> n1 -> n1
Actual type: [n] -> n -> n
In the first argument of `Trainable', namely `polynomialTrf'
In the expression: Trainable polynomialTrf polynomialCost
src/MachineLearning/Polynomial.hs:18:40:
Could not deduce (n ~ n1)
from the context (Floating n)
bound by the type signature for
polynomialSV :: Floating n => Trainable n n
at src/MachineLearning/Polynomial.hs:18:1-53
or from (Floating n1)
bound by a type expected by the context:
Floating n1 => n -> n -> [n1] -> n1
at src/MachineLearning/Polynomial.hs:18:16-53
`n' is a rigid type variable bound by
the type signature for polynomialSV :: Floating n => Trainable n n
at src/MachineLearning/Polynomial.hs:18:1
`n1' is a rigid type variable bound by
a type expected by the context: Floating n1 => n -> n -> [n1] -> n1
at src/MachineLearning/Polynomial.hs:18:16
Expected type: n -> n -> [n1] -> n1
Actual type: n -> n -> [n] -> n
In the second argument of `Trainable', namely `polynomialCost'
In the expression: Trainable polynomialTrf polynomialCost
My question is where is the problem coming from? How can I solve it? For me it feels clear the those two types are equal, so there is the possibility that I misunderstand something in the type system.
Upvotes: 0
Views: 263
Reputation: 183978
I'm afraid the rank 2 type
data Trainable a b
= Trainable (forall n. Floating n => [n] -> a -> b)
(forall n. Floating n => a -> b -> [n] -> n)
won't help you. I concentrated only on the type error in the other question, and didn't notice that Floating
isn't rich enough to make that really usable. Since you can't generically convert from a Floating
type to some other type or to a Floating
type from anything but Real
s (realToFrac
), you can't write many interesting functions of the given polymorphic types in general, sorry.
The problem here is that the above type demands that the functions passed to the Trainable
constructor work for all Floating
types n
(whatever the specified a
and b
), but the implementations polynomialTrf
and polynomialCost
only work for one specific Floating
type, the one that is given as (both) the parameters. polynomialTrf
has the type Floating n => [n] -> n -> n
, but it would need to have the type (Floating n, Floating f) => [f] -> n -> n
to be eligible to be passed to the Trainable
constructor.
With a third type parameter, you would have
Trainable polynomialTrf polynomialCost :: Floating n => Trainable n n n
and for trainSgdFull
, you would need the type
trainSgdFull :: (Floating n, Ord n, Mode s) => Trainable a b (AD s n) -> [n] -> a -> b -> [[n]]
to be able to use gradientDescent
.
I don't know how a proper solution to your problem might look like.
Upvotes: 2