I am trying to Learn Me a Haskell, and I decided to practice by writing a simple function for inverting 3x3 matrices. It should be easy, yet nothing I try will compile successfully.
Here is my code:
matInv3x3 :: [[Double]] -> [[Double]]
matInv3x3 m
| length m /= 3 = error "wrong number of rows"
| length (m !! 0) /= 3 = error "wrong number of elements in row 0"
| length (m !! 1) /= 3 = error "wrong number of elements in row 1"
| length (m !! 2) /= 3 = error "wrong number of elements in row 2"
| det == 0 = error "zero determinant"
| otherwise = mInv
where a = m !! 0 !! 0
b = m !! 0 !! 1
c = m !! 0 !! 2
d = m !! 1 !! 0
e = m !! 1 !! 1
f = m !! 1 !! 2
g = m !! 2 !! 0
h = m !! 2 !! 1
i = m !! 2 !! 2
det = a*(e*i - f*h) - b*(i*d - f*g) + c*(d*h - e*g)
A = (e*i - f*h) / det
B = -(d*i - f*g) / det
C = (d*h - e*g) / det
D = -(b*i - c*h) / det
E = (a*i - c*g) / det
F = -(a*h - b*g) / det
G = (b*f - c*e) / det
H = -(a*f - c*d) / det
I = (a*e - b*d) / det
mInv = [[A,B,C],[D,E,F],[G,H,I]]
I am trying to guard against everything which can go wrong: bad list dimensions, and zero determinant. I modeled it after examples in the 'Learn You A...' book. I am trying to rely on the lazy evaluation in case the matrix has zero determinant.
GHCi won't compile it, citing a parse error for the '=' on line 10 (where b is defined). I'm sure there is some simple, fundamental thing I am missing. Can someone point out what I did wrong?
UPDATE:
I implemented the fixes proposed in the comments, and also corrected the swapped indices mistake I made (didn't spot it before, as the code wouldn't compile). Here is the fixed code, which inverts 3x3 matrices correctly:
matInv3x3 :: [[Double]] -> [[Double]]
matInv3x3 m
| length m /= 3 = error "wrong number of rows"
| length (m !! 0) /= 3 = error "wrong number of elements in row 0"
| length (m !! 1) /= 3 = error "wrong number of elements in row 1"
| length (m !! 2) /= 3 = error "wrong number of elements in row 2"
| abs det < 1.0e-15 = error "zero or near-zero determinant"
| otherwise = mInv
where [[a,d,g],[b,e,h],[c,f,i]] = m
det = a*(e*i - f*h) - b*(i*d - f*g) + c*(d*h - e*g)
a' = (e*i - f*h) / det
b' = -(d*i - f*g) / det
c' = (d*h - e*g) / det
d' = -(b*i - c*h) / det
e' = (a*i - c*g) / det
f' = -(a*h - b*g) / det
g' = (b*f - c*e) / det
h' = -(a*f - c*d) / det
i' = (a*e - b*d) / det
mInv = [[a',b',c'],[d',e',f'],[g',h',i']]