Haskell: how to write code that interacts with the internals of two wrapped types? - haskell

I'm wondering how to create two encapsulated types that interact with each other, without exposing the internal implementation to other modules.
As an example, consider my two modules, Vector.hs and Matrix.hs, that wrap Linear.V4 (a 4-element vector) and Linear.M44 (a 4x4 element matrix). I wish to write a function that multiplies a Matrix by a Vector, returning a Vector, and using the wrapped data types to perform the operation.
In this example, in Vector.hs I have:
-- Vector.hs
module Vector (Vector, vector) where
import Linear (V4 (V4))
newtype Vector = Vector (V4 Double) deriving (Eq, Show, Read)
vector :: (Double, Double, Double, Double) -> Vector
vector (x, y, z, w) = Vector (V4 x y z w)
Note that I'm only exporting the new type and the factory function - the data constructor Vector is not exported. As far as I understand, this hides the internal implementation of Vector (i.e. that it's really a V4).
And in Matrix.hs I have something similar:
-- Matrix.hs
module Matrix (Matrix, vector)
import Linear (V4 (V4), M44)
type Row = (Double, Double, Double, Double)
newtype Matrix = Matrix (M44 Double) deriving (Eq, Show, Read)
matrix :: (Row, Row, Row, Row) -> Matrix
--matrix ((a00, a01, a02, a03), (a10, ... ) = Matrix (V4 (V4 a00 a01 a02 a03) (V4 a10 ...))
These two modules can be used by client code pretty effectively - the client code is not aware that they are implemented with Linear data structures, and there's apparently no way for client code to exploit that (is that true?).
The problem arises when those two types need to interact with each other at the level of their wrapped types - in this particular case, multiplying a Matrix by a Vector yields a new Vector. However to implement this operation, the code performing it needs access to the internal implementation of both Vector and Matrix, in order to do something like this:
-- Matrix.hs
-- ... include earlier definitions
{-# LANGUAGE FlexibleInstances #-}
import qualified Linear.Matrix ((!*))
class MatrixMultiplication a b c | a b -> c where
infixl 7 |*| -- set same precedence and associativity as *
(|*|) :: a -> b -> c
instance MatrixMultiplication Matrix Vector Vector where
(|*|) (Matrix a) q0 =
let (V4 x y z w) = a Linear.Matrix.!* _impl q0
in vector (x, y, z, w)
To do this I need a function, _impl, that allows the Matrix module to get at the internals of Vector:
-- Vector.hs
-- ... include earlier definitions
_impl :: Vector -> V4 Double
_impl (Vector q) = q
-- also added to export list
So after carefully hiding the internals of Vector (by not exporting the data constructor function of Vector), it seems I must expose them with a different exported function, and the only defence I have is some documentation telling client code they shouldn't be using it. This seems unfortunate - I've effectively just renamed the data constructor.
In a language like C++, the friend keyword could be used to provide a function access to the private data member of one of the types. Is there a similar concept in Haskell?
I suppose I could implement both Vector and Matrix in the same module. They'd then have access to each others' data constructors. However this isn't really a satisfying solution as it just works around the issue.
Is there a better approach?

Related

Haskell data type for hmatrix Vector and Matrix

I am just starting out with Haskell, I have read up to the defining data types section of LYAH and am attempting to implement the Sum-Product algorithm for Belief Propagation. One of the rudimentary tasks is to define the Probabilistic Graphical Model.
As shown below, I have attempted to create a graph by tying the knot to represent the graph where each node represents a Gaussian distribution and has constant weight links(for now) to it's neighbours. However, when trying to define the Mean and Covariance types I am having some difficulty in specifying the types of the Matrix and Vector types, i.e. Float or Double.
module Graph(Graph) where
import Numeric.LinearAlgebra
data Mean = Mean Vector
data Covariance = Covariance Matrix
data Gaussian = Gaussian Mean Covariance
data Node = Node [Node] Gaussian
data Graph = Graph [Node]
In this simple example, what is the syntax to define Mean as a Vector of type Double and Covariance as a Matrix of type Double. Additionally, how would one generalise so that Mean and Covariance can be of type Float or Double?
I currently get the following from GHCi
Graph.hs:5:18: error:
• Expecting one more argument to ‘Vector’
Expected a type, but ‘Vector’ has kind ‘* -> *’
• In the type ‘Vector’
In the definition of data constructor ‘Mean’
In the data declaration for ‘Mean’
Failed, modules loaded: none.
I am using the hmatrix package as described here
Vector and Matrix are parameterised on the scalar type (so you can not only have matrices of floating-point “real numbers”, but also matrices of integers, complex numbers etc.). This is what GHC tells you by ‘Vector’ has kind ‘* -> *’: by itself, Vector is not a type (types have kind *, aka Type). Rather it is a type function mapping types of kind * to types of kind *. Scalars like Double are already plain types, so you can just apply Vector to them.
GHCi> :kind Vector
Vector :: * -> *
GHCi> :k Double
Double :: *
GHCi> :k Vector Double
Vector Double :: *
Thus you need
newtype Mean = Mean (Vector Double)
newtype Covariance = Covariance (Matrix Double)
(newtype does the same thing as data here, but it's a bit more efficient because no extra box/pointer is needed).
Alternatively, you may use more meaningfully-typed vector spaces, e.g.
import Math.LinearMap.Category
newtype Mean v = Mean v
newtype Covariance v = Covariance (v +> DualVector v)
The advantage of this is that dimensions are checked at compile time, which prevents nasty runtime errors (and can in principle also improve performance, though frankly the linearmap-category library is not optimised at all yet).
You'd then also parameterise the other types over the vector space:
data Gaußian v = Gaußian (Mean v) (Covariance v)
data Node v = Node [Node v] (Gaussian v)
data Graph v = Graph [Node v]
Somewhat unrelated to your question: this knot-tying sure feels elegant, but it's not really a suitable way to represent a graph, because nodes can't be identity-checked. Any cycles in the graph lead to, for all distinguishable means, an infinite structure. In practice, you won't get around giving your nodes e.g. Int labels and keeping a separate structure for the edges.

Typeclass instances with constrained return type

I'm implementing a notion of inner product that's general over the container and numerical types. The definition states that the return type of this operation is a (non-negative) real number.
One option (shown below) is to write all instances by hand, for each numerical type (Float, Double, Complex Float, Complex Double, Complex CFloat, Complex CDouble, etc.). The primitive types aren't many, but I dislike the repetition.
Another option, or so I thought, is to have a parametric instance with a constraint such as RealFloat (which represents Float and Double).
{-# language MultiParamTypeClasses, TypeFamilies, FlexibleInstances #-}
module Test where
import Data.Complex
class Hilbert c e where
type HT e :: *
dot :: c e -> c e -> HT e
instance Hilbert [] Double where
type HT Double = Double
dot x y = sum $ zipWith (*) x y
instance Hilbert [] (Complex Double) where
type HT (Complex Double) = Double
a `dot` b = realPart $ sum $ zipWith (*) (conjugate <$> a) b
Question
Why does the instance below not work ("Couldn't match type e with Double.. expected type HT e, actual type e")?
instance RealFloat e => Hilbert [] e where
type HT e = Double
dot x y = sum $ zipWith (*) x y
Well, that particular instance doesn't work because the sum only yields an e, but you want the result to be Double. As e is constrained to RealFrac, this is easy to fix though, as any Real (questionable though is is mathematically) can be converted to a Fractional:
dot x y = realToFrac . sum $ zipWith (*) x y
However, that generic instance prevents you from also defining complex instances: with instance RealFloat e => Hilbert [] e where you cover all types, even if they aren't really real numbers. You could still instantiate Complex as an overlapping instance, but I'd rather stay away from those if I could help it.
It's also questionable if such vectorspace classes should be defined on * -> * at all. Yes, linear also does it this way, but IMO parametricity doesn't work in our favour in this application. Have you checked out the vector-space package? Mind, it isn't exactly complete for doing serious linear algebra; that's a gap I hope to fill with my linearmap-category package.

Haskell linear algebra libraries that are polymorphic with classes of kind *

I want to use a linear algebra library with netwire. Because netwire's types are instances of Applicative, it provides Num and Fractional instances for its types that automagically liftA2 the appropriate function. This is nice because you can do things like multiply time-varying values without any extra effort.
I've been using linear, but its functions are defined to be polymorphic over a non-* kind, ie the matrix product:
(!*!) :: (Functor m, Foldable t, Additive t, Additive n, Num a)
=> m (t a) -> t (n a) -> m (n a)
This means, if I am not much mistaken, that I can't define instances for Additive and company, because there is no sane form for the instance to take. While I can write
instance Num b => Num (Wire s e m a b) where ...
there is no way to write
instance Additive n => Additive (Wire s e m a (n x)) where ...
because (Wire s e m a (n x)) has the wrong kind (* as opposed to * -> *). Other libraries I've seen aren't polymorphic at all.
What I want to know is, which linear algebra libraries are polymorphic over kind *?
I've looked at Vec, which seems better. Its matrix multiply has type
(Map v v' m1 m3, Map v a b v', Transpose m2 b, Fold v a, Num v, Num a)
=> m1 -> m2 -> m3
which is what I want. Are there other libraries like this?
There's vector-space, which is indeed in many ways more elegant than the libraries that are parameterised over their scalars (VectorSpace has that field instead as an associated type synonym).
Part of what I like about it is that it's totally not based on free vector spaces as linear is, which means a signature based on Foldables wouldn't make any sense in the first place. (Indeed, it doesn't talk about matrices at all, only about linear mappings, which are simply the morphisms of the category of vector spaces)
instance (AdditiveGroup a) => AdditiveGroup (Wire a) where
...
instance (VectorSpace v) => VectorSpace (Wire v) where
type Scalar (Wire v) = Scalar v -- Or perhaps `Wire (Scalar v)`
...
I did a survey of some other libraries, and here's what I found:
hmatrix - actively maintained; classes of kind * -> *, GPL licensed
vect - OpenGL bindings; not actively maintained; uses hardwired scalar types so things like dot can't be lifted
Vec - sort of actively maintained; not overloaded correctly (see below); useful auxiliary functions; no OpenGL bindings
linear - actively maintained; supported by GLUtil and vinyl-gl; * -> * classes
vector-space - sort of actively maintained; overloaded correctly; OpenGL bindings, but for vectors only; after an hour I still can't figure out how to use it, especially the linear mappings
Tensor - built into OpenGL; no math functions
bed-and-breakfast - actively maintained; uses unboxed arrays; uses type families on value type, so it could be overloaded but it would look weird (ie Matrix (Wire s e m a Double) is a wire carrying matricies); no OpenGL interface
This eliminates all but Vec, vector-space, and bed-and-breakfast. The wonky types eliminate bed-and-breakfast (unfortunately, because it's otherwise nice). In the end Vec ends up winning just a little over vector-space because it seems to be designed for graphics rather than abstract algebra study. And because I can't seem to figure out how to make a perspective transformation with linear maps.
I'll have to write an OpenGL interface (which shouldn't be too bad since it's already Storable). The only downside is that I can't think of a sensible typeclass for dimension-dependent arguments/results of auxiliary functions (ie rotationX :: Floating a => a -> Mat44 a). This is one of the strengths of vector-space I lose with Vec.
Update: Vec will not work. The classes aren't just for result types, they are on types that get put into the vector as well. For instance, the Fold class.
Final update: I ended up giving up on this idea and creating separate functions for Wires.

How to have an operator which adds/subtracts both absolute and relative values, in Haskell

(Apologies for the weird title, but I could not think of a better one.)
For a personal Haskell project I want to have the concepts of 'absolute values' (like a frequency) and relative values (like the ratio between two frequencies). In my context, it makes no sense to add two absolute values: one can add relative values to produce new relative values, and add a relative value to an absolute one to produce a new absolute value (and likewise for subtraction).
I've defined type classes for these: see below. However, note that the operators ##+ and #+ have a similar structure (and likewise for ##- and #-). Therefore I would prefer to merge these operators, so that I have a single addition operator, which adds a relative value (and likewise a single subtraction operator, which results in a relative value). UPDATE: To clarify, my goal is to unify my ##+ and #+ into a single operator. My goal is not to unify this with the existing (Num) + operator.
However, I don't see how to do this with type classes.
Question: Can this be done, and if so, how? Or should I not be trying?
The following is what I currently have:
{-# LANGUAGE MultiParamTypeClasses #-}
class Abs a where
nullPoint :: a
class Rel r where
zero :: r
(##+) :: r -> r -> r
neg :: r -> r
(##-) :: Rel r => r -> r -> r
r ##- s = r ##+ neg s
class (Abs a, Rel r) => AbsRel a r where
(#+) :: a -> r -> a
(#-) :: a -> a -> r
I think you're looking for a concept called a Torsor. A torsor consists of set of values, set of differences, and operator which adds a difference to a value. Additionally, the set of differences must form an additive group, so differences also can be added together.
Interestingly, torsors are everywhere. Common examples include
Points and Vectors
Dates and date-differences
Files and diffs
etc.
One possible Haskell definition is:
class Torsor a where
type TorsorOf a :: *
(.-) :: a -> a -> TorsorOf a
(.+) :: a -> TorsorOf a -> a
Here are few example instances:
instance Torsor UTCTime where
type TorsorOf UTCTime = NominalDiffTime
a .- b = diffUTCTime a b
a .+ b = addUTCTime b a
instance Torsor Double where
type TorsorOf Double = Double
a .- b = a - b
a .+ b = a + b
instance Torsor Int where
type TorsorOf Int = Int
a .- b = a - b
a .+ b = a + b
In the last case, notice that the two sets of the torsors don't need to be a different set, which makes adding your relative values together simple.
For more information, see a much nicer description in Roman Cheplyakas blog
I don't think you should be trying to unify these operators. Subtracting two vectors and subtracting two points are fundamentally different operations. The fact that it's difficult to represent them as the same thing in the type system is not the type system being awkward - it's because these two concepts really are different things!
The mathematical framework behind what you're working with is the affine space.
These are already available in Haskell in the vector-space package (do cabal install vector-space at the command prompt). Rather than using multi parameter type classes, they use type families to associate a vector (relative) type with each point (absolute) type.
Here's a minimal example showing how to define your own absolute and relative data types, and their interaction:
{-# LANGUAGE TypeFamilies #-}
import Data.VectorSpace
import Data.AffineSpace
data Point = Point { px :: Float, py :: Float }
data Vec = Vec { vx :: Float, vy :: Float }
instance AdditiveGroup Vec where
zeroV = Vec 0 0
negateV (Vec x y) = Vec (-x) (-y)
Vec x y ^+^ Vec x' y' = Vec (x+x') (y+y')
instance AffineSpace Point where
type Diff Point = Vec
Point x y .-. Point x' y' = Vec (x-x') (y-y')
Point x y .+^ Vec x' y' = Point (x+x') (y+y')
You have two answers telling you what you should do, here's another answer telling you how to do what you asked for (which might not be a good idea). :)
class Add a b c | a b -> c where
(#+) :: a -> b -> c
instance Add AbsTime RelTime AbsTime where
(#+) = ...
instance Add RelTime RelTime RelTime where
(#+) = ...
The overloading for (#+) makes it very flexible. Too flexible, IMO. The only restraint is that the result type is determined by the argument types (without this FD the operator becomes almost unusable because it constrains nothing).

writing a function that accepts multiple input and has multiple outputs in haskell

whats the correct way to write a function that can accept different input's and have different outputs
for example i'm using hmatrix and
lets say i want to accept a Matrix or a Vector in my function, and the output can be a Matrix or a Vector depending on hte formula
where T in the below example can be a matrix or a vector , is maybe the right tool for this?
Myfunc ::(Matrix A, Matrix/Vector T) -> Maybe(Matrix/Vector T)
Update using either mentioned below here is one possible solution
Myfunc :: Maybe Matrix Double t -> (Either Vector Double a,Matrix Double a) -> Either (Matrix Double T,Vector Double T)
Take a look at how matrix multiplication and left-divide are implemented in the source code for HMatrix.
Essentially, they define a multi-parameter type class which tells the function how to behave for different inputs, and it has a functional dependency which tells it what output is appropriate. For example, for multiplication:
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FunctionalDependencies #-}
-- |The class declaration 'Mul a b c' means "an 'a' multiplied by a 'b' returns
-- a 'c'". The functional dependency 'a b -> c' means that once 'a' and 'b' are
-- specified, 'c' is determined.
class Mul a b c | a b -> c where
-- | Matrix-matrix, matrix-vector, and vector-matrix products.
(<>) :: Product t => a t -> b t -> c t
-- |Matrix times matrix is another matrix, implemented using the matrix
-- multiplication function mXm
instance Mul Matrix Matrix Matrix where
(<>) = mXm
-- |Matrix times vector is a vector. The implementation converts the vector
-- to a matrix and uses the <> instance for matrix/matrix multiplication/
instance Mul Matrix Vector Vector where
(<>) m v = flatten $ m <> asColumn v
-- |Vector times matrix is a (row) vector.
instance Mul Vector Matrix Vector where
(<>) v m = flatten $ asRow v <> m
You could either have a look at Either (I know, it's a bad joke), or, if your function has a general meaning but different implementations on different data types, you could define a typeclass.
edit: I didn't add any further details because your question isn't completely clear to me
The question is what do you want to do with your input? For example if you want to do comparison then you can say input has to be of class Ord like this:
myFunc :: (Ord a) => a -> b
Another way would be to use Either, but in that case you can have only two different data types. For example
myFunc :: Either a b -> Either c d
can accept and return different types.
Another solution would be to use a list of lists [[a]]. Essentially a vector is a matrix with a single row.

Resources