Haskell Matrix Constructor and Method

So, here is the nested list [[1, 2], [3, 4]]

I want to wrap it in a Matrix type and make it an instance of the Eq, Num and Show classes

I have already created (add, sub, mul) operations for nested lists (matrices). How can I overload (+ - *) operators so that + maps add - maps to sub and * maps in mul? So i can do it

> ma = Matrix [[1, 2], [3, 4]] > mb = Matrix [[5, 6], [7, 8]] > ma + mb > ma - mb > ma * mb 

thanks

EDIT

This is my attempt so far

  > add = zipWith (zipWith (+))
 > sub = zipWith (zipWith (-))
 > data Matrix a = Matrix [[a]] deriving (Eq, Show)
 > instance Num (Matrix a)
 > where
 > (+) xy = Matrix $ add xy
 > (-) xy = Matrix $ sub xy

This is what I get from ghci

  Couldn't match expected type `[[c0]] 'with actual type` Matrix a'
     In the first argument of `sub ', namely` x'
     In the second argument of `($) ', namely` sub xy'
     In the expression: Matrix $ sub xy

EDIT No. 2 The last thing I need to find out now:

how to print

  12
 3 4

Instead of the matrix [[1,2], [3,4]]

+4
source share
2 answers

Are you having trouble defining a Num instance for your type? Try this code:

 data Matrix a = Matrix [[a]] deriving (Eq) plus_mat :: Num a => [[a]] -> [[a]] -> [[a]] plus_mat = zipWith (zipWith (+)) instance Num a => Num (Matrix a) where (Matrix a) + (Matrix b) = Matrix $ plus_mat ab (-) = undefined (*) = undefined negate = undefined abs = undefined signum = undefined fromInteger = undefined 

Testing:

 *Main> Matrix [[1,2],[3,4]] + Matrix [[5,6],[7,8]] Matrix [[6,8],[10,12]] 

The definitions of the rest of the class methods remain in the form of an exercise.

And here is the Show instance for Matrix :

 import Data.List instance Show a => Show (Matrix a) where show (Matrix a) = intercalate "\n" $ map (intercalate " " . map show) a 

Testing:

 *Main Data.List> Matrix [[1,2,3], [4,5,6]] 1 2 3 4 5 6 
+6
source

If you check the type of your add and sub , you will see a problem.

 ghci> :t add add :: Num a => [[a]] -> [[a]] -> [[a]] ghci> :t sub sub :: Num a => [[a]] -> [[a]] -> [[a]] 

Michael's suggestion was to essentially expand the 2D list and reinstall it in the Num instance methods. Another way to do this is to change the add and sub methods for working with matrices. Here I use the β€œrise” approach, where I write combinators to β€œraise” a function from one type to another.

 -- unwraps the 2d list from a matrix unMatrix :: Matrix a -> [[a]] unMatrix (Matrix m) = m -- lifts a 2d list operation to be a Matrix operation liftMatrixOp :: ([[a]] -> [[a]] -> [[a]]) -> Matrix a -> Matrix a -> Matrix a liftMatrixOp fxy = Matrix $ f (unMatrix x) (unMatrix y) -- lifts a regular operation to be a 2d list operation lift2dOp :: (a -> a -> a) -> [[a]] -> [[a]] -> [[a]] lift2dOp f = zipWith (zipWith f) 

With these combinators, defining add and sub is just a matter of sub it right.

 add, sub :: Num a => Matrix a -> Matrix a -> Matrix a add = liftMatrixOp add2D sub = liftMatrixOp sub2D add2D, sub2D :: Num a => [[a]] -> [[a]] -> [[a]] add2D = lift2dOp (+) sub2D = lift2dOp (-) 

Now that we have functions that work with matrices, the Num instance is simple

 instance (Num a) => Num (Matrix a) where (+) = add (-) = sub ..etc.. 

Of course, we could combine lift2dOp and liftMatrixOp in one convenient function:

 -- lifts a regular operation to be a Matrix operation liftMatrixOp' :: (a -> a -> a) -> Matrix a -> Matrix a -> Matrix a liftMatrixOp' = liftMatrixOp . lift2dOp instance (Num a) => Num (Matrix a) where (+) = liftMatrixOp' (+) (-) = liftMatrixOp' (-) (*) = liftMatrixOp' (*) ..etc.. 

Now try: define liftMatrix :: (a -> a) -> Matrix a -> Matrix a , the lift function for unary functions. Now use this to define negate , abs and signum . The docs assume that abs x * signum x should always be equivalent to x . See if this is true for our implementation.

 ghci> quickCheck (\xs -> let m = Matrix xs in abs m * signum m == m) +++ OK, passed 100 tests. 

In fact, if you write liftMatrix with a softer type signature, you can use it to define an instance of Functor for matrices.

 liftMatrix :: (a -> b) -> Matrix a -> Matrix b instance Functor (Matrix a) where fmap = liftMatrix 

Now think about how you can implement fromInteger . Implementing this allows you to do such things in ghci:

 ghci> Matrix [[1,2],[3,4]] + 1 Matrix [[2,3],[4,5]] 

The way it works the way I implemented it, anyway. Remember that any number literal n in Haskell code is actually converted to fromInteger n , so this works.

I think this time is enough fun, but if you need more exercise, try participating in this Arbitrary instance of Matrices:

 instance Arbitrary a => Arbitrary (Matrix a) where arbitrary = liftM Matrix arbitrary 
+7
source

All Articles