我已经从{{3}}阅读到有关monoid同构的信息,并且无法理解100%。
作者说(强调原文):
length
函数从String
映射到Int
,同时保留 单体结构。这样的功能,可以将一个半身像映射到 另一种以这种保存方式被称为 monoid同态。在 一般而言,对于monoM
和N
,同构f: M => N
和所有值x:M
,y:M
,以下等式成立:f(x |+| y) == (f(x) |+| f(y)) f(mzero[M]) == mzero[N]
他的意思是说,由于数据类型String
和Int
是类半群,而函数length
映射String => Int
保留了类半群结构(Int
是一个monoid),它被称为monoid同态,对吧?
答案 0 :(得分:68)
他的意思是说,数据类型String和Int是等宽的。
否,String
和Int
都不是类半体动物。一个单面体是一个三元组(S,⊕,e),其中⊕是一个二元运算符⊕:S×S→S ,因此对于所有元素 a,b,c∈S认为(a⊕b)⊕c=a⊕(b⊕c)和e∈S是一个“身份元素”,例如a⊕e=e⊕a= a 。 String
和Int
是类型,因此基本上是一组值,但不是三元组。
文章说:
让我们将
String
串联和Int
添加作为 有关系的示例 monoids 。
因此,作者显然还提到了二元运算符(在(++)
的情况下为String
,在(+)
的情况下为Int
)。身份(String
为空字符串,0
为Int
)是隐式的;在非正式英语语篇中,将身份留给读者练习是很常见的。
现在假设我们有两个单半体结构(M,⊕,e m )和(N,⊗,e n ),然后将函数 f:M→N (如length
称为monoid homomorphism [wiki],因为它认为 f(m 1 ⊕m 2 )= f(m 1 )⊗f(m 2 ) m 1 ,m 2 ∈M并且该映射还保留了标识元素: f(e m )= e n 。
例如length :: String -> Int
是一个单面体同态,因为我们可以考虑(String
,(++)
,""
)和(Int
,(+)
,0
)。它认为:
length (s1 ++ s2) == length s1 + length s2
(对于所有String
个s1
和s2
);和length "" == 0
。答案 1 :(得分:18)
数据类型本身不能是monoid。对于Monoid,您需要数据类型T
和另外两件事:
|+|
,它接受两个T
类型的元素并产生一个T
类型的元素T
的 identity元素,我们将其称为i
,这样对于类型为t
的每个元素T
,以下内容均成立:t |+| i = i |+| t = t
以下是monoid的一些示例:
Monoid同态
通过将.length
应用于字符串的所有元素,可以将字符串串联Monoid转换为整数加法Monoid。这两个集合都构成一个半体。顺便说一句,请记住,我们不能只说“一组整数构成一个单半体”。我们必须选择一个关联操作和一个相应的标识元素。如果我们采取除法运算,我们打破了第一条规则(而不是生成整数类型的元素,而可能生成float / double类型的元素)。
方法length
允许我们从一个Monoid(字符串串联)转到另一个Monoid(整数加法)。如果这样的操作也保留了类半体结构,则它被认为是 monoid同态。
保留结构意味着:
length(t1 |+| t2) = length(t1) |+| length(t2)
and
length(i) = i'
其中t1
和t2
代表“源” monoid的元素,i
是“源” monoid的标识,i'
是“目的地”类半身像。您可以自己尝试一下,看看length
确实是一个对字符串串联Monoid进行结构保留的操作,例如indexOf("a")
不是。
Monoid同构
如所示,length
将所有字符串映射到它们相应的整数,并形成一个以加法运算为运算符和以零表示为标识的monoid。但是我们不能返回-对于每个字符串,我们都可以计算出它的长度,但是在给定长度的情况下,我们无法重构“原始”字符串。如果可以的话,“向前”操作与“向后”操作相结合将形成 monoid同构。
同构意味着能够来回移动而不会丢失任何信息。例如,如前所述,列表在附加为操作和空列表作为标识元素的情况下形成一个monoid。我们可以从“附加列表下的” monoid转到“附加矢量下的” monoid,然后返回而不会丢失任何信息,这意味着操作.toVector
和.toList
共同形成同构。鲁纳尔在课文中提到的同构的另一个示例是String
⟷List[Char]
。
答案 2 :(得分:2)
通俗地说,同构是保留结构的函数。在length
函数的示例中,保留的结构是to字符串的长度之和等于相同字符串的串联长度。由于字符串和整数都可以视为等分体(当配备了等式和遵循二等性律的关联二进制运算时),length
被称为类同态。
另请参阅其他答案以获取更多技术说明。
答案 3 :(得分:0)
trait Monoid[T] {
def op(a: T, b: T): T
def zero: T
}
val strMonoid = new Monoid[String] {
def op(a: String, b: String): String = a ++ b
def zero: String = ""
}
val lcMonoid = new Monoid[List[Char]] {
def op(a: List[Char], b: List[Char]): List[Char] = a ::: b
def zero = List.empty[Char]
}
f{M.op(x,y)} = N.op(f(x),g(y))
for example, using toList available on String
//in REPL
scala> strMonoid.op("abc","def").toList == lcMonoid.op("abc".toList,"def".toList)
res4: Boolean = true
通过函数f和g M和N之间存在双向同构,
f{M.op(x,y)} = N.op(f(x),f(y))
g{N.op(x,y)} = M.op(g(x),g(y))
如果(f andThen g)和(g andThen f)都是识别函数,则通过f和g的等式M和N是同构的。
g{f{M.op(x,y)}} = g{N.op(f(x),f(y))} = M.op(g(f(x)),g(f(y))) = M.op(x,y)
例如,使用toList
上可用的String
和toString
上可用的List[Char]
(其中toList andThen toString
和toString andThen toList
是身份函数)< / p>
scala> ( strMonoid.op("abc","def").toList ).toString == ( lcMonoid.op("abc".toList,"def".toList) ).toString
res7: Boolean = true