(+)(++) 只是 mappend 的特化;我对吗?为什么需要它们?这是无用的重复,因为 Haskell 有这些强大的类型类和类型推断。
假设我们删除 (+)(++) 并重命名 mappend (+) 以方便视觉和打字增益。
对于初学者来说,编码会更直观、更短、更容易理解:

--old and new
1 + 2
--result
3

--old
"Hello" ++ " " ++ "World"
--new
"Hello" + " " + "World"
--result
"Hello World"

--old
Just [1, 2, 3] `mappend` Just [4..6]
--new
Just [1, 2, 3] + Just [4..6]
--result
Just [1, 2, 3, 4, 5, 6]

(它让我做梦。)。对于坚持抽象和诸如 Haskell 之类的东西的美丽语言来说,三个甚至更多的函数对于同一件事来说并不是一件好事。
我也看到了同一种重复使用的单子(monad):fmap是相同的,或近,作为map(.)liftMmapMforM,...
我知道 fmap 有历史原因,但是幺半群呢? Haskell 委员会是否对此有计划?它会破坏一些代码,但我听说,虽然我不确定,有一个即将到来的版本会有很大的变化,这是一个很好的机会。太可惜了……至少, fork 买得起吗?

编辑
在我读到的答案中,事实上,对于数字, (*)(+) 都可以放入 mappend 。事实上,我认为 (*) 应该是 Monoid 的一部分!看:

目前,忘记了函数 memptymconcat ,我们只有 mappend
class Monoid m where
    mappend :: m -> m -> m

但我们可以这样做:
class Monoid m where
    mappend :: m -> m -> m
    mmultiply :: m -> m -> m

它会(也许,我还没有考虑得足够多)表现如下:
3 * 3
mempty + 3 + 3 + 3
0 + 3 + 3 + 3
9

Just 3 * Just 4
Just (3 * 4)
Just (3 + 3 + 3 +3)
Just 12

[1, 2, 3] * [10, 20, 30]
[1 * 10, 2 * 10, 3 * 10, ...]
[10, 20, 30, 20, 40, 60, ...]

实际上 'mmultiply' 只会根据 'mappend' 定义,因此对于 Monoid 的实例,无需重新定义它!那么 Monoid 更接近数学;也许我们也可以将 (-)(/) 添加到类中!
如果这有效,我认为它会解决 SumProduct 以及函数重复的情况: mappend 变为 (+) 和新的 1x231314313143131313431313134313431343131343431343131343131341
基本上我建议用“上拉”重构代码。
哦,我们还需要一个新的 mmultiply 用于 (*)
我们可以在类 mempty 中抽象这些运算符,并定义 (*) 如下:
class (Monoid m) => MonoidOperator mo m where
    mempty :: m
    mappend :: m -> m -> m

instance MonoidOperator (+) m where
    mempty = 0
    mappend = --definition of (+)

instance MonoidOperator (*) where
    --...

class Monoid m where
    -...

好吧,我还不知道如何做到这一点,但我认为所有这些都有一个很酷的解决方案。

最佳答案

你试图在这里混合一些不同的概念。

算术和列表连接是非常实用的直接操作。如果你写:

[1, 2] ++ [3, 4]

...你知道你会得到 [1, 2, 3, 4] 作为结果。

Monoid 是一个更抽象的数学代数概念。这意味着 mappend 不必字面意思是“将这个附加到那个;”它可以有许多其他含义。当你写:
[1, 2] `mappend` [3, 4]

...这些是该操作可能产生的一些有效结果:
[1, 2, 3, 4] -- concatenation, mempty is []

[4, 6]       -- vector addition with truncation, mempty is [0,0..]

[3, 6, 4, 8] -- some inner product, mempty is [1]

[3, 4, 6, 8] -- the cartesian product, mempty is [1]

[3, 4, 1, 2] -- flipped concatenation, mempty is []

[]           -- treating lists like `Maybe a`, and letting lists that
             -- begin with positive numbers be `Just`s and other lists
             -- be `Nothing`s, mempty is []

为什么列表的 mappend 只是连接列表?因为这只是编写 Haskell 报告的人选择作为默认实现的幺半群的定义,可能是因为它对列表的所有元素类型都有意义。实际上,您可以通过将列表包装在各种新类型中来使用列表的替代 Monoid 实例;例如,有一个替代 Monoid 实例,用于对它们执行笛卡尔积的列表。

Monoid这个概念在数学中有着固定的含义和悠久的历史,在Haskell中改变它的定义意味着偏离数学概念,这是不应该发生的。 Monoid 不仅仅是对空元素和(文字)追加/连接操作的描述;它是遵循 Monoid 提供的接口(interface)的广泛概念的基础。

您正在寻找的概念特定于数字(因为您无法定义类似 mmultiplymproduce/mproduct 之类的东西,对于 0x251812231343 的所有实例,已经存在 151812231343 的所有实例,例如 151812231343 的数学概念已经存在,18123134312313143143143131313131343134并没有真正涵盖您的问题中的结合性,但无论如何您都在示例中的不同概念之间跳跃﹘有时坚持结合性,有时不坚持﹘但总体思路是相同的)。

在 Haskell 中已经有 Semirings 的实现,例如在 Semiring 包中。

然而,幺半群通常不是半环,特别是除了加法和乘法之外,对于实数还有多种半环的实现。向像 Monoid 这样定义良好的类型类添加广泛的泛化添加,不应该仅仅因为它“会很整洁”或“会节省一些击键次数”;我们将 Maybe aalgebra(++) 作为单独的概念是有原因的,因为它们代表了完全不同的计算思想。

关于Haskell:重复函数 (+) 和 (++),mappend,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/10961483/

10-13 04:41