英文:
Is there any good way to define Monoid interface?
问题
我想定义一个类似于"Monoid"的结构体。(这是一个在群论中出现的词。)
这里有一个Monoid结构的例子。
例子(1):
type monoid_sum struct{
val int
}
func op(x, y monoid_sum) monoid_sum {
return monoid_sum{x.val + y.val}
}
func ide() monoid_sum {
return monoid_sum{0}
}
例子(2):
import "math"
func max(a, b int) int {
if a > b {
return a
} else {
return b
}
}
type monoid_max struct {
val int
}
func op(x, y monoid_max) monoid_max {
return monoid_max{max(x.val, y.val)}
}
func ide() monoid_max {
return monoid_max{math.MinInt}
}
有没有一种好的方法来定义一个Monoid接口?我想创建一个类似于这样的接口:
type monoid interface {
op func(monoid) monoid // 映射函数(monoid, monoid) -> monoid(Monoid中的二元操作)
ide() monoid // 单位元函数() -> monoid(返回单位元素)
}
尽管这些代码不起作用(只是伪代码)。
英文:
I'd like to define structure like "Monoid". (This is a word which appears in Group-Theory.)
Here's one example of Monoid-Structure.
Example(1):
type monoid_sum struct{
val int
}
func op(x,y monoid_sum) monoid_sum {
return monoid_sum{x.val + y.val}
}
func ide() monoid_sum{
return monoid_sum{0}
}
Example(2):
import "math"
func max(a,b int) int{
if a > b{
return a
}else{
return b
}
}
type monoid_max struct {
val int
}
func op(x,y monoid_max) monoid_max {
return monoid_max{max(x.val,y.val)}
}
func ide() monoid_max {
return monoid_max{math.MinInt}
}
Is there any good way to define a monoid interface? I want to make an interface like this:
type monoid interface{
op func(monoid) monoid // mapping_function(monoid,monoid) -> monoid(binary operations in monoid)
ide() monoid // identity_function() -> monoid (return Identity element)
}
though the codes does not work(just Pseudo code)
答案1
得分: 1
你可以将Monoid
接口定义为以下通用接口:
type Monoid[T any] interface {
Identity() T
Combine(T) T
}
Combine()
对应于幺半群(associative)的二元操作,而Identity()
返回幺半群的单位元素。你分别称它们为op()
和ide()
。
CombineMonoids
是一个通用的便利函数,用于将任意数量的幺半群组合成一个单一的幺半群:
func CombineMonoids[M Monoid[M]](ms ...M) M {
var res M
res = res.Identity()
for _, m := range ms {
res = res.Combine(m)
}
return res
}
对类型参数M
的约束Monoid[M]
- 即M Monoid[M]
- 意味着它适用于具有Identity() M
和Combine(M) M
方法的任何类型M
,即它满足Monoid[M]
。
示例
例如,这里是与你的monoid_sum
和monoid_max
相对应的SumMonoid
和MaxMonoid
类型。
SumMonoid
type SumMonoid int
func (s SumMonoid) Identity() SumMonoid {
return 0
}
func (s SumMonoid) Combine(r SumMonoid) SumMonoid {
return s + r
}
类型SumMonoid
满足接口Monoid[SumMonoid]
。
func TestSumMonoid(t *testing.T) {
a := SumMonoid(3)
b := SumMonoid(7)
c := SumMonoid(10)
want := SumMonoid(20)
got := CombineMonoids(a, b, c)
if got != want {
t.Fail()
}
}
MaxMonoid
type MaxMonoid int
func (m MaxMonoid) Identity() MaxMonoid {
return math.MinInt
}
func (m MaxMonoid) Combine(n MaxMonoid) MaxMonoid {
if m > n {
return m
} else {
return n
}
}
类型MaxMonoid
满足接口Monoid[MaxMonoid]
。
func TestMaxMonoid(t *testing.T) {
a := MaxMonoid(-100)
b := MaxMonoid(500)
c := MaxMonoid(100)
want := MaxMonoid(500)
got := CombineMonoids(a, b, c)
if got != want {
t.Fail()
}
}
非通用的Monoid
接口怎么样?
与你建议的类似,你可以原则上将Monoid
定义为非通用接口:
type Monoid interface {
Identity() Monoid
Combine(Monoid) Monoid
}
问题是特定幺半群(例如SumMonoid
或MaxMonoid
)的原始类型将被擦除为只有接口Monoid
。
将SumMonoid
与MaxMonoid
组合在一起是没有意义的 - 你将在Combine
方法实现中放置类型断言,如果要组合的两个幺半群的动态类型不同,将导致恐慌。因此,基于通用接口的解决方案似乎更加健壮。
英文:
You could define the Monoid
interface as the following generic interface:
type Monoid[T any] interface {
Identity() T
Combine(T) T
}
Combine()
corresponds to the monoid's (associative) binary operation, and Identity()
returns the monoid's identity element. You called them op()
and ide()
, respectively.
CombineMonoids
is a generic convenience function for combining an arbitrary number of monoids into a single monoid:
func CombineMonoids[M Monoid[M]](ms ...M) M {
var res M
res = res.Identity()
for _, m := range ms {
res = res.Combine(m)
}
return res
}
The constraint Monoid[M]
on the type parameter M
– i.e., M Monoid[M]
– means that it works with any type M
that has the methods Identity() M
and Combine(M) M
, i.e., it satisfies Monoid[M]
.
Examples
For example, here are the types SumMonoid
and MaxMonoid
that correspond to your monoid_sum
and monoid_max
, respectively.
SumMonoid
type SumMonoid int
func (s SumMonoid) Identity() SumMonoid {
return 0
}
func (s SumMonoid) Combine(r SumMonoid) SumMonoid {
return s + r
}
The type SumMonoid
satisfies the interface Monoid[SumMonoid]
.
func TestSumMonoid(t *testing.T) {
a := SumMonoid(3)
b := SumMonoid(7)
c := SumMonoid(10)
want := SumMonoid(20)
got := CombineMonoids(a, b, c)
if got != want {
t.Fail()
}
}
MaxMonoid
type MaxMonoid int
func (m MaxMonoid) Identity() MaxMonoid {
return math.MinInt
}
func (m MaxMonoid) Combine(n MaxMonoid) MaxMonoid {
if m > n {
return m
} else {
return n
}
}
The type MaxMonoid
satisfies the interface Monoid[MaxMonoid]
.
func TestMaxMonoid(t *testing.T) {
a := MaxMonoid(-100)
b := MaxMonoid(500)
c := MaxMonoid(100)
want := MaxMonoid(500)
got := CombineMonoids(a, b, c)
if got != want {
t.Fail()
}
}
What about a non-generic Monoid
interface?
Similarly to what you suggested, you could, in principle, define the Monoid
as a non-generic interface:
type Monoid interface {
Identity() Monoid
Combine(Monoid) Monoid
}
The problem is that the original type of the particular monoid (e.g., SumMonoid
or MaxMonoid
) will be erased to just the interface Monoid
.
Combining a SumMonoid
with a MaxMonoid
makes no sense – you would place type assertions inside of the Combine
method implementation that will lead to a panic if the dynamic type of the two monoids to be combined differ. So, the solution based on the generic interface seems to be more robust.
答案2
得分: 0
你需要按照结构体的接口定义来实现接口。当接口将返回类型定义为 monoid
时,你在实现该接口的 op
方法时需要返回 monoid
。看看下面的代码是否有帮助:
type monoid interface{
get() int
op(monoid, monoid) monoid // mapping_function(monoid,monoid) -> monoid(在monoid中的二元操作)
ide() monoid // identity_function() -> monoid(返回单位元素)
}
func max(a,b int) int{
if a > b{
return a
}else{
return b
}
}
type monoid2 struct{
val int
}
func (m monoid2) get() int {
return m.val
}
func (monoid2) op(x,y monoid) monoid{
return monoid2{max(x.get(),y.get())}
}
func (monoid2) ide() monoid{
return monoid2{-math.MaxInt8}
}
英文:
You'll have to follow the interface definitions as they are defined for struct to implement the interface. When interface defines return type as monoid
for your op
method, you'll have to return monoid in when implementing that interface. See if following helps:
type monoid interface{
get() int
op(monoid, monoid) monoid // mapping_function(monoid,monoid) -> monoid(binary operations in monoid)
ide() monoid // identity_function() -> monoid (return Identity element)
}
func max(a,b int) int{
if a > b{
return a
}else{
return b
}
}
type monoid2 struct{
val int
}
func (m monoid2) get() int {
return m.val
}
func (monoid2) op(x,y monoid) monoid{
return monoid2{max(x.get(),y.get())}
}
func (monoid2) ide() monoid{
return monoid2{-math.MaxInt8}
}
答案3
得分: 0
感谢大家的帮助和善意!
我成功定义了幺半群结构。
package main
import (
"fmt"
)
type monoid interface {
get() interface{} // 接口{}的类型取决于每个幺半群类型。
op(monoid, monoid) monoid // mapping_function(monoid,monoid) -> monoid(幺半群中的二元操作)
ide() monoid // identity_function() -> monoid(返回幺元素)
}
type monoid1 struct {
val int
sum int
}
type monoid2 struct {
name string
power int
}
func (m monoid2) get() interface{} {
return m
}
func (m monoid2) op(x, y monoid) monoid {
a := x.get().(monoid2)
b := y.get().(monoid2)
if len(a.name) > len(b.name) {
return monoid2{a.name, a.power + b.power}
} else {
return monoid2{b.name, a.power + b.power}
}
}
func (m monoid2) ide() monoid {
return monoid2{"", 0}
}
func (m monoid1) get() interface{} {
return m
}
func (m monoid1) op(x, y monoid) monoid {
a := x.get().(monoid1)
b := y.get().(monoid1)
return monoid1{a.val + b.val, a.sum + b.sum}
}
func (m monoid1) ide() monoid {
return monoid1{0, 0}
}
func main() {
a := []monoid{monoid2{"Jame", 100}, monoid2{"Tom", 1010}, monoid2{"BOB SMITH", 1111}, monoid1{1, 1}, monoid1{2, 2}, monoid1{3, 3}}
b := []monoid{monoid2{"Trump", 111}, monoid2{"MaryJames", 1234}, monoid2{"Cachy", 123245}, monoid1{1, 1}, monoid1{2, 2}, monoid1{3, 3}}
for i := 0; i < 6; i++ {
fmt.Println(a[i].op(b[i], a[i]))
}
return
}
英文:
Thank you for everyone's help and kindness!
I successfully defined monoid structure.
package main
import (
"fmt"
)
type monoid interface {
get() interface{} // type of interface{} depends on each monoid type.
op(monoid, monoid) monoid // mapping_function(monoid,monoid) -> monoid(binary operations in monoid)
ide() monoid // identity_function() -> monoid (return Identity element)
}
type monoid1 struct {
val int
sum int
}
type monoid2 struct {
name string
power int
}
func (m monoid2) get() interface{} {
return m
}
func (m monoid2) op(x, y monoid) monoid {
a := x.get().(monoid2)
b := y.get().(monoid2)
if len(a.name) > len(b.name) {
return monoid2{a.name, a.power + b.power}
} else {
return monoid2{b.name, a.power + b.power}
}
}
func (m monoid2) ide() monoid {
return monoid2{"", 0}
}
func (m monoid1) get() interface{} {
return m
}
func (m monoid1) op(x, y monoid) monoid {
a := x.get().(monoid1)
b := y.get().(monoid1)
return monoid1{a.val + b.val, a.sum + b.sum}
}
func (m monoid1) ide() monoid {
return monoid1{0, 0}
}
func main() {
a := []monoid{monoid2{"Jame", 100}, monoid2{"Tom", 1010}, monoid2{"BOB SMITH", 1111}, monoid1{1, 1}, monoid1{2, 2}, monoid1{3, 3}}
b := []monoid{monoid2{"Trump", 111}, monoid2{"MaryJames", 1234}, monoid2{"Cachy", 123245}, monoid1{1, 1}, monoid1{2, 2}, monoid1{3, 3}}
for i := 0; i < 6; i++ {
fmt.Println(a[i].op(b[i], a[i]))
}
return
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论