我是Haskell新手。
我不明白为什么我们在下面的代码中使用单峰和instance Functor Matrix
,以及instance Functor Matrix
是如何工作的?
instance Functor Matrix where
fmap f (M n m v) = M n m $ fmap (fmap f) v
instance Num a => Num (Matrix a) where
fromInteger = M 1 1 . V.singleton . V.singleton . fromInteger
negate = fmap negate
(+) = add
(*) = mult
abs = fmap abs
signum = fmap signum
scalarMult :: Num a => a -> Matrix a -> Matrix a
scalarMult = fmap . (*)
我知道函子对于negate
, (*)
, abs
, signum
是必需的,但是我需要一个详细的解释。
Functor
s是一个非常简单的东西,有一个复杂的名字。简单地说,Functor
是容器,您可以通过fmap
函数将函数映射到其值上。列表是最熟悉的Functor
,因为fmap
就是map
。其他Functor
包括Maybe
、IO
和Either a
。
在这个代码片段中,您将Matrix
定义为Functor
,因此您告诉编译器Matrix
是一个可以映射函数的容器。出于这个问题的目的,fmap
用于定义Num
类型类中的几个函数。很容易看出这是如何工作的(假设有一个fromList :: [[a]] -> Matrix a
函数):
> fmap id $ fromList [[1, 2], [3, 4]]
fromList [[1, 2], [3, 4]]
> fmap (+1) $ fromList [[1, 2], [3, 4]]
fromList [[2, 3], [4, 5]]
> fmap show $ fromList [[1, 2], [3, 4]]
fromList [["1", "2"], ["3", "4"]]
对于其他Functor
s:
> fmap (+1) [1, 2, 3]
[2, 3, 4]
> fmap (*10) (Just 1)
Just 10
> fmap (*10) Nothing
Nothing
对于Data.Matrix
为什么在源代码中导入Data.Monoid
,完全是因为函数
-- | Display a matrix as a 'String' using the 'Show' instance of its elements.
prettyMatrix :: Show a => Matrix a -> String
prettyMatrix m@(M _ _ v) = unlines
[ "( " <> unwords (fmap (j -> fill mx $ show $ m ! (i,j)) [1..ncols m]) <> " )" | i <- [1..nrows m] ]
where
mx = V.maximum $ fmap (V.maximum . fmap (length . show)) v
fill k str = replicate (k - length str) ' ' ++ str
作者选择使用<>
而不是++
将字符串连接在一起,这是Monoid
列表的一个相当普通的使用。它与Matrix
类型没有任何关联。