Why is hmatrix Matrix not an instance of 'functor'?

To quote LYAH: “Functors are things that can be mapped over”.
So when I tried to fmap over a matrix, I was surprised to discover that Matrix is not an instance.

   m = (2><3)[3,5,4,6,5,7]
   x =  fmap (1+) m 
-- "No instance for (Functor Matrix) arising from a use of ‘fmap’"

Why ever not?

Because hmatrix is a container only for certains elements.

Makes sense since the package is about linear systems, hence Matrix String would carry little meaning.

2 Likes

Possibly Container/cmap will do what you want?

1 Like

Ahh I think I understand… The constructor Matrix in the definition is hidden (so we can’t pattern match :frowning_face:). Instead members of Matrix class are produced by functions like matrix, (><), fromColumns, etc. - functions whose type definitions restrict the type of matrix elements to Double (type alias R), Element or Storable type. If Matrix could be a member of Functor then fmap :: (a -> b) -> Matrix a -> Matrix b would need to apply for arbitrary a and b. But it would only make sense for the type signature fmap :: (Storable a, Storable b) => (a -> b) -> Matrix a -> Matrix b. Essentially this is what cmap does, but where Container takes the role of Functor, and cmap takes the role of fmap. (Aside - it seems to me that this limited fmap-like functionality - call it SemiFunctor - should be totally generic, whereas the Container implementation limits what can be ‘contained’ to Elements. Has this been done? Would it be a worthwhile addition to the Haskell ecosystem?)

I wonder - if Matrix is to be limited to Storable (or in practice, Element) types, why not embed this in the data declaration using GADTs?

data Matrix t where
    Matrix :: Storable t => Int -> Int -> Int -> Int -> (Vector t) -> Matrix t
                      --   irows  icols   xRow   xCol     xdat
2 Likes

I wonder - if Matrix is to be limited to Storable (or in practice, Element) types, why not embed this in the data declaration using GADTs?

Not library author but: I suspect because typeclasses are open to new instances — even instances created by library users —, while GADTs are not.

part of the answer is “Functors are things that can be mapped over” is not quite right!

An oversimplification maybe.

1 Like

A relevant discussion is here:

In particular this solution (Why Data.Set (containers) doesn't have Functor and Monad instance?) is, I believe, something that could be in base but … who knows

The problem with embedding with GADTs is you now have no way of guaranteeing to the compiler that two Matrix t share the same Storable dictionary. Also, you don’t get any benefit out of it – it just makes things more complicated. Try coding up some simple examples in that style and you’ll see the limitations soon enough for yourself!

1 Like

A functor is a function between functions ^___^

1 Like