この記事はGo3 Advent Calendar23日目の記事です。
Go3アドベントカレンダーなんですが、 あんまりGoの話が出てきません。
Foの話をします。
Foとは
Foとは、Goに関数型言語の機能を追加したプログラミング言語です。
いくつか特徴的な点があります。ひとつずつ見ていきます。
ジェネリクス
Foでは、ジェネリクスを定義することができます。
type A[T] []T
type B[T, U] map[T]U
type C[T, U] func(T) U
type D[T] struct{
a T
b A[T]
}
ジェネリクスを利用して、Mapを定義してみます。
func MapSlice[T](f func(T) T, list []T) []T {
result := make([]T, len(list))
for i, val := range list {
result[i] = f(val)
}
return result
}
MapSlice関数は、 func(T) T
と []T
を引数に受け取って、listの中身をfuncに渡した結果からなる新しいsliceを返します。
RubyやJavascriptではおなじみですね。
今回はTをintとして、funcは以下のように実装してみます。
func incr(n int) int {
return n+1
}
これを実行してみましょう。main関数は以下のように書けます
func main() {
fmt.Println(MapSlice[int](incr, []int{1, 2, 3}))
}
どうやって実行するのかですが、今回はThe Fo Playgroundを利用します。
実行すると、incrされたlistが表示されますね。
次は、Tをstringとしてみます。
このようなコードを書きました。
package main
import "fmt"
func MapSlice[T](f func(T) T, list []T) []T {
result := make([]T, len(list))
for i, val := range list {
result[i] = f(val)
}
return result
}
func past(n string) string {
return n + "ed"
}
func main() {
fmt.Println(MapSlice[string](past, []string{"want", "watch", "point"}))
}
実行結果は [wanted watched pointed]
のようになります。
カリー化
もうちょっとFunctional Programmingっぽいことをしたいので、カリー化を実装してみます。
このようなコードを書きました。
package main
import "fmt"
func curry2[P1, P2, R](f func(P1, P2) R) func(P1) func(P2) R {
return func(p1 P1) func(P2) R {
return func(p2 P2) R {
return f(p1, p2)
}
}
}
func main() {
add := curry2[int, int, int](
func(a, b int) int {
return a + b
},
)
incr := add(1)
fmt.Println(incr(1))
fmt.Println(incr(10))
}
curry2関数は、f func(P1, P2) R
を受け取って、 func(P1) func(P2) R
を’返す関数です。
ここでは、incrがfです。
ちなみに、そもそもGoは、関数を引数で受け取る・関数を戻り値で返す関数を定義することができるため、
がんばればGo単体でもカリー化を実装することは可能です。
まとめ
その他の例はexamplesにあります。
Goでもジェネリクスがサポートされるという話がありますね。
Foは開発がストップしてしまっている雰囲気があるのですが、面白い試みだと思ったため紹介しました。