nob*_*ody 4 constructor haskell types instance
所以这是一个嵌套列表[[1,2],[3,4]]
我想将它包装在一个名为Matrix的类型中,并使其成为Eq,Num和Show类的实例
我已经为嵌套列表(矩阵)创建了(add,sub,mul)操作.如何重载(+ - *)运算符以便+ map添加, - 映射到sub,以及*映射到mul?所以我可以做到这一点
> ma = Matrix [[1, 2], [3, 4]]
> mb = Matrix [[5, 6], [7, 8]]
> ma + mb
> ma - mb
> ma * mb
Run Code Online (Sandbox Code Playgroud)
谢谢
编辑
这是我到目前为止的尝试
> 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
这是我从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
编辑#2我现在需要弄清楚的最后一件事是
我该怎么打印
1 2 3 4
而不是矩阵[[1,2],[3,4]]
如果您检查您的类型add和sub,你会看到这个问题.
ghci> :t add
add :: Num a => [[a]] -> [[a]] -> [[a]]
ghci> :t sub
sub :: Num a => [[a]] -> [[a]] -> [[a]]
Run Code Online (Sandbox Code Playgroud)
Mikhail的建议是基本上解开2D列表并将其重新包装在Num实例方法中.另一种方法是修改你的add和sub方法来处理矩阵.在这里,我使用"提升"方法,在其中我编写组合器以将函数从一种类型"提升"到另一种类型.
-- 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)
Run Code Online (Sandbox Code Playgroud)
使用这些组合器,定义add并且sub仅仅是适当提升的问题.
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 (-)
Run Code Online (Sandbox Code Playgroud)
现在我们有了适用于矩阵的函数,Num实例很简单
instance (Num a) => Num (Matrix a) where
(+) = add
(-) = sub
..etc..
Run Code Online (Sandbox Code Playgroud)
当然,我们可以结合lift2dOp并liftMatrixOp进入一个便利功能:
-- 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..
Run Code Online (Sandbox Code Playgroud)
现在你尝试:define liftMatrix :: (a -> a) -> Matrix a -> Matrix a,一元函数的提升函数.现在用它来定义negate,abs和signum.文档建议abs x * signum x应该始终相当于x.看看我们的实施是否属实.
ghci> quickCheck (\xs -> let m = Matrix xs in abs m * signum m == m)
+++ OK, passed 100 tests.
Run Code Online (Sandbox Code Playgroud)
实际上,如果liftMatrix使用更宽松的类型签名进行编写,则可以使用它来定义Functor矩阵的实例.
liftMatrix :: (a -> b) -> Matrix a -> Matrix b
instance Functor (Matrix a) where
fmap = liftMatrix
Run Code Online (Sandbox Code Playgroud)
现在想想你如何实现fromInteger.实现这个允许你在ghci中做这样的事情:
ghci> Matrix [[1,2],[3,4]] + 1
Matrix [[2,3],[4,5]]
Run Code Online (Sandbox Code Playgroud)
无论如何,这就是我实现它的方式.请记住,nHaskell代码中的任何数字文字实际上都已转换为fromInteger n,这就是为什么这样做的原因.
我认为现在这很有趣,但如果你需要更多的练习,试着对这个Arbitrary矩阵实例感到满意:
instance Arbitrary a => Arbitrary (Matrix a) where
arbitrary = liftM Matrix arbitrary
Run Code Online (Sandbox Code Playgroud)
您是否在Num为类型定义实例时遇到问题?试试这段代码:
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
Run Code Online (Sandbox Code Playgroud)
测试:
*Main> Matrix [[1,2],[3,4]] + Matrix [[5,6],[7,8]]
Matrix [[6,8],[10,12]]
Run Code Online (Sandbox Code Playgroud)
其余类方法的定义留作练习.
这是一个Show实例Matrix:
import Data.List
instance Show a => Show (Matrix a)
where
show (Matrix a) = intercalate "\n" $ map (intercalate " " . map show) a
Run Code Online (Sandbox Code Playgroud)
测试:
*Main Data.List> Matrix [[1,2,3], [4,5,6]]
1 2 3
4 5 6
Run Code Online (Sandbox Code Playgroud)