C++幼女先輩

プログラミング成分多め

GoでメソッドチェインのMapReduceライブラリ作ろうか悩んだ

全部For文で筋力プレイしたくない

ってことで、MapReduce系のライブラリ作ろうかと悩んで下記のコードをサンプルで作った

Go Playground - The Go Programming Language

// You can edit this code!
// Click here and start typing.
package main

import "fmt"

type Map[T any] struct {
    value []T
    err   bool
}

func NewMap[T any](v []T) *Map[T] {
    return &Map[T]{value: v, err: false}
}

func errMap[T any]() *Map[T] {
    return &Map[T]{nil, true}
}

func copyMap[T any](v []T, e bool) *Map[T] {
    return &Map[T]{value: v, err: e}
}

// var errMap Map[T] = &Map[T]{value: nil, err: true}

func (s *Map[T]) Foreach(fn func(T) T) *Map[T] {
    if s.err {
        return errMap[T]()
    }

    nv := make([]T, len(s.value))
    for i, v := range s.value {
        nv[i] = fn(v)
    }

    return copyMap(nv, false)
}

func (s *Map[T]) Ok() *Map[T] {
    if s.err {
        return errMap[T]()
    }
    return copyMap(s.value, false)
}

func (s *Map[T]) Ng() *Map[T] {
    if s.err {
        return errMap[T]()
    }
    return copyMap(s.value, true)
}

func (s *Map[T]) Get() ([]T, bool) {
    return s.value, s.err
}

func main() {
    hoge := NewMap[int]([]int{1, 2, 3, 4, 5})

    result, err := hoge.Ok().Ok().Foreach(func(v int) int { return v * 2 }).Get()
    if err {
        fmt.Println("Error")
    } else {
        fmt.Printf("%v\n", result)
    }

}

思い付きで書いたコードだけど
他のMapReduceライブラリだと、リフレクションを使うもの
コード自動生成系

があったが
リフレクションは最終手段にしたい事、interface{}になりキャストが発生
実行速度や動作不安定さが怖いので使いたくない
コードジェネレート系も、色々なからみで使いたくない

ので、ジェネリクスを使いサンプル実装してみた

まず、メソッドチェインをしたかったが、Goの基本は 値とerrのタプルを返却するものなので
タプルだとメソッドチェインが出来ないため
ジェネリクスを使い2値をもつStructを作りメソッドチェインを実現させ
Goには例外がないので、メンバ変数でErrを保持し処理をし
最後にGetメンバで、値とErr値を取得

最低限の動作はできそう

本当は遅延評価とかしたいんですけどね・・
Goで遅延評価考えたくないし、そもそもクロージャの記述がだるく、関数型に向いてないよねえ

例外処理的な事考えずに素直に関数型っぽくする方が楽かなあ・・