Go语言 有什么好的方法来定义Monoid接口吗?

pcrecxhr  于 2023-05-04  发布在  Go
关注(0)|答案(3)|浏览(227)

我想定义像“Monoid”这样的结构。(这是一个出现在Group-Theory中的单词。
这里有一个Monoid-Structure的例子。
实施例⑴:

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 // mapping_function(monoid,monoid) -> monoid(binary operations in monoid)
    ide() monoid          // identity_function() -> monoid (return Identity element)

}

尽管代码不起作用(只是伪代码)

llmtgqce

llmtgqce1#

您可以将Monoid接口定义为以下通用接口:

type Monoid[T any] interface {
    Identity() T
    Combine(T) T
}

Combine()对应于幺半群的(关联的)二元运算,Identity()返回幺半群的单位元素。您分别将它们称为op()ide()
CombineMonoids是一个通用的便利函数,用于将任意数量的monoid组合成单个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
}

类型参数M上的约束Monoid[M]-即M Monoid[M]-意味着它适用于任何具有Identity() MCombine(M) M方法的类型M,即它满足Monoid[M]

示例

例如,下面是SumMonoidMaxMonoid类型,它们分别对应于monoid_summonoid_max

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组合在一起是没有意义的--你会将类型Assert放在Combine方法实现中,如果要组合的两个monoid的 *dynamic类型 * 不同,这将导致恐慌。因此,基于通用接口的解决方案似乎更健壮。

k97glaaz

k97glaaz2#

您必须遵循接口定义,因为它们是为struct定义的,以便实现接口。当接口为op方法定义返回类型为monoid时,在实现该接口时必须返回monoid。看看以下是否有帮助:

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}
}
wyyhbhjk

wyyhbhjk3#

谢谢大家的帮助和好意!
我成功地定义了幺半群结构。

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
}

相关问题