Haskell: Understanding algebraic data types better - haskell

I'm trying to construct an algebraic data type that represents polynomials. Given the definition that an Integer constant is a polynomial and that if you add two polynomials or multiply two polynomials, it results in a polynomial.
I'm having a difficult time understanding how algebraic data types work in general and how I would even go about producing this. I currently have
data Poly = Const Int |
Add Poly Poly |
Mult Poly Poly
However I don't know what this even means or how to use it, I'm simply going off of examples I've seen of algebraic data types.
I've seen types like
data Tree = NullT |
Node Int Tree Tree
That makes more sense to me, and how to use it. The polynomial example seems so abstract I don't know where to start.
Edit: When I try to implement simple testing functions like:
evalPoly :: Poly -> Int
evalPoly (Const n) = n
I'm met with the error
*Polynomial> evalPoly Poly 1
<interactive>:25:10: Not in scope: data constructor ‘Poly’
*Polynomial>
Edit again: Thank you for all your suggestions and help, it's helped me produce something that's working for my purposes!

You seem to want to make an ADT for polynomials, but I'd prefer to use a Map. First some imports:
import qualified Data.Map as M
import Data.Function (on)
A polynomial is a Map from powers of x to coefficients.
newtype Poly a n = Poly {coeffMap :: M.Map n a} deriving (Show)
lift f = Poly . f . coeffMap
Let's make some simple polynomials:
zero = Poly M.empty -- none of the powers have non-zero coefficients
x = Poly $ M.singleton 1 1 -- x^1 has coefficient 1
constant 0 = zero
constant a = Poly $ M.singleton 0 a -- x^0 has coefficient a
A standard thing to do with a polynomial is evaluate it with a particular value for x.
The fold here takes the partially-calculated b and adds on the new term, a*x^n:
evalAt :: (Num a, Integral n) => a -> Poly a n -> a
evalAt x = M.foldrWithKey (\n a b -> b + a*x^n) 0 . coeffMap
If we want to use a Map function, we can lift it from Map n a to Poly n a.
I'd like to be able to map on the coefficients, but I don't want to make this an instance of Functor because it's a classic student error to apply operations like squaring, applying trigonometrical or logarithmic functions or taking square roots term by term, when in fact only a tiny few things like scalar multiplication, differentiation and integration work like this. Providing fmap encourages you to do wong things like fmap (+1) instead of (+ (constant 1)).
mapCoeffs :: (a -> b) -> Poly a n -> Poly b n
mapCoeffs f = lift (fmap f)
Maps already collect like terms automatically, but we'll want to omit terms with zero coefficients:
strikeZeros :: (Num a,Eq a) => Poly a n -> Poly a n
strikeZeros = lift $ M.filter (/= 0)
Now we can make the instances:
instance (Eq a,Num a,Ord n,Num n) => Eq (Poly a n) where
f == g = f - g == zero
instance (Eq a,Num a,Num n,Ord n) => Num (Poly a n) where
fromInteger = constant . fromInteger
signum (Poly m) | M.null m = zero
| otherwise = let (n,a) = M.findMax m in
Poly $ M.singleton n (signum a)
abs = mapCoeffs abs
negate = mapCoeffs negate
(+) = (strikeZeros.) . (Poly.) . ((M.unionWith (+)) `on` coeffMap)
(Poly m) * (Poly m') = Poly $
M.fromListWith (+) [(n+n',a*a') | (n,a)<-M.assocs m, (n',a')<-M.assocs m']
In action:
ghci> 3*x^4 + 6 + 2*x^7
Poly {coeffMap = fromList [(0,6),(4,3),(7,2)]}

Here's an alternative solution to the other one I posted.
You seem to want to make an ADT for polynomials, where I'd use a Map, but let's go with a list of terms. First some imports:
import Data.Function (on)
import Data.List (sortBy, groupBy, foldl1')
This way a polynomial is a list of terms, sorted with the highest power first, and a term is aX^n, represented by X a n
newtype Poly a n = Poly {terms :: [Term a n]} deriving (Show)
data Term a n = X {coeff :: a, power :: n} deriving (Eq,Show)
Let's make some simple polynomials:
zero = Poly []
x = Poly [X 1 1]
constant :: (Num a,Eq a,Num n) => a -> Poly a n
constant 0 = zero
constant a = Poly [X a 0]
Once we've defined the Num instance, we'll be able to make X 3 4 by writing 3*x^4.
A standard thing to do with a polynomial is evaluate it with a particular value for x.
subst :: (Num a, Integral n) => a -> Term a n -> a
subst x (X a n) = a * x ^ n
evalAt :: (Num a, Integral n) => a -> Poly a n -> a
evalAt x = sum . map (subst x) . terms
I'd like to be able to map on the coefficients, but I don't want to make this an instance of Functor because it's a classic student error to apply operations like squaring, applying trigonometrical or logarithmic functions or taking square roots term by term, when in fact only a tiny few things like scalar multiplication, differentiation and integration work like this. Providing fmap encourages you to do wong things like fmap (+1) instead of (+ (constant 1)).
mapCoeffs :: (a -> b) -> Poly a n -> Poly b n
mapCoeffs f = Poly . map f' . terms
where f' (X a n) = X (f a) n
We'll need to add and multiply terms, and collect like terms. When we collect like terms, we sort in reverse order of power and omit terms with zero coefficients.
addTerm (X a n) (X b m) | n == m = X (a+b) n
| otherwise = error "addTerm: mismatched powers"
multTerm (X a n) (X b m) = X (a*b) (n+m)
collectLikeTerms :: (Num a, Ord n, Eq a) => Poly a n -> Poly a n
collectLikeTerms = Poly . filter ((/= 0).coeff) -- no zero coeffs
. map (foldl1' addTerm) -- add the like powers
. groupBy ((==) `on` power) -- group the like powers
. sortBy (flip compare `on` power) -- sort in reverse powers
. terms
Now we can make the instances:
instance (Eq a,Num a,Ord n,Num n) => Eq (Poly a n) where
f == g = f - g == zero
instance (Eq a,Num a,Num n,Ord n) => Num (Poly a n) where
fromInteger = constant . fromInteger
signum (Poly []) = zero
signum (Poly (t:_)) = constant . signum . coeff $ t
abs = mapCoeffs abs
negate = mapCoeffs negate
(+) = (collectLikeTerms.) . (Poly.) . ((++) `on` terms)
(Poly ts) * (Poly ts') = collectLikeTerms $ Poly [multTerm t t' | t<-ts, t'<-ts']
In action:
ghci> 5*x^2 + 6*x^7 + 2
Poly {terms = [X {coeff = 6, power = 7},X {coeff = 5, power = 2},X {coeff = 2, power = 0}]}

Related

Lagrange Interpolation for a schema based on Shamir's Secret Sharing

I'm trying to debug an issue with an implementation of a threshold encryption scheme. I've posted this question on crypto to get some help with the actual scheme but was hoping to get a sanity check on the simplified code I am using.
Essentially the the crypto system uses Shamir's Secret Sharing to combine the shares of a key. The polynomial is each member of the list 'a' multiplied by a increasing power of the parameter of the polynomial. I've left out the mod by prime to simplify the code as the actual implementation uses PBC via a Haskell wrapper.
I have for the polynomial
poly :: [Integer] -> Integer -> Integer
poly as xi = (f 1 as)
where
f _ [] = 0
f 0 _ = 0
f s (a:as) = (a * s) + f (s * xi) as
The Lagrange interpolation is:
interp0 :: [(Integer, Integer)] -> Integer
interp0 xys = round (sum $ zipWith (*) ys $ fmap (f xs) xs)
where
xs = map (fromIntegral .fst) xys
ys = map (fromIntegral .snd) xys
f :: (Eq a, Fractional a) => [a] -> a -> a
f xs xj = product $ map (p xj) xs
p :: (Eq a, Fractional a) => a -> a -> a
p xj xm = if xj == xm then 1 else negate (xm / (xj - xm))
and the split and combination code is
execPoly as#(a0:_) = do
let xs = zipWith (,) [0..] (fmap (poly as) [0..100])
let t = length as + 1
let offset = 1
let shares = take t (drop offset xs)
let sm2 = interp0 shares
putText ("poly and interp over " <> show as <> " = " <> show sm2 <> ". Should be " <> show a0)
main :: IO ()
main = do
execPoly [10,20,30,40,50,60,70,80,90,100,110,120,130,140,150] --1
execPoly [10,20,30,40,50,60,70,80] -- 2
execPoly(1) fails to combine to 10 but execPoly(2) combines correctly. The magic threshold seems to be 8.
Is my code correct? I am missing something in the implementation that limits the threshold size to 8?
As MathematicalOrchid said it was a precision problem.
Updated the code to:
f :: (Eq a, Integral a) => [a] -> a -> Ratio a
f xs xj = product $ map (p xj) xs
p :: (Eq a, Integral a)=> a -> a -> Ratio a
p xj xm = if xj == xm then (1 % 1) else (negate xm) % (xj - xm)
And it works as expected.

Undefined error on defined function

I'm trying to implement a function that multiplies polynomials (represented using lists -- 3x^2 + 5x + 2 = P [2,5,3]):
newtype Poly a = P [a]
plus :: Num a => Poly a -> Poly a -> Poly a
plus (P a) (P b) = P (map (\(y,z) -> z + y) (zipWithPadding 0 a b))
where
zipWithPadding :: (Num a) => a -> [a] -> [a] -> [(a, a)]
zipWithPadding e (aa: as) (bb: bs) = ((aa, bb): zipWithPadding e as bs)
zipWithPadding e [] bs = zip (repeat e) bs
zipWithPadding e as [] = zip as (repeat e)
times :: Num a => Poly a -> Poly a -> Poly a
times (P a) (P b) = sum $ multList 0 [] a b
where
multList :: Num a => Int -> [Poly a] -> [a] -> [a] -> [Poly a]
multList _ s [] _ = s
multList e s (aa:as) bs = multList (e + 1) (s ++ (multElement e aa bs)) as bs
multElement :: Num a => Int -> a -> [a] -> [Poly a]
multElement e aa bs = [P $ replicate e 0 ++ (map (*aa) bs)]
instance Num a => Num (Poly a) where
(+) = plus
(*) = times
negate = undefined
fromInteger = undefined
-- No meaningful definitions exist
abs = undefined
signum = undefined
When I tried to run however, I got an undefined error:
*HW04> times (P [1,2,2]) (P [1,2])
*** Exception: Prelude.undefined
I'm confused.
Clearly you are calling one of the undefined methods in the Num instance for Poly.
You can determine which one is being called by using these definitions:
negate = error "Poly negate undefined"
fromInteger = error "Poly fromInteger undefined"
abs = error "Poly abs undefined"
signum = error "Poly signum undefined"
Running your test expression yields:
Poly *** Exception: Poly fromInteger undefined
The problem is in your use of sum which is essentially defined as:
sum xs = foldl (+) 0 xs
It is therefore calling fromInteger 0. You can fix this with:
fromInteger x = P [ fromInteger x ]
Update
The reason fromInteger for Poly a needs to be defined this way is
because we need to construct a list of Num a values, and fromInteger x
is the way to create a Num a from the Integer value x.
A polynomial is not really a Num, although there is a ring monomorphism Num a => a -> Poly a.
Discard that Num instance and use foldl plus instead of sum.
I'm going to take the position that you should not define an instance of a class simply to hijack the class's functions. The minimal definition of a Num instance expects certain functions to be defined; explicitly assigning undefined to those names does not qualify as a definition. Consider that Haskell provides a specific operator (++) for list concatenation instead of simply overloading (+) with an instance like
instance Num [a] where
a + [] = a
[] + b = b
(a:as) + b = a:(as + b)
(*) = undefined
negate = undefined
-- etc
Instead, define a class that does provide the operations you want. In this case, you want a Ring, which is a type along with two operations, addition and multipication, that obey certain laws. (Put briefly, the operations act as you would expect given the integers as an example, except multiplication is not required to be commutative.)
In Haskell, we would define the class as
class Ring a where
rplus :: a -> a -> a -- addition
rmult :: a -> a -> a -- multiplication
rnegate :: a -> a -- negation
runit :: a -- multiplicative identity
rzero :: a -- additive identity, multiplicative zero
Any value with a valid Num instance forms a ring, although you need to define the instances separately.
instance Ring Integer where
rplus = (+)
rmult = (*)
rnegate = negate
rzero = 0
runit = 1
instance Ring Float
rplus = (+)
rmult = (*)
rnegate = negate
rzero = 0
runit = 1
-- etc
You can define an instance of Ring for polynomials, as long as the coefficients form a ring as well.
newtype Poly a = P [a]
instance Ring a => Ring (Poly a) where
-- Take care to handle polynomials with different degree
-- Note the use of rplus and rzero instead of (+) and 0
-- when dealing with coefficients
rplus (P a) (P b) = case (compare (length a) (length b)) of
LT -> rplus (P (rzero:a)) (P b)
EQ -> P $ zipWith rplus a b
GT -> rplus (P a) (P (rzero:b))
-- I leave a correct implementation of rmult as an exercise
-- for the reader.
rmult = ...
rnegate (P coeffs) = P $ map rnegate coeffs
rzero = P [0]
runit = P [1]

How is Ratio implemented in Haskell?

This is something I have been confused about for a while and I am not sure how I can learn more about it. Let's say I have the following program:
main :: IO ()
main = do
x <- liftM read getLine
y <- liftM read getLine
print (x % y)
If I run this with the input 6 and 2, it will print 3 % 1.
At what point does the simplification happen (namely the division by the gcd)? Is it implemented in show? If so, then is the underlying representation of the rational still 6 % 2? If not, then does (%) do the simplification? I was under the impression that (%) is a data constructor, so how would a data constructor do anything more than "construct"? More importantly, how would I actually go about doing similar things with my own data constructors?
I appreciate any help on the topic.
Ratio is actually implemented in GHC.Real (on GHC, obviously), and is defined as
data Ratio a = !a :% !a deriving (Eq)
The bangs are just there for strictness. As you can see, the function % is not a data constructor, but :% is. Since you aren't supposed to construct a Ratio directly, you use the % function, which calls reduce.
reduce :: (Integral a) => a -> a -> Ratio a
{-# SPECIALISE reduce :: Integer -> Integer -> Rational #-}
reduce _ 0 = ratioZeroDenominatorError
reduce x y = (x `quot` d) :% (y `quot` d)
where d = gcd x y
(%) :: (Integral a) => a -> a -> Ratio a
x % y = reduce (x * signum y) (abs y)
The rule is that if an operator starts with a colon :, then it is a constructor, otherwise it is just a normal operator. In fact, this is part of the Haskell standard, all type operators must have a colon as their first character.
You can just look at the source to see for yourself:
instance (Integral a) => Num (Ratio a) where
(x:%y) + (x':%y') = reduce (x*y' + x'*y) (y*y')
(x:%y) - (x':%y') = reduce (x*y' - x'*y) (y*y')
(x:%y) * (x':%y') = reduce (x * x') (y * y')
negate (x:%y) = (-x) :% y
abs (x:%y) = abs x :% y
signum (x:%_) = signum x :% 1
fromInteger x = fromInteger x :% 1
reduce :: (Integral a) => a -> a -> Ratio a
reduce _ 0 = ratioZeroDenominatorError
reduce x y = (x `quot` d) :% (y `quot` d)
where d = gcd x y

Scalar multiplication with a new Matrix type in Haskell

I've been programming in C-type and Lisp-type languages for a few decades and Haskell for a few years. Now in order to further my understanding of typeclasses and other nifty more advanced features of Haskell, such as parallelism, I've been trying to create a new data type with matrix semantics, for now piggy-backed on top of the library's Array type.
I am using the latest Haskell Platform 2013.2.0.0 with the included ghc.
newtype Matrix a = Matrix (Array (Int,Int) a)
(I understand that data would work instead of newtype, but that in this instance, you get the same semantics with better performance using newtype instead).
Some simple functions to create an identity matrix, for example, work just fine:
unityMatrix:: (Num a) => Int -> Matrix a
unityMatrix d = Matrix $ let b = ((0,0),(d-1,d-1)) in array b
[((i,j),if i==j then 1 else 0)|(i,j)<-range b]
So does creating a basic show function:
instance Show a => Show (Matrix a) where
show (Matrix x) =
let
b = bounds x
rb = ((fst.fst) b, (fst.snd) b)
cb = ((snd.fst) b, (snd.snd) b)
in
intercalate "\n" [unwords ([show (x!(r,c))|c<-range cb])|r<-range rb]
Then, for the regular arithmetic operators to work, I add this:
instance Num a => Num (Matrix a) where
fromInteger x =
let
b = ((0,0),(0,0))
in Matrix $ array b
[((i,j),if i == j then (fromInteger x) else 0)|(i,j)<-range b]
(Matrix x) + (Matrix y) =
let
b = bounds x
in
if b /= bounds y then error "Unmatched matrix addition" else Matrix $ array b
[(ij,x!ij + y!ij)|ij<-range b]
signum (Matrix x) =
let
b = bounds x
in Matrix $ array b
[(ij,signum (x!ij))|ij<-range b]
abs (Matrix x) =
let
b = bounds x
in Matrix $ array b
[(ij,abs (x!ij))|ij<-range b]
(Matrix x) - (Matrix y) =
let
b = bounds x
in
if b /= bounds y then error "Unmatched matrix subtraction" else Matrix $ array b
[(ij,x!ij - y!ij)|ij<-range b]
(Matrix x) * (Matrix y) =
let
b = (((fst.fst.bounds) x, (fst.snd.bounds) x),((snd.fst.bounds) y, (snd.snd.bounds) y))
kb = ((snd.fst.bounds) x, (snd.snd.bounds) x)
in
if kb /= ((fst.fst.bounds) y, (fst.snd.bounds) y) then error "Unmatched matrix multiplication" else Matrix $ array b
[((i,j),sum [(x!(i,k)) * (y!(k,j))|k<-range kb])|(i,j)<-range b]
(My apologies if the indentation is screwed up here--the actual code is properly indented and compiles.)
So far, so good, though it is a little annoying to have to define a fromInteger function which does not really have any meaning in matrix semantics, but creating a 1x1 matrix with the value is as reasonable as anything else.
My problem is trying to get proper semantics for multiplication of a scalar (i.e., a type of the Num typeclass) with a matrix. By mathematical convention that means just element-wise multiplication with the scalar.
However, no matter what syntax I try, I don't get the right result. By default this implementation just promotes, e.g., an Int to a Matrix using fromInteger which (unless the Matrix is already 1x1) results in a "Unmatched matrix multiplication" error. I have tried all alternative syntaxes I can think of to define a alternate code for this type of multiplication without success, such as:
(Matrix x) * (y::Int) =
or
(Matrix x) * (Num y) =
or
(*):: (Num a) => Matrix -> a -> Matrix
But all of these give me various syntax errors.
How should I go about defining the scalar by matrix multiplication so that it does what you would expect it to do? I feel that enabling the non-standard pattern guard feature might help, but I'm not quite sure how to use that correctly in this context.
I realize that I could just special case the Matrix multiplication to allow multiplication of any Matrix with a 1x1 Matrix which I guess would work. But that would be (a) inelegant, (b) un-Haskell-y, (c) probably inefficient as it would require every scalar to be wrapped into a matrix before being multiplied, and (d) would permit some code (such as multiplication of an arbitrary matrix with any 1x1 matrix) to run when it should result in a n error.
I also understand that there are probably excellent Matrix implementations out there which somehow sidestep this problem. But using them would defeat my purpose to learn.
This is the type of the standard (*) operator:
(*) :: Num a => a -> a -> a
In other words, the two arguments to this operator have to be the same type, so what you are asking for is not possible as it stands.
I can see a couple of options:
As suggested in the comments, define your own (*), perhaps with a type class to go with it that standard types like Integer can also be a member of. This answer might provide some inspiration.
Add scalars to your matrix type:
data Matrix a = Scalar a | Matrix (Array (Int,Int) a)
(perhaps the name could now be improved - also note that now it has to be data rather than newtype. I doubt the performance difference will matter in practice.)
Just an attemp to extend Ganesh's answer.
We could redefine Scalar matrix as Unity matrix of unindentidied size.
import Data.List (transpose)
data Matrix a = Matrix [[a]] | UnityMatrix a deriving (Show)
instance Functor Matrix where
fmap f (Matrix x) = Matrix $ fmap (fmap f) x
fmap f (UnityMatrix x) = UnityMatrix $ f x
fmap2::(Num a) => (a->a->b)->Matrix a->Matrix a->Matrix b
fmap2 f (Matrix x) (Matrix y) = Matrix $ zipWith ( zipWith f ) x y
fmap2 f m#(Matrix x) u#(UnityMatrix y) = fmap2 f m $ expandUnity u
fmap2 f u#(UnityMatrix y) m#(Matrix x) = fmap2 f (expandUnity u) m
fmap2 f (UnityMatrix x) (UnityMatrix y) = UnityMatrix $ f x y
expandUnity (UnityMatrix a) = Matrix [replicate i 0 ++ a : repeat 0| i <-[0..]]
instance Num a => Num (Matrix a) where
fromInteger = UnityMatrix . fromInteger
signum = fmap signum
abs = fmap abs
(+) = fmap2 (+)
(-) = fmap2 (-)
(Matrix x) * (Matrix y) = Matrix [[sum $ zipWith (*) a b | b <- transpose y ]| a <- x ]
m#(Matrix x) * (UnityMatrix y) = fmap (*y) m
(UnityMatrix y) * m#(Matrix x) = fmap (y*) m
(UnityMatrix x) * (UnityMatrix y) = UnityMatrix $ x * y
main = print $ 3 * Matrix [[1,2,3],[4,5,6]] + 2
This code contains lot of repeating - but this in case if any of (+) , (-) or (*) operators in base type is not commutative.
Also underlying type changed to list of lists instead of matrix. But this is only to ease of idea demo.
The "semantics you're looking for" are just inconsistent with how the Haskell Num class is defined. There is no such thing as data promotion in Haskell (for very good reasons that are hard to explain but easy found out the more experience you gain with Haskell).
I'd not recommend defining a new *, nor your own operator name that has the signature a -> Matrix a -> Matrix a, it would be confusing. Rather, you should look where this operation is already defined: as user5402 has it, this is a scalar multiplication. This is obviously not just meaningful for matrices / linear operators, but already to vectors. And behold, here is the class for vector spaces!
But like suggested by Ganesh and Odomontois for Num, you'll also need to expand you data type to make proper use of this. The basic problem is that matrix multiplication is really only defined for matching covariant-contravariant dimensions, but your approach has no way to ensure this. Ideally, the type checker should infer the correct dimension, but instead of that you can have a special case, not just for the identity but general diagonal matrices.
data LinOp a = Diagonal a
| GMatrix (Matrix a)
instance Functor LinOp where
fmap f (Diagonal a) = Diagonal (f a)
fmap f (GMatrix m) = GMatrix $ fmap f m
instance (Num a) => AdditiveGroup (Matrix a) where
zeroV = Diagonal 0
negateV = fmap negate
(Diagonal x) ^+^ (Diagonal y) = Diagonal $ x+y
...
instance (Num a) => VectorSpace (Matrix a) where
type Scalar (Matrix a) = a
μ *^ m = fmap (μ*) m
instance (Num a) => Num (Matrix a) where
fromInteger = Diagonal . fromInteger
(+) = (^+^)
...
Does this work?
scalarMult :: Num a => a -> Matrix a -> Matrix a
scalarMult c (Matrix x) = Matrix $ array (range x) [(ij,(x!ij) * c) | ij <- range x]
In general you can't implement scalar multiplication with fromInteger and ordinary matrix multiplication because you don't know what size matrix to create - it will depend on its context.
However, you could possibly use this approach if you kept track of the matrix size in the type system. Then the compiler could infer what size to promote scalars to, and it also could detect dimension mismatches for matrix operations at compile time.

Matrix constructor and method in Haskell

So here is a nested list [[1, 2], [3, 4]]
I want to wrap it in a type called Matrix, and make it an instance of the classes Eq, Num, and Show
I have already created (add, sub, mul) operations for nested lists (matrices). How do I overload (+ - *) operators so that + maps to add, - maps to sub, and * maps to mul? So I can do this
> 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
> (+) x y = Matrix $ add x y
> (-) x y = Matrix $ sub x y
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 x y'
In the expression: Matrix $ sub x y
EDIT #2
The last thing I need to figure out right now is
how to I print
1 2
3 4
Instead of Matrix [[1,2],[3,4]]
Are you having a problem with 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 a b
(-) = 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]]
Definitions of the remaining class methods are left as exercise.
And here's a 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
If you inspect the type of your add and sub, you will see the issue.
ghci> :t add
add :: Num a => [[a]] -> [[a]] -> [[a]]
ghci> :t sub
sub :: Num a => [[a]] -> [[a]] -> [[a]]
Mikhail's suggestion was to essentially unwrap the 2D list and rewrap it in the Num instance methods. Another way to do this is to modify your add and sub methods to work on Matrices instead. Here I use a "lifting" approach, where I write combinators to "lift" 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 f x y = 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 simply a matter of lifting appropriately.
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 on Matrices, the Num instance is simple
instance (Num a) => Num (Matrix a) where
(+) = add
(-) = sub
..etc..
Of course we could have combined lift2dOp and liftMatrixOp into one convenience 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 you try: define liftMatrix :: (a -> a) -> Matrix a -> Matrix a, a lifting function for unary functions. Now use that to define negate, abs, and signum. The docs suggest 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 the more lenient type signature, it can be used to define a Functor instance for Matrices.
liftMatrix :: (a -> b) -> Matrix a -> Matrix b
instance Functor (Matrix a) where
fmap = liftMatrix
Now think about how you could implement fromInteger. Implementing this allows you to do stuff like this in ghci:
ghci> Matrix [[1,2],[3,4]] + 1
Matrix [[2,3],[4,5]]
That's how it works the way I implemented it, anyways. Remember that any numeric literal n in Haskell code is actually transformed into fromInteger n, which is why this works.
I think that's enough fun for now, but if you need more exercises, try getting comfortable with this Arbitrary instance of Matrices:
instance Arbitrary a => Arbitrary (Matrix a) where
arbitrary = liftM Matrix arbitrary

Resources