Goとモナド

Goとerror monads - moriyoshiの日記

ちょっとそれをモナドって呼んだらHaskellerやってきますよ? (太宰メソッド)
just型の構造体にfuncって関数で(interface {}, error)の値を遅延して持たせているのは奇妙だ。
こういう風に、もっとわかりやすく書きたい。

package main

import (
	"log"
	"os"
)

type right struct {
	val interface{}
}

type left struct {
	val error
}

type either interface {
	Fmap(func(interface{}) interface{}) either
	Bind(func(interface{}) (interface{}, error)) either
	Elim(func(error) interface{}) interface{}
}

func (m *right) Fmap(f func(interface{}) interface{}) either {
	return &right{f(m.val)}
}

func (m *left) Fmap(f func(interface{}) interface{}) either {
	return m
}

func (m *right) Bind(k func(interface{}) (interface{}, error)) either {
	v, err := k(m.val)
	if err != nil {
		return &left{err}
	}
	return &right{v}
}

func (m *left) Bind(k func(interface{}) (interface{}, error)) either {
	return m
}

func Pure(v interface{}) either {
	return &right{v}
}

func (m *right) Elim(f func(error) interface{}) interface{} {
	return m.val
}

func (m *left) Elim(f func(error) interface{}) interface{} {
	return f(m.val)
}

func main() {
	if err := Pure("hello.txt").
		Bind(func(s interface{}) (interface{}, error) { return os.Open(s.(string)) } ).
		Fmap(func(f interface{}) interface{} { return f.(*os.File).Close() }).
		Elim(func(err error) interface{} { return err }); err != nil {
		log.Fatalln(err)
	}
}

実行結果:

go$ go build either.go 
go$ ./either 
2013/10/20 03:29:20 open hello.txt: no such file or directory
go$ touch hello.txt
go$ ./either 
go$ rm hello.txt 
go$ ./either 
2013/10/20 03:29:35 open hello.txt: no such file or directory
go$ 

ぶっちゃけGo言語ってこういう書き方に向いていない。せめてジェネリクスは欲しいよね。