I'ld like to implement a general Gaussian function for scalars and vectors. In Ada or C++ I simply would choose template for this, but in Haskell it's a little bit confusing.
I would start by defining a class that can apply Gaussian operators, like combining or calculating the probability:
class Gaussian g where
(!*) :: g -> g -> g
prob :: g -> a -> Float -- Here, I want a to be depending on g
data Gaussian1D = Gaussian1D Float Float
data Gaussian2D = Gaussian2D (Linear.V2 Float) Linear.V2(LinearV2 Float)
, and I'ld like to have something like:
instance Gaussian Gaussian1D where
prob :: Gaussian1D -> Float -> Float
instance Gaussian Gaussian2D where
prob :: Gaussian2D -> Linear.V2 Float -> Float
But I'm not able to implement this in a nice way. Would this somehow be possible with a multiparameter class without digging into the field of template-haskell, eg:
class Gaussian g a where
(!*) :: g a -> g a -> g a
prob :: g a -> a -> Float
? At the moment, I'm failing to realize this scenario when I do domething like:
data Gaussian1D = Gaussian1D Float Float
instance Gaussian Gaussian1D Float where
with error:
Expected kind ‘* -> *’, but ‘Gaussian1D’ has kind ‘*’
(btw, I don't understand why this error occurs)
Thx
This seems like a textbook use-case for Functional dependencies, a GHC-only language feature that allows multi-parameter type classes where one parameter uniquely determines the other:
{-# LANGUAGE FunctionalDependencies #-}
class Guassian g a | g -> a where
(!*) :: g -> g -> g
prob :: g -> a -> Float
instance Gaussian Gaussian1D Float where
-- ...
If you write g a
, for example in:
(!*) :: g a -> g a -> g a
It means that g
takes a type parameter. That should for example work if Gaussian1D
was defined as:
data Gaussian1D a = Gaussian1D a a
But that is not the case here. You can make a typeclass with two type parameters:
{-# LANGUAGE AllowAmbiguousTypes, MultiParamTypeClasses #-}
class Guassian g a where
(!*) :: g -> g -> g
prob :: g -> a -> Float
But this thus means that you can make an instance for any g
, a
combination. This thus means that a
does not depend on g
, or at least not directly. You thus can implement a Gaussian Gaussian1D Double
and Gaussian Gaussian1D Float
.
You can however make use of functional dependencies [wiki] where the type a
is determined by the type g
. This thus means that no two a
s can be used for the same g
:
{-# LANGUAGE AllowAmbiguousTypes, FunctionalDependencies, MultiParamTypeClasses #-}
class Guassian g a | g -> a where
(!*) :: g -> g -> g
prob :: g -> a -> Float
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With