[Haskell-cafe] vector-space and standard API for vectors

Alexey Khudyakov alexey.skladnoy at gmail.com
Sun Oct 31 18:36:40 EDT 2010

On Wed, Oct 27, 2010 at 2:53 AM, wren ng thornton <wren at freegeek.org> wrote:
> On 10/26/10 8:51 AM, Alexey Khudyakov wrote:
>> On 24.10.2010 03:38, wren ng thornton wrote:
>>> I don't care much about the name of the class, I'd just like support for
>>> monoids, semirings,... when they lack a group, ring,... structure.
>> Then what about following type class hierarchy? I think it supports
>> those structures. Only restriction is that it forces one to have both
>> left and right modules. It's possible to split them but I think it will
>> be to painful for vector spaces over R and C.
>> class Module v where
>> type Scalar v :: *
>> (*^) :: Scalar v → v → v
>> (^*) :: v → Scalar v → v
>> (^*) = flip (*^)
> Is there any good reason for forcing them together? Why not, use the
> hierarchy I proposed earlier? If you want to reduce the clutter in type
> signatures for real and complex vector spaces then just add to my previous
>    -- Or just call it "Module" if preferred.
>    class (LeftModule v, RightModule v) => AssociativeModule v where
>        -- Law: (^*) == flip (*^)
> This way, when (not if) people want nonassociative modules the classes are
> already there. The additional overhead in defining an associative module is
> only three lines when using default implementation; two lines otherwise:
>    type instance Scalar Foo = Bar
>    instance AssociativeModule Foo where
>    instance RightModule Foo where
>        (^*) = flip (^*)
>    instance LeftModule Foo where
>        (*^) = ...
> vs
>    instance Module Foo where
>        type Scalar Foo = Bar
>        (*^) = ...
> And once it's defined, the usage is the same: just require AssociativeModule
> and you'll pull in both (*^) and (^*).
Main reason is that it complicate creation of instances for types for which
multiplication is associative and commutative more complicated.
Programmer must write three instances instead of one and they must
satisfy some law. It leads to code which more difficult to understand and
contain more bug (mostly dumb).

This is tradeoff between usability and generality. Modules are much less
frequent and much less known than vector space. I for example didn't known
about their existence before. I think difficulties should be pushed on
the people
who define instances for non associative modules.

One possibility is to add separate type classes for left and right modules
and require that is type is has both Module and LeftModule instances
(*^^) == (*^)

  class Module v where
    (^*) :: v -> Scalar v -> v
    (*^) :: Scalar v -> v -> v

Of course code that is written to work with left/right modules wont work with
associative modules.

> We already know that there are noncommutative modules/vectorspaces of
> interest (e.g., modules over quaternions and modules over graph paths), why
> not support them from the beginning? It seems like you're going out of your
> way to exclude things that would be trivial to include. This is exactly why
> this is my standard complaint against the various proposals out there for
> new numeric hierarchies. People who are used to only using R^n think the
> proposals are just fine, but none of the proposals capture the structures I
> work with daily. Which means the new proposals are no better than the
> Prelude for me.
I have to admit that I with R^n and therefore mostly care about this use
case. I think good set of type classes should be small enough (IMHO five or so).
It should not require to write unnecessary code in common cases. Probably this
is case when rule "one size doesn't fit all" applies.

More information about the Haskell-Cafe mailing list