【问题标题】:Why we use a monoid and a functor there?为什么我们在那里使用幺半群和仿函数?
【发布时间】:2014-05-28 14:01:15
【问题描述】:

我是 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(*)abssignum 是必需的,但我需要详细说明。请帮帮我。

【问题讨论】:

  • 请显示Matrix的定义。我可以大致猜出它的外观,但正确处理所有细节对于提供更好的示例很有用。
  • 该代码中没有幺半群。澄清你的意思。另外,请包括您使用的数据/类型声明Matrix(或链接到您从中获取它们的库)。
  • import Data.Monoid import Prelude
  • @dmitryvodop 在Data.MonoidPrelude 中没有定义Matrix 类型(无需自行导入,它会自动导入)。 Matrix 定义在哪里?
  • @leftaroundabout 我检查了这段代码:hackage.haskell.org/package/matrix-0.2.1/docs/src/…

标签: haskell functor monoids


【解决方案1】:

Functors 是一个很简单的东西,名字很复杂。简单地说,Functors 是容器,您可以通过 fmap 函数将函数映射到其值上。列表是最熟悉的Functor,因为fmap 只是map。其他Functors 包括MaybeIOEither a

在这个 sn-p 中,您将 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"]]

对于其他Functors:

> fmap (+1) [1, 2, 3]
[2, 3, 4]
> fmap (*10) (Just 1)
Just 10
> fmap (*10) Nothing
Nothing

至于Data.Monoid为什么要在Data.Matrix的源中导入,完全是因为函数原因

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

作者选择使用&lt;&gt; 而不是++ 将字符串连接在一起,这是Monoid 列表的一种相当普通的用法。它与Matrix 类型完全无关。

【讨论】:

  • 谢谢你,很好的解释,现在一切都清楚了!顺便说一句,我们可以写++而不是&lt;&gt;,它的含义是一样的吗?
  • @dmitryvodop 如果您查看Data.Monoid 的来源,您会看到(&lt;&gt;) = mappend,以及instance Monoid [a]mappend = (++)mempty = []。启用优化后,编译器应该能够将其完全内联到++,因为&lt;&gt; 是内联的,简单的类型类对于内联来说是微不足道的。从字面上看,(&lt;&gt;) === mappend === (++)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-06-12
  • 2014-12-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-05
相关资源
最近更新 更多