Skip to content

Instantly share code, notes, and snippets.

@lupuszr
Created April 7, 2022 20:02
Show Gist options
  • Save lupuszr/c250e1e8020ee3ef5513f48dca42cb3a to your computer and use it in GitHub Desktop.
Save lupuszr/c250e1e8020ee3ef5513f48dca42cb3a to your computer and use it in GitHub Desktop.
package main
import (
"errors"
"fmt"
)
type RS[R any] struct {
a R
err error
}
func (rs *RS[R]) mapV(fn func(R) (R, error)) *RS[R] {
if rs.err != nil {
return rs
}
u, err := fn(rs.a)
return &RS[R]{a: u, err: err}
}
// used to fallback
func (rs *RS[R]) alt(a R) *RS[R] {
if rs.err != nil {
return &RS[R]{a: a, err: nil}
}
return rs
}
// map the value and the error
//func (rs *RS[R]) bimap(fn func(R) (R, error), fne func(error) (R, error)) *RS[R] {
// if rs.err != nil {
// return &RS[R]{a: rs.a, err: errors.New(fne(rs.error))}
// }
// res, err := fn(rs.a)
// return &RS[R]{a: res, err: errors.New(fne(err))}
//}
func mapRS[R any, B any](rs *RS[R], fn func(R) (B, error)) *RS[B] {
if rs.err != nil {
i := &RS[B]{}
i.err = rs.err
//return rs
return i
}
u, err := fn(rs.a)
return &RS[B]{a: u, err: err}
}
func fold[R any, Acc any](rs *RS[R], acc Acc, fn func(R, Acc) (*Acc, error)) *Acc {
if rs.err != nil {
return &acc
}
res, err := fn(rs.a, acc)
if err != nil {
return &acc
}
return res
}
func apply[R any, B any](fn *RS[func(R) (B, error)], rs *RS[R]) *RS[B] {
//return mapRS(rs, func(a R) (B, error) {
// return fn.mapV(func(f func(R) (B, error)) (B, error) {
// return f(a)
// })
//})
return mapRS(rs, func(value R) (B, error) {
v, e := fn.a(value)
if e != nil {
return v, e
}
return v, e
})
}
func mkRS[R any](val R) *RS[R] {
return &RS[R]{a: val, err: nil}
}
func DoSomething() error {
return errors.New("something didn't work")
}
type Box struct {
v int64
k string
}
func main() {
var x = RS[int64]{a: 4, err: nil}
var y = RS[int64]{a: 4, err: DoSomething()}
// functorial nature
var z = x.mapV(func(a int64) (int64, error) { return a + 5, nil }).mapV(func(a int64) (int64, error) { return a + 1, nil })
var u = mapRS(z, func(a int64) (Box, error) { return Box{v: a, k: "hello"}, nil })
if u.err != nil {
fmt.Println("Err is:", z.err)
} else {
fmt.Println("Val is:", u.a)
}
// using as an applicative
var f = mkRS(func(a int64) (int64, error) {
if a%2 == 0 {
return a, errors.New("Not an even number")
}
return a * 2, nil
})
//rs := apply(f, &x)
rs := apply(f, &y)
if rs.err != nil {
fmt.Println("Err is:", rs.err)
} else {
fmt.Println("Val is:", rs.a)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment