[Haskell-cafe] Problems with type family in a class
Niklas Haas
haskell at nand.wakku.to
Thu Jul 17 06:32:36 UTC 2014
On Wed, 16 Jul 2014 22:32:27 -0400, Leza Morais Lutonda <leza.ml at fecrd.cujae.edu.cu> wrote:
>
> Hi,
>
> Consider the following type classes:
>
> class (Signal sx) => Complexable sx where
> type ComplexSignalType
> ....
>
> class (Complexable sx) => FourierTransformable sx where
> fft :: (cx ~ ComplexSignalType sx) => cx -> cx
> ....
>
> and an instance:
>
> instance (RealFloat e) => Complexable [e] where
> type ComplexSignalType = [Complex e]
>
> instance (RealFloat e) => FourierTransformable [e] where
> fft = ...
>
> Why this example will give errors:
>
> *DSP.Signals.Core Prelude Data.Complex> :t ax
> ax :: [Complex Double]
> *DSP.Signals.Core Prelude Data.Complex> fft ax
>
> <interactive>:90:1:
> No instance for (FourierTransformable s0 [Complex Double])
> arising from a use of ‘fft’
> The type variable ‘s0’ is ambiguous
> Note: there is a potential instance available:
> instance [overlap ok] (RealFloat e, Math.FFT.Base.FFTWReal e) =>
> FourierTransformable [e] [Complex e]
> -- Defined at src/DSP/Signals/Instances/List.hs:40:10
> In the expression: fft ax
> In an equation for ‘it’: it = fft ax
>
>
> Thanks!
The reason you're getting this error is because all you know about your
instance is that the type of fft is :: [Complex Double] -> [Complex
Double].
Since by definition this [Complex Double] is ComplexSignalType sx, all
we know about the associated instance (parametrized by sx) is that
ComplexSignalType sx ~ [Complex Double]. Since ComplexSignalType is a
type family, it's not injective, so this does not suffice to uniquely
identify our actual instance (sx, here called s0 by GHC).
For example, we could have a second instance:
instance Complexable () where
type ComplexSignalType () = [Complex Double]
instance FourierTransformable () where
fft = error "oops"
And with this instance, fft would also be [Complex Double] -> [Complex
Double] but the behavior of would clearly be different to your actually
intended function.
If you think your signal function is bijective, you could use a two-way
functional dependency like this:
class Complexable sx cx | sx -> cx, cx -> sx
class Complexable sx cx => FourierTransformable sx cx where
fft :: cx -> cx
Or if you want to avoid the overhead of redesigning Complexable you
could even do something like this:
class (cx ~ ComplexSignalType sx, Complexable sx) => FourierTransformable sx cx | cx -> sx where
fft :: cx -> cx
Either way, if instance selection should be possible based solely on the
type of ‘cx’, then ‘cx’ must imply everything contained in the instance
head.
More information about the Haskell-Cafe
mailing list