我刚开始学习Haskell 我有一个问题。我试着写一个函数来找到逆矩阵 我的矩阵类型如下:
data Matrix a = M
{ nrows :: !Int
, ncols :: !Int
, mvect :: V.Vector (V.Vector a)
} deriving Eq
我也有fromLists
功能
查找行列式的函数如下:
det :: Num a => Matrix a -> a
det (M 1 1 v) = V.head (V.head v)
det m =
sum [ (-1)^(i-1) * m ! (i,1) * det (minorMatrix i 1 m) | i <- [1 .. nrows m] ]
所以,我的代码是找到逆矩阵:
coords :: Matrix a -> [[(Int, Int)]]
coords = zipWith (map . (,)) [0..] . map (zipWith const [0..])
delmatrix :: Int -> Int -> Matrix a -> Matrix a
delmatrix i j = dellist i . map (dellist j)
where dellist i xs = take i xs ++ drop (i + 1) xs
mapMatrix :: (a -> a) -> Matrix a -> Matrix a
mapMatrix f = map (map f)
cofactor :: Num a => Int -> Int -> Matrix a -> a
cofactor i j m = ((-1) ** fromIntegral (i + j)) * det (delmatrix i j m)
cofactorM :: Matrix a -> Matrix a
cofactorM m = map (map (\(i,j) -> cofactor j i m)) $ coords m
inverse :: (Num a, Fractional a) => Matrix a -> Matrix a
inverse m = mapMatrix (* recip deter) $ cofactorM m
where deter = det m
我在控制台上有什么:
Prelude> :r
[1 of 1] Compiling Matrixlab ( Matrixlab.hs, interpreted )
Matrixlab.hs:120:38:
Couldn't match expected type `Matrix a' with actual type `[a0]'
Expected type: Matrix a -> [[Int]]
Actual type: [a0] -> [b0]
In the return type of a call of `map'
In the second argument of `(.)', namely
`map (zipWith const [0 .. ])'
Matrixlab.hs:123:17:
Couldn't match expected type `Matrix a' with actual type `[a0]'
Expected type: [a0] -> Matrix a
Actual type: [a0] -> [a0]
In the return type of a call of `dellist'
In the first argument of `(.)', namely `dellist i'
Matrixlab.hs:127:15:
Couldn't match expected type `Matrix a' with actual type `[a0]'
Expected type: Matrix a -> Matrix a
Actual type: [a0] -> [b0]
In the return type of a call of `map'
In the expression: map (map f)
Matrixlab.hs:130:24:
Could not deduce (Floating a) arising from a use of `**'
from the context (Num a)
bound by the type signature for
cofactor :: Num a => Int -> Int -> Matrix a -> a
at Matrixlab.hs:130:1-71
Possible fix:
add (Floating a) to the context of
the type signature for
cofactor :: Num a => Int -> Int -> Matrix a -> a
In the first argument of `(*)', namely
`((- 1) ** fromIntegral (i + j))'
In the expression:
((- 1) ** fromIntegral (i + j)) * det (delmatrix i j m)
In an equation for `cofactor':
cofactor i j m
= ((- 1) ** fromIntegral (i + j)) * det (delmatrix i j m)
Matrixlab.hs:133:15:
Couldn't match expected type `Matrix a' with actual type `[[a]]'
In the expression:
map (map (\ (i, j) -> cofactor j i m)) $ coords m
In an equation for `cofactorM':
cofactorM m = map (map (\ (i, j) -> cofactor j i m)) $ coords m
Failed, modules loaded: none.
请帮帮我。
答案 0 :(得分:3)
首先,如果你想使用矢量,你应该使用矢量。如果你要将它们一直转换回列表,你应该坚持使用列表。 vector包提供了Vector
类型列表中的所有功能。所以你应该使用那些。事实上,使用Vector
函数几乎总是更容易,因为它们为您提供了对项目索引的内置访问。 If you don't know what functions you have available, take a look at the docs.
您也不能假装您的Matrix
等同于列表列表,并期望编译器知道您在说什么。你必须使用模式匹配从Matrix
构造函数中取出向量,对它们进行操作,然后将它们放回去。例如:
import qualified Data.Vector as V
cofactorM :: Floating a => Matrix a -> Matrix a
cofactorM m@(M x y v) = M x y $ (V.imap $ \i -> V.imap $ \j -> const (cofactor i j m)) v
cofactor :: Floating a => Int -> Int -> Matrix a -> a
cofactor ...
请注意,Vector
为零索引,而您的det
函数意味着您的列和行是一个索引。你将不得不弥补这一点。
最后,没有充分的理由用Vector (Vector a)
打包行数和列数,因为获取向量的长度无论如何都是一个恒定的时间操作。