
Henning:
I was wrong, the different names are synonymes for the same type. :-(
I agree that we must statically distinguish Vector and Matrix (see below).
Some notes: I would not call it a matrix library but a linear algebra library. Then setup modules like LinearAlgebra.Matrix, LinearAlgebra.Vector and so on and move functions related to each type into these modules. Vector is more basic than Matrix, thus Matrix should import Vector, not vice versa, it should contain Matrix-Vector operations. The Vector module could contain e.g. the scalar product. I also find it good style not to repeat the modules name in function and type names. E.g. Matrix.mulVector is a good function name, but the type name should also not be Matrix.Matrix but say Matrix.T. Unfortunately this style is not very widely spread currently, I wished it would be more.
You are right, module structure and names are provisional.
Then you may consider no to restrict the library to Double. Most operations can be defined in terms of any numbers (including even say matrices of matrices). This can be handled by type classes. The instances for Double can invoke GSL, others may use Haskell routines.
Ok. Currently we can have "blocks" of Storable types. Block Double works with the GSL and Block Int is only in Num, using Haskell. Clearly we should admit other any number as base type.
If you are interested I have here some algorithm for computing the determinant of a n by n matrix in n^4 steps which does not need division and thus can be used for integers and polynomials.
Of course I would like to see it, and we can include it in the library... David:
The one thing I'd like to see (and here I agree with Hennig) is a distinction between matrices and tensors. Your library is really very tensor-based, but tensors and matrices are very different beasts.
I imagine one could take your Block, which is really a sort of generalized tensor, and implement a Matrix type such as
data Matrix = M (Block Double)
(or perhaps for arbitrary element type) with the constructor not exported, so that Matrices will always be guaranteed to be two-dimensional.
Then for matrices one could define * to be matrix multiplication, sqrt, exp, cos, sin etc to be matrix functions (expm etc in octave-speak), and then define .* and ./ to be as defined in octave.
This definition would allow considerably more type-safeness than your current implementation (which seems scarily dynamically typed to me).
To me too! Due to the type trickery required to statically check matrix dimensions in this first version I also used a common type for blocks with any number of indices, which ruins many of the Haskell advantages. I will work on your idea. We can have different types for scalar, vector and matrix, with elementwise numeric operations, and using multiparamenter classes we can statically check typical multiplications and other functions. We can also define a constructor from vectors or matrices to arbitrary blocks, to be used (dynamically) in more general but less frequent situations.
Alas, we'd still not have the truly strong typing I'd dream about where one could define
matMul :: Int n, m, l => Matrix n m -> Matrix m l -> Matrix n l
which as I understand things, isn't possible in Haskell without some sort of weird type trickery. Of course, if you had this kind of type trickery, you might not need to declare a separate Matrix type, since you'd be able to represent the dimensionality of the Block in its type.
And hopefully you and he can work together to create a great library (and I'll be able to mooch off of whatever you create...). :)
Of course! I am very happy to know that other people is also interested in a simple "scientific computing" library for Haskell. Alberto