iTranslated by AI

The content below is an AI-generated translation. This is an experimental feature, and may contain errors. View original article

#golang Method Expressions and Method Values

に公開

This is a small tip. It's based on an interesting discussion from Chapter 6.4 that came up during the "7th 'The Go Programming Language' Online Reading Circle".

For example, a method Method() for type T can be represented as follows:

func (t T) Method() { ... }

The (t T) immediately following the func keyword is what's called a "method receiver," and it serves to connect the type and the function. In fact, this method is equivalent to:

func Method(t T) { ... }

It might be easier to understand if you think of the method receiver (t T) as an implicit "zeroth" argument.

What expresses this property well are "Method Expressions" and "Method Values." Let's consider the following type and method as an example.

package main

type Number struct {
    n int
}

func (n Number) Add(i int) int {
    return n.n + i
}

Method Expression

Consider the following process for the definition above.

sample1.go
func main() {
    add := Number.Add
    fmt.Printf("%T\n", add)
}

The execution result of this code is:

$ go run sample1.go
func(main.Number, int) int

Do you notice that the first argument is of type Number? When you expand a method tied to a type into a "Method Expression" like this, the method receiver becomes the first argument. Therefore:

sample1b.go
func main() {
    add := Number.Add
    fmt.Println(add(Number{1}, 2))
}

The execution result of this code is:

$ go run sample1b.go 
3

Method Value

Even more interesting is the "Method Value." Let's consider a code like this.

sample2.go
func main() {
    increment := Number{1}.Add
    fmt.Printf("%T\n", increment)
    fmt.Println(increment(2))
}

The execution result of this code is:

$ go run sample1.go
func(int) int
3

In other words, the "Method Value" set in increment is already associated with the Number instance initialized with 1.

This kind of feels like partial application in currying, doesn't it? Well, not quite (haha).

Feels like partial application?

In the hardcore functional programming language Haskell, a function definition:

add x y = x + y

is syntactic sugar for the curried expression[1]:

add = \x -> \y -> x + y

Using this, you can create partial application:

increment = add 1

Since Go supports first-class functions, you can implement currying expressions if you really want to:

package main

import "fmt"

func add(x int) func(int) int {
    return func(y int) int {
        return x + y
    }
}

func main() {
    fmt.Println(add(1)(2)) //Output: 3
    increment := add(1) //partial application
    fmt.Println(increment(2)) //Output: 3
}

But it ends up being unnecessarily complicated code like that (haha). If you just want to do partial application, using Method Values might be easier.

And that's all for now.

https://text.baldanders.info/remark/2020/03/currying/

Reference Books

https://www.amazon.co.jp/dp/4621300253

脚注
  1. In Haskell, a function can only take one argument, so currying is a mandatory requirement. ↩︎

GitHubで編集を提案

Discussion