8

我正在以不同的方式重写简单的函数,我显然误解了一些核心概念。有没有更好的方法来处理像这样的有限类型?

mlength :: Monoid m => m -> Int
mlength mempty   = 0
mlength (l <> r) = mlength l + mlength r

编译失败并出现以下错误:

Parse error in pattern: l <> r

我可以看到我的使用被误导了,因为and<>有多个正确的匹配项。尽管看起来分配哪个值并不重要,但最终仍然必须分配一个值。也许我有办法为特定的 Monoid 实例断言这个决定?lr

"ab" == ""   <> "ab" 
"ab" == "a"  <> "b" 
"ab" == "ab" <> ""
4

2 回答 2

12

在一般情况下,幺半群没有长度的概念。以 为例Sum Int,它Int配备了用于单向操作的加法。我们有

Sum 3 <> Sum 4 = Sum 7 = Sum (-100) <> Sum 7 <> Sum (100)

它的“长度”应该是多少?这里没有真正的长度概念,因为基础类型是Int,它不是类似列表的类型。

又如:Endo Int其中Int -> Int配备作文。例如

Endo (\x -> x+1) <> Endo (\x -> x*2) = Endo (\x -> 2*x+1)

同样,这里不能定义有意义的“长度”。

您可以浏览Data.Monoid并查看其他没有“长度”概念的示例。

Const a也是一个没有长度的(无聊的)幺半群。

现在,列表确实[a]形成了一个幺半群(自由幺半群 over a),并且确实可以在那里定义长度。不过,这只是一个特例,不能一概而论。

于 2020-02-15T08:37:25.760 回答
5

和接口提供了一种建立价值的方法Semigroup,. 然而,它们并没有给我们一种方法来分解或以其他方式从值中提取信息。既然如此,超出某些特定类型的泛化需要不同的抽象。Monoid(<>)length

正如对chi's answer的评论中所讨论的那样,虽然Data.Foldable提供了一个概括性的length :: Foldable t => t a -> Int,但它并不是您的目标——特别是,和之间的联系FoldableMonoid可折叠结构可以转换为列表/自由幺半群,而不是那个可折叠物本身必然是幺半群。

另一种可能性,有点模糊,但更接近你的问题的精神,是Factorial来自monoid-subclasses的类,它是Semigroup. 它是围绕 构建的factors :: Factorial m => m -> [m],它将一个值拆分为不可约的因素,取消做什么sconcatmconcat做什么。length :: Factorial m => m -> Int然后可以将广义定义为因子列表的长度。Semigroup在任何情况下,请注意,我们仍然需要在/的顶部进行进一步的抽象Monoid

于 2020-02-16T20:23:31.893 回答