Haskell中的矩阵构造函数和方法

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]]

Dan*_*ton 7

如果您检查您的类型addsub,你会看到这个问题.

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实例方法中.另一种方法是修改你的addsub方法来处理矩阵.在这里,我使用"提升"方法,在其中我编写组合器以将函数从一种类型"提升"到另一种类型.

-- 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)

当然,我们可以结合lift2dOpliftMatrixOp进入一个便利功能:

-- 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,abssignum.文档建议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)


Mik*_*kov 6

您是否在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)