public abstract class Option[T] implements Iterable[T] { }
// Some then is a one element Iterator/ None is an empty iterator
// With for you then can do something on Some
// orElse left as an exercise to the reader
for (String name: option) {
// do something with name
}
but today I think one should embrace the language and if it does not work for you, use something else.For Go I think something like Zigs !i32 would fit in perhaps, if one wants a higher level of error handling.
That being said though, it actually fit really well in golang. Allowed functions that used to return ‘null, err’ to return an Either, which improved on all the downsides of returning null (if you return null your callers have to check for it).
It actually improved the ergonomics quite a bit. ‘Either’ fits nicely into golang, but I doubt it will become mainstream anytime soon.
Not an expert in Go but I think you can do this:
func compose[A any, B any, C any](a func(A) (B, error), b func(B) (C, error)) func(A) (C, error) {
return func(aInp A) (C, error) {
res, err := a(aInp)
if err == nil {
return b(res)
} else {
return *new(C), err
}
}
}
The above is equivalent to haskells fish operator >=>The bind operator (>>=) can be implimented in terms of composition:
func bind[A any, B any, C any](a func(A) (B, error), b func(B) (C, error), aInput A) (C, error) {
return compose[A, B, C](a, b)(aInput)
}From my experience, "handling" the error means wrapping it in another error and returning, which is what you get from other languages for free.
You can if A is a function which takes two arguments, e.g.
package main
import "log"
func A(x, y int) { log.Printf("%d, %d", x, y) }
func B() (int, int) { return 1, 2 }
func main() { A(B()) }
https://go.dev/play/p/Jp4B0L6NJj2And there are no slices or channels of tuples, return values must be destructured right away.