有没有好的方法来定义Monoid接口?

huangapple go评论89阅读模式
英文:

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() MCombine(M) M方法的任何类型M,即它满足Monoid[M]

示例

例如,这里是与你的monoid_summonoid_max相对应的SumMonoidMaxMonoid类型。

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
}

问题是特定幺半群(例如SumMonoidMaxMonoid)的原始类型将被擦除为只有接口Monoid

SumMonoidMaxMonoid组合在一起是没有意义的 - 你将在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 (
	&quot;fmt&quot;
)

type monoid interface {
	get() interface{}         // type of interface{} depends on each monoid type.
	op(monoid, monoid) monoid // mapping_function(monoid,monoid) -&gt; monoid(binary operations in monoid)
	ide() monoid              // identity_function() -&gt; 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) &gt; 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{&quot;&quot;, 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{&quot;Jame&quot;, 100}, monoid2{&quot;Tom&quot;, 1010}, monoid2{&quot;BOB SMITH&quot;, 1111}, monoid1{1, 1}, monoid1{2, 2}, monoid1{3, 3}}
	b := []monoid{monoid2{&quot;Trump&quot;, 111}, monoid2{&quot;MaryJames&quot;, 1234}, monoid2{&quot;Cachy&quot;, 123245}, monoid1{1, 1}, monoid1{2, 2}, monoid1{3, 3}}
	for i := 0; i &lt; 6; i++ {
		fmt.Println(a[i].op(b[i], a[i]))
	}
	return
}

huangapple
  • 本文由 发表于 2021年8月12日 10:51:39
  • 转载请务必保留本文链接:https://go.coder-hub.com/68751029.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定