Created
September 24, 2015 23:34
-
-
Save Rubentxu/c353cac8f18321dbd96d to your computer and use it in GitHub Desktop.
Implementing the Maybe monad in Golang
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"fmt" | |
"errors" | |
) | |
type Maybe interface { | |
Return(value interface{}) Maybe | |
Bind(func(interface{}) Maybe) Maybe | |
} | |
type Just struct { | |
Value interface{} | |
} | |
type Nothing struct {} | |
func (j Just) Return(value interface{}) Maybe { | |
return Just{ value } | |
} | |
func (j Just) Bind(fn func(interface{}) Maybe) Maybe { | |
return fn(j.Value) | |
} | |
func (n Nothing) Return(value interface{}) Maybe { | |
return Nothing{} | |
} | |
func (n Nothing) Bind(fn func(interface{}) Maybe) Maybe { | |
return Nothing{} | |
} | |
// Now instead of writing things like this | |
func ErroringDouble(a int) (int, error) { | |
return 2 * a, errors.New("This is what bothers me about Go the most, I think.") | |
} | |
// We can write | |
func MaybeDouble(a Maybe) Maybe { | |
return a.Bind(func (v interface{}) Maybe { | |
return Just { 2 * v.(int) } | |
}) | |
} | |
// Although it certainly isn't as clear as the first definition, and we | |
// basically had to throw type safety out the window, we no longer | |
// have to write code like the following: | |
/* | |
// Double a number three times because demonstrations, okay? | |
a := 2 | |
newA1, err := ErroringDouble(a) | |
if err != nil { | |
fmt.Println("Whoops!") | |
} else { | |
newA2, err2 := ErroringDouble(newA1) | |
if err2 != nil { | |
fmt.Println("Whoops!!") | |
} else { | |
newA3, err3 := ErroringDouble(newA3) | |
if err3 != nil { | |
fmt.Println("Whoops!!!") | |
} else { | |
// Finally do something with newA3 | |
} | |
} | |
} | |
*/ | |
// We can instead write... | |
/* | |
a := Just{ 2 } | |
newA := MaybeDouble(MaybeDouble(MaybeDouble( a ))) | |
newA.bind(func (v interface{}) Maybe) { | |
// Do stuff with our new value | |
}) | |
*/ | |
func main() { | |
val := Just{ 3 } | |
fmt.Println(val.Bind(func (v interface{}) Maybe { | |
value := v.(int) | |
return Just{ value * value } | |
}).Bind(func (v interface{}) Maybe { | |
return Nothing{} | |
}).Bind(func (v interface{}) Maybe { | |
return Just{ v.(int) + 1 } | |
})) | |
fmt.Println(MaybeDouble(MaybeDouble(MaybeDouble(val)))) | |
} |
Yes!, now lets go with Try!!, and then Either 😄
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Please, do it +