-2

I'm new in Haskell.
I can't figure out why we use a monoid and instance Functor Matrix in the code bellow and how instance Functor Matrix works?

instance Functor Matrix where
    fmap f (M n m v) = M n m $ fmap (fmap f) v

instance Num a => Num (Matrix a) where
    fromInteger = M 1 1 . V.singleton . V.singleton . fromInteger
    negate = fmap negate
    (+) = add
    (*) = mult
    abs = fmap abs
    signum = fmap signum

scalarMult :: Num a => a -> Matrix a -> Matrix a
    scalarMult = fmap . (*)

I know that the functor is necessary for negate, (*), abs, signum, but I need a detailed explanation. Help me, please.

dmitryvodop
  • 167
  • 2
  • 2
  • 6
  • Please show the definition of `Matrix`. I can guess roughly how it looks, but having all the details right is useful for giving better examples. –  May 28 '14 at 14:07
  • There is no monoid in that code. Clarify what you mean. Also, please include the data/type declaration for what you use as `Matrix` (or link to the library you've taken them from). – leftaroundabout May 28 '14 at 14:07
  • `import Data.Monoid import Prelude` – dmitryvodop May 28 '14 at 14:09
  • 1
    @dmitryvodop There is no `Matrix` type defined in either `Data.Monoid` or `Prelude` (which is unnecessary to import on its own, it gets imported automatically). Where is `Matrix` defined? – bheklilr May 28 '14 at 14:10
  • @leftaroundabout I examine this code: http://hackage.haskell.org/package/matrix-0.2.1/docs/src/Data-Matrix.html – dmitryvodop May 28 '14 at 14:14
  • @bheklilr Here is the full code: http://hackage.haskell.org/package/matrix-0.2.1/docs/src/Data-Matrix.html – dmitryvodop May 28 '14 at 14:16

1 Answers1

3

Functors are a very simple thing that have a complicated name. Simply put, Functors are containers that you can map a function over its values, via the fmap function. Lists are the most familiar Functor, since fmap is just map. Other Functors include Maybe, IO, and Either a.

In this snippet you're defining Matrix to be a Functor, so you're telling the compiler that Matrix is a container that it can map functions over. For the purposes of this question, fmap is used to define several of the functions in the Num typeclass. It is pretty easy to see how this works (assuming there is a fromList :: [[a]] -> Matrix a function):

> fmap id $ fromList [[1, 2], [3, 4]]
fromList [[1, 2], [3, 4]]
> fmap (+1) $ fromList [[1, 2], [3, 4]]
fromList [[2, 3], [4, 5]]
> fmap show $ fromList [[1, 2], [3, 4]]
fromList [["1", "2"], ["3", "4"]]

For other Functors:

> fmap (+1) [1, 2, 3]
[2, 3, 4]
> fmap (*10) (Just 1)
Just 10
> fmap (*10) Nothing
Nothing

As for why Data.Monoid is imported in the source for Data.Matrix, it is solely because of the function

-- | Display a matrix as a 'String' using the 'Show' instance of its elements.
prettyMatrix :: Show a => Matrix a -> String
prettyMatrix m@(M _ _ v) = unlines
 [ "( " <> unwords (fmap (\j -> fill mx $ show $ m ! (i,j)) [1..ncols m]) <> " )" | i <- [1..nrows m] ]
 where
  mx = V.maximum $ fmap (V.maximum . fmap (length . show)) v
  fill k str = replicate (k - length str) ' ' ++ str

Where the author has opted to use <> instead of ++ for concatenating strings together, a rather mundane use of the list Monoid. It has no relevance at all to the Matrix type.

bheklilr
  • 53,530
  • 6
  • 107
  • 163
  • Thank you, the great explanation, now all is clear! By the way, instead of `<>` we could write `++` and it would be the same meaning? – dmitryvodop May 28 '14 at 14:54
  • @dmitryvodop If you look at the source of [`Data.Monoid`](http://haddocks.fpcomplete.com/fp/7.4.2/20130829-168/base/src/Data-Monoid.html), you'll see that `(<>) = mappend`, and for `instance Monoid [a]`, `mappend = (++)` and `mempty = []`. With optimizations enabled the compiler should be capable of inlining it entirely down to `++`, since `<>` is inlined and simple typeclasses are trivial to inline. So quite literally, `(<>) === mappend === (++)`. – bheklilr May 28 '14 at 14:59