如何在 Go 中模拟 `fmap`?
How can I emulate `fmap` in Go?
我想在 Go 中模拟 fmap
。一个简单的例子:
type S [A any] struct {
contents A
}
type Functor [A any, B any] interface{
fmap(f func(A)B) B
}
func (x S[A]) fmap (f func(A)B) S[B] {
x.contents = f(x.contents)
return x
}
这失败了:undefined: B
关于 interface
实施。对此有通用的解决方法吗?
Go 的泛型和方法的组合不像 Haskell 的类型类那样富有表现力;至少还没有。特别是,正如 kostix 在 、
中指出的那样
Go permits a generic type to have methods, but, other than the receiver, the arguments to those methods cannot use parameterized types.
(source)
由于 Go 方法不能引入新的类型参数,因此在 fmap
方法中访问 B
的唯一方法是在 Functor
类型的声明中引入它,和你一样。但这没有意义,因为根据类别理论,functor 接受一个类型参数,而不是两个。
这个例子可能足以让您相信,在 Go 中使用泛型和方法来模拟 Haskell 类型类是徒劳的。
不过,您可以做的一件事是实现 fmap
,不是作为方法,而是作为 top-level 函数:
package main
import "fmt"
type S[A any] struct {
contents A
}
func Fmap[A, B any](sa S[A], f func(A) B) S[B] {
return S[B]{contents: f(sa.contents)}
}
func main() {
ss := S[string]{"foo"}
f := func(s string) int { return len(s) }
fmt.Println(Fmap(ss, f)) // {3}
}
但仅仅因为你可以并不意味着你应该。总是问问自己,将某种其他语言的方法转换为 Go 感觉 是否正确。
我要补充一点,您遇到的一些问题是您开始时定义不正确。提议的 Functor
-
中应该有一些直接的危险信号
type Functor [A any, B any] interface{
// ^ Functor should wrap a single type ⚠️
fmap(f func(A)B) B
// ^ should return Functor-wrapped B ⚠️
}
解决你上面的问题,这就是我们喜欢写的-
type Functor[A any] interface{
fmap[B any](f func(A)B) Functor[B]
}
但是 Go 警告我们就您面临的问题向我们提供直接反馈 -
interface method must have no type parameters
undefined: B
正如@jub0bs 在链接的答案中指出的那样,methods may not take additional type arguments。
我想在 Go 中模拟 fmap
。一个简单的例子:
type S [A any] struct {
contents A
}
type Functor [A any, B any] interface{
fmap(f func(A)B) B
}
func (x S[A]) fmap (f func(A)B) S[B] {
x.contents = f(x.contents)
return x
}
这失败了:undefined: B
关于 interface
实施。对此有通用的解决方法吗?
Go 的泛型和方法的组合不像 Haskell 的类型类那样富有表现力;至少还没有。特别是,正如 kostix 在
Go permits a generic type to have methods, but, other than the receiver, the arguments to those methods cannot use parameterized types.
(source)
由于 Go 方法不能引入新的类型参数,因此在 fmap
方法中访问 B
的唯一方法是在 Functor
类型的声明中引入它,和你一样。但这没有意义,因为根据类别理论,functor 接受一个类型参数,而不是两个。
这个例子可能足以让您相信,在 Go 中使用泛型和方法来模拟 Haskell 类型类是徒劳的。
不过,您可以做的一件事是实现 fmap
,不是作为方法,而是作为 top-level 函数:
package main
import "fmt"
type S[A any] struct {
contents A
}
func Fmap[A, B any](sa S[A], f func(A) B) S[B] {
return S[B]{contents: f(sa.contents)}
}
func main() {
ss := S[string]{"foo"}
f := func(s string) int { return len(s) }
fmt.Println(Fmap(ss, f)) // {3}
}
但仅仅因为你可以并不意味着你应该。总是问问自己,将某种其他语言的方法转换为 Go 感觉 是否正确。
我要补充一点,您遇到的一些问题是您开始时定义不正确。提议的 Functor
-
type Functor [A any, B any] interface{
// ^ Functor should wrap a single type ⚠️
fmap(f func(A)B) B
// ^ should return Functor-wrapped B ⚠️
}
解决你上面的问题,这就是我们喜欢写的-
type Functor[A any] interface{
fmap[B any](f func(A)B) Functor[B]
}
但是 Go 警告我们就您面临的问题向我们提供直接反馈 -
interface method must have no type parameters
undefined: B
正如@jub0bs 在链接的答案中指出的那样,methods may not take additional type arguments。