goio

package module
v0.0.0-...-e097087 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 28, 2025 License: Apache-2.0 Imports: 0 Imported by: 0

README

IO Monad Go Lang

Attention. This is an experimental project that I use in my company. The fact that Go Lang does not support generics in struct functions makes the whole thing more insecure. So I started with building a Pipeline and then went to the IO transformations that seem more interesting to me. I ended up implementing two versions, one with functions and one with struct. Below is a minimum documentation of the use of Pipeline and the two IO implementations.

Pipeline

Pipeline should return:

  • any
  • (any, error)
  • (string, any) -> var name, type
  • *result.Result[any]
  • *option.Option[any]
  • *result.Result[*option.Option[any]] Any return of error or None stop pipeline. The last computation should be return a same type of Pipeline[T] generic type.

func TestPipelineSimpleSumWithOpitonSome(t *testing.T) {
	res :=
		pipeline.New[int]().
			Next(func() int {
				return 5
			}).
			Next(func() int {
				return 2
			}).
			Next(func(x int, y int) *option.Option[int] {
				return option.Of(x + y)
			}).
			UnsafeRun()

	assert.Equal(t, 7, res.Get().Get())
}

Http module
// use a custom responder if you need
func Responser(req *nethttp.Request) *result.Result[*http.Responser] {
	res := httptest.NewRecorder()
	beego.BeeApp.Handlers.ServeHTTP(res, req)
	return result.OfValue(&http.Responser{
		StatusCode: res.Code,
		Body:       res.Result().Body,
		Header:     res.Result().Header,
		Raw:        option.Of(res.Result()),
	})
}

response := http.
	NewClient[Req, Resp, Err]().
	Header("Authorization", "my token").
	AsJSON().
	Debug().
	//WithRequester(Responser).
	Post("http://myapp.com/api/account", payload)
RIO

Experimental IO operations using functions

rio.Pure[T any](value T) *IO[T]
rio.PureF[T any](f func() T) *IO[T]
rio.Map[A, B any](io *IO[A], f func(A) B) *IO[B]
rio.FlatMap[A, B any](io *IO[A], f func(A) *IO[B]) *IO[B]
rio.AndThan[A, B any](io *IO[A], f func() *IO[B]) *IO[B]
rio.Filter[A any](io *IO[A], f func(A) bool) *IO[A]
rio.Foreach[A any](io *IO[A], f func(A)) *IO[A]
rio.OrElse[A any](io *IO[A], f func() *IO[A]) *IO[A]
rio.Or[A any](io *IO[A], f func() A) *IO[A]
rio.Recover[A any](io *IO[A], f func(error) A) *IO[A]
rio.RecoverIO[A any](io *IO[A], f func(error) *IO[A]) *IO[A]
rio.CatchAll[A any](io *IO[A], f func(error)) *IO[A]
rio.Ensure[A any](io *IO[A], f func()) *IO[A]
rio.Debug[A any](io *IO[A], label ...string) *IO[A]
rio.Attempt[A any](f func() *result.Result[A]) *IO[A]
rio.Pipe2[A, B, T any](a *IO[A], b *IO[B], f func(A, B) *IO[T]) *IO[T]
rio.Pipe3[A, B, C, T any](a *IO[A], b *IO[B], c *IO[C], f func(A, B, C) *IO[T]) *IO[T]
rio.Pipe4[A, B, C, D, T any](a *IO[A], b *IO[B], c *IO[C], d *IO[D], f func(A, B, C, D) *IO[T]) *IO[T]
rio.Pipe5[A, B, C, D, E, T any](a *IO[A], b *IO[B], c *IO[C], d *IO[D], e *IO[E], f func(A, B, C, D, E) *IO[T]) *IO[T]
rio.Pipe6[A, B, C, D, E, F, T any](a *IO[A], b *IO[B], c *IO[C], d *IO[D], e *IO[E], f *IO[F], fn func(A, B, C, D, E, F) *IO[T]) *IO[T]
rio.Pipe7[A, B, C, D, E, F, G, T any](a *IO[A], b *IO[B], c *IO[C], d *IO[D], e *IO[E], f *IO[F], g *IO[G], fn func(A, B, C, D, E, F, G) *IO[T]) *IO[T]
rio.Pipe8[A, B, C, D, E, F, G, H, T any](a *IO[A], b *IO[B], c *IO[C], d *IO[D], e *IO[E], f *IO[F], g *IO[G], h *IO[H], fn func(A, B, C, D, E, F, G, H) *IO[T]) *IO[T]
rio.Pipe9[A, B, C, D, E, F, G, H, I, T any](a *IO[A], b *IO[B], c *IO[C], d *IO[D], e *IO[E], f *IO[F], g *IO[G], h *IO[H], i *IO[I], fn func(A, B, C, D, E, F, G, H, I) *IO[T]) *IO[T]
rio.Pipe10[A, B, C, D, E, F, G, H, I, J, T any](a *IO[A], b *IO[B], c *IO[C], d *IO[D], e *IO[E], f *IO[F], g *IO[G], h *IO[H], i *IO[I], j *IO[J], fn func(A, B, C, D, E, F, G, H, I, J) *IO[T]) *IO[T]
rio.UnsafeRun[T any](io *IO[T]) (r *result.Result[*option.Option[T]])

func TestHttpRIO(t *testing.T) {

	reqIO := http.
		NewClient[any, *User, any]().
		AsJSON().
		GetRIO("http://4gym.com.br/tools-api/mock/user")

	filterIO := rio.Filter[*http.Response[*User, any]](
		reqIO,
		func(r *http.Response[*User, any]) bool {
			return r.StatusCode == 200
		})

	mapIO := rio.Map[*http.Response[*User, any], int](
		filterIO,
		func(r *http.Response[*User, any]) int {
			return r.StatusCode
		})

	assert.Equal(t, 200, rio.UnsafeRun(mapIO).Get().Get())

}

IO

Experimental IO operations using "magic" app

The IO[T] agregate a set of effects. The result of the last effect should the same of IO generic type.

For exemple:

io.IOApp[string](

	io.IO[string](	// IO operation
		io.Pure(func() int { // effect 1 
            return 1
        }).
		Map(func(i int) string { // effect 1
            return fmt.Sprintf("%v", i)
        }),
	),

).UnsafeRun()	

See as the last effect return string, that is the same type of IO operation.

io.IOApp[string](
	
	io.IO[string](	// IO operation
		io.Pure(func() int { // effect 1
				return 1
		}).
		FailIf(func(i int) error { // effect 2
            if i == 0 {
                return fmt.Errorf("value can't be zero")
            }
            return nil
        }).
		Map(func(i int) string { // effect 3
            return fmt.Sprintf("%v", i)
        }),
	),

).UnsafeRun()

It is also possible apply transformations between distinct IO's


io.IOApp[string](

	io.IO[int](	// IO operation

		io.Pure(func() int { // effect 1 
            return 1
        }).
		FailIf(func(i int) error { // this effect can be arbitrary type
            if i == 0 {
                return fmt.Errorf("value can't be zero")
            }
            return nil
        }),
	),

	io.IO[string]( // IO receive result of last IO
		io.Map(func(i int) string {
            return fmt.Sprintf("%v", i)
        }),
	),

).UnsafeRun()

Http example:

	app := io.IOApp[int](
		http.
			NewClient[any, *User, any]().
			AsJSON().
			GetIO("http://4gym.com.br/tools-api/mock/user"). // IO[*http.Response[*User, any]]
			Filter(io.Filter[*http.Response[*User, any]](
				func(r *http.Response[*User, any]) bool {
					return r.StatusCode == 200
				})),

		io.Map[*http.Response[*User, any], int](
			func(r *http.Response[*User, any]) int {
				return r.StatusCode
			}).Lift(),
	)

	assert.Equal(t, 200, app.UnsafeRun().Get().Get())

The IOApp have an internal cache to store IO results. Using Attempt* effects, we can get a stored value by type. Or else we can get stored type using any Pipe* function. For exemple


io.IOApp[int] (

	io.PureVal(1).Lift(),
	io.PureVal(2).Lift(),
	io.Pipe2(func(x int, y int) int {
		// x = 2, y = 1
		return x + y
	}),

).UnsafeRun()

or


io.IOApp[int] (

	io.PureVal(1).Lift(),
	io.PureVal(2).Lift(),
	io.AttemptValueState(func(s *state.State) int {
		x := state.Consume[int](s) // 2
		y := state.Consume[int](s) // 1
		return x + y
	}),

).UnsafeRun()

state.Consume ensures, in this case, that var is used only one time into effect. If that's not a concern, as in most cases, you can use state.Var[T](s).

The stored values are consumed from last to first in both cases.

Finally, you can return a suspended computation


func SuspendedComputation() *types.IOSuspended {
	return types.Suspend(
		io.PureVal(1).Lift(),
		io.PureVal(2).Lift(),
	)
}

func MyApp() {
	
	io.IOApp[int] (

		SuspendedComputation(),

		io.AttemptValueState(func(s *state.State) int {
			x := state.Consume[int](s) // 2
			y := state.Consume[int](s) // 1
			return x + y
		}),

	).UnsafeRun()

}

All Effects:

io.AndThan[A any](f func() types.IORunnable) *ios.IOAndThan[A]	
io.Then[A any](f func(A) A) *ios.IOThen[A]
io.Ensure[A any](f func()) *ios.IOEnsure[A]
io.Debug[A any](label string) *ios.IODebug[A]
io.MaybeFail[A any](f func(A) *result.Result[A]) *ios.IOMaybeFail[A]
io.MaybeFailError[A any](f func(A) error) *ios.IOMaybeFail[A]
io.Filter[A any](f func(A) bool) *ios.IOFilter[A]
io.FlatMap[A any, B any](f func(A) types.IORunnable) *ios.IOFlatMap[A, B]
io.Map[A any, B any](f func(A) B) *ios.IOMap[A, B]
io.PureVal[T any](value T) *ios.IOPure[T]
io.Pure[T any](f func() T) *ios.IOPure[T]
io.RecoverPure[A any](f func(error) A) *ios.IORecover[A]
io.Recover[A any](f func(error) *result.Result[A]) *ios.IORecover[A]
io.RecoverOption[A any](f func(error) *option.Option[A]) *ios.IORecover[A]
io.RecoverResultOption[A any](f func(error) *result.Result[*option.Option[A]]) *ios.IORecover[A]
io.SliceFilter[A any](f func(A) bool) *ios.IOSliceFilter[A]
io.SliceFlatMap[A any, B any](f func(A) types.IORunnable) *ios.IOSliceFlatMap[A, B]
io.SliceForeach[A any](f func(A)) *ios.IOSliceForeach[A]
io.SliceAttemptOrElse[A any](f func() *result.Result[[]A]) *ios.IOSliceAttemptOrElse[A]
io.SliceAttemptOrElseWithState[A any](f func(*state.State) *result.Result[[]A]) *ios.IOSliceAttemptOrElse[A]
io.SliceMap[A any, B any](f func(A) B) *ios.IOSliceMap[A, B]
io.SliceOr[A any](f func() []A) *ios.IOSliceOr[A]
io.SliceOrElse[A any](f func() types.IORunnable) *ios.IOSliceOrElse[A]
io.AsSliceOf[A any]() *ios.IOAsSlice[A]
io.Tap[A any](f func(A) bool) *ios.IOTap[A]
io.Foreach[A any](f func(A)) *ios.IOForeach[A]
io.Or[A any](f func() A) *ios.IOOr[A]
io.FailIfEmpty[A any](f func() error) *ios.IOFailIfEmpty[A]
io.FailWith[A any](f func() error) *ios.IOFailWith[A]
io.FailIf[A any](f func(A) error) *ios.IOFailIf[A]
io.OrElse[A any](f func() types.IORunnable) *ios.IOOrElse[A]
io.CatchAll[A any](f func(error)) *ios.IOCatchAll[A]
io.Nohup[A any]() *ios.IONohup[A]
io.Attempt[A any](f func() *result.Result[A]) *ios.IOAttempt[A]
io.AttemptOfOption[A any](f func() *option.Option[A]) *ios.IOAttempt[A]
io.AttemptOfResultOption[A any](f func() *result.Result[*option.Option[A]]) *ios.IOAttempt[A]
io.AttemptState[A any](f func(*state.State) *result.Result[A]) *ios.IOAttempt[A]
io.AttemptStateOfOption[A any](f func(*state.State) *option.Option[A]) *ios.IOAttempt[A]
io.AttemptStateOfResultOption[A any](f func(*state.State) *result.Result[*option.Option[A]]) *ios.IOAttempt[A]
io.AttemptOfUnit[A any](f func()) *ios.IOAttempt[A]
io.AttemptStateOfUnit(f func(*state.State)) *ios.IOAttempt[*types.Unit]
io.AttemptOfError[A any](f func() (A, error)) *ios.IOAttempt[A]
io.AttemptStateOfError[A any](f func(*state.State) (A, error)) *ios.IOAttempt[A]
io.AttemptPureState[A any](f func(*state.State) A) *ios.IOAttempt[A]
io.AttemptAndThanWithState[A any](f func(*state.State) types.IORunnable) *ios.IOAttemptAndThan[A]
io.AttemptAndThan[A any](f func() types.IORunnable) *ios.IOAttemptAndThan[A]
io.AttemptRunIOWithState[A any](f func(*state.State) types.IORunnable) *ios.IOAttemptAndThan[A]
io.AttemptRunIO[A any](f func() types.IORunnable) *ios.IOAttemptAndThan[A]
io.AttemptAuto[A any](f interface{}) *ios.IOAttemptAuto[A]
io.AttemptExec[A any](f func(A)) *ios.IOAttemptExec[A]
io.AttemptExecWithState[A any](f func(A, *state.State)) *ios.IOAttemptExec[A]
io.AttemptExecOrElse[A any](f func()) *ios.IOAttemptExecOrElse[A]
io.AttemptExecOrElseWithState[A any](f func(*state.State)) *ios.IOAttemptExecOrElse[A]
io.AttemptOrElseWithState[A any](f func(*state.State) types.IORunnable) *ios.IOAttemptOrElse[A]io.AttemptOrElse[A any](f func() types.IORunnable) *ios.IOAttemptOrElse[A]
io.AttemptThen[A any](f func(A) *result.Result[A]) *ios.IOAttemptThen[A]
io.AttemptThenWithState[A any](f func(A, *state.State) *result.Result[A]) *ios.IOAttemptThen[A]
io.AttemptThenOption[A any](f func(A) *result.Result[*option.Option[A]]) *ios.IOAttemptThen[A]
io.AttemptThenOptionWithState[A any](f func(A, *state.State) *result.Result[*option.Option[A]]) *ios.IOAttemptThen[A]
io.AttemptThenIO[A any](f func(A) types.IORunnable) *ios.IOAttemptThen[A]
io.AttemptThenIOWithState[A any](f func(A, *state.State) types.IORunnable) *ios.IOAttemptThen[A]
io.PipeIO[A, T any](f func(A) types.IORunnable) *ios.IOPipe[A, T]
io.Pipe[A, T any](f func(A) *result.Result[*option.Option[T]]) *ios.IOPipe[A, T]
io.PipeOfValue[A, T any](f func(A) T) *ios.IOPipe[A, T]
io.PipeOfResult[A, T any](f func(A) *result.Result[T]) *ios.IOPipe[A, T]
io.PipeOfOption[A, T any](f func(A) *option.Option[T]) *ios.IOPipe[A, T]
io.Pipe2IO[A, B, T any](f func(A, B) types.IORunnable) *ios.IOPipe2[A, B, T]
io.Pipe2[A, B, T any](f func(A, B) *result.Result[*option.Option[T]]) *ios.IOPipe2[A, B, T]
io.Pipe2OfValue[A, B, T any](f func(A, B) T) *ios.IOPipe2[A, B, T]
io.Pipe2OfResult[A, B, T any](f func(A, B) *result.Result[T]) *ios.IOPipe2[A, B, T]
io.Pipe2OfOption[A, B, T any](f func(A, B) *option.Option[T]) *ios.IOPipe2[A, B, T]
io.Pipe3IO[A, B, C, T any](f func(A, B, C) types.IORunnable) *ios.IOPipe3[A, B, C, T]
io.Pipe3[A, B, C, T any](f func(A, B, C) *result.Result[*option.Option[T]]) *ios.IOPipe3[A, B, C, T]
io.Pipe3OfValue[A, B, C, T any](f func(A, B, C) T) *ios.IOPipe3[A, B, C, T]
io.Pipe3OfResult[A, B, C, T any](f func(A, B, C) *result.Result[T]) *ios.IOPipe3[A, B, C, T]
io.Pipe3OfOption[A, B, C, T any](f func(A, B, C) *option.Option[T]) *ios.IOPipe3[A, B, C, T]
io.Pipe4IO[A, B, C, D, T any](f func(A, B, C, D) types.IORunnable) *ios.IOPipe4[A, B, C, D, T]
io.Pipe4[A, B, C, D, T any](f func(A, B, C, D) *result.Result[*option.Option[T]]) *ios.IOPipe4[A, B, C, D, T]
io.Pipe4OfValue[A, B, C, D, T any](f func(A, B, C, D) T) *ios.IOPipe4[A, B, C, D, T]
io.Pipe4OfResult[A, B, C, D, T any](f func(A, B, C, D) *result.Result[T]) *ios.IOPipe4[A, B, C, D, T]
io.Pipe4OfOption[A, B, C, D, T any](f func(A, B, C, D) *option.Option[T]) *ios.IOPipe4[A, B, C, D, T]
io.Pipe5IO[A, B, C, D, E, T any](f func(A, B, C, D, E) types.IORunnable) *ios.IOPipe5[A, B, C, D, E, T]
io.Pipe5[A, B, C, D, E, T any](f func(A, B, C, D, E) *result.Result[*option.Option[T]]) *ios.IOPipe5[A, B, C, D, E, T]
io.Pipe5OfValue[A, B, C, D, E, T any](f func(A, B, C, D, E) T) *ios.IOPipe5[A, B, C, D, E, T]
io.Pipe5OfResult[A, B, C, D, E, T any](f func(A, B, C, D, E) *result.Result[T]) *ios.IOPipe5[A, B, C, D, E, T]
io.Pipe5OfOption[A, B, C, D, E, T any](f func(A, B, C, D, E) *option.Option[T]) *ios.IOPipe5[A, B, C, D, E, T]
io.Pipe6IO[A, B, C, D, E, F, T any](f func(A, B, C, D, E, F) types.IORunnable) *ios.IOPipe6[A, B, C, D, E, F, T]
io.Pipe6[A, B, C, D, E, F, T any](f func(A, B, C, D, E, F) *result.Result[*option.Option[T]]) *ios.IOPipe6[A, B, C, D, E, F, T]
io.Pipe6OfValue[A, B, C, D, E, F, T any](f func(A, B, C, D, E, F) T) *ios.IOPipe6[A, B, C, D, E, F, T]
io.Pipe6OfResult[A, B, C, D, E, F, T any](f func(A, B, C, D, E, F) *result.Result[T]) *ios.IOPipe6[A, B, C, D, E, F, T]
io.Pipe6OfOption[A, B, C, D, E, F, T any](f func(A, B, C, D, E, F) *option.Option[T]) *ios.IOPipe6[A, B, C, D, E, F, T]
io.Pipe7IO[A, B, C, D, E, F, G, T any](f func(A, B, C, D, E, F, G) types.IORunnable) *ios.IOPipe7[A, B, C, D, E, F, G, T]
io.Pipe7[A, B, C, D, E, F, G, T any](f func(A, B, C, D, E, F, G) *result.Result[*option.Option[T]]) *ios.IOPipe7[A, B, C, D, E, F, G, T]
io.Pipe7OfValue[A, B, C, D, E, F, G, T any](f func(A, B, C, D, E, F, G) T) *ios.IOPipe7[A, B, C, D, E, F, G, T]
io.Pipe7OfResult[A, B, C, D, E, F, G, T any](f func(A, B, C, D, E, F, G) *result.Result[T]) *ios.IOPipe7[A, B, C, D, E, F, G, T]
io.Pipe7OfOption[A, B, C, D, E, F, G, T any](f func(A, B, C, D, E, F, G) *option.Option[T]) *ios.IOPipe7[A, B, C, D, E, F, G, T]
io.Pipe8IO[A, B, C, D, E, F, G, H, T any](f func(A, B, C, D, E, F, G, H) types.IORunnable) *ios.IOPipe8[A, B, C, D, E, F, G, H, T]
io.Pipe8[A, B, C, D, E, F, G, H, T any](f func(A, B, C, D, E, F, G, H) *result.Result[*option.Option[T]]) *ios.IOPipe8[A, B, C, D, E, F, G, H, T]
io.Pipe8OfValue[A, B, C, D, E, F, G, H, T any](f func(A, B, C, D, E, F, G, H) T) *ios.IOPipe8[A, B, C, D, E, F, G, H, T]
io.Pipe8OfResult[A, B, C, D, E, F, G, H, T any](f func(A, B, C, D, E, F, G, H) *result.Result[T]) *ios.IOPipe8[A, B, C, D, E, F, G, H, T]
io.Pipe8OfOption[A, B, C, D, E, F, G, H, T any](f func(A, B, C, D, E, F, G, H) *option.Option[T]) *ios.IOPipe8[A, B, C, D, E, F, G, H, T]
io.Pipe9IO[A, B, C, D, E, F, G, H, I, T any](f func(A, B, C, D, E, F, G, H, I) types.IORunnable) *ios.IOPipe9[A, B, C, D, E, F, G, H, I, T]
io.Pipe9[A, B, C, D, E, F, G, H, I, T any](f func(A, B, C, D, E, F, G, H, I) *result.Result[*option.Option[T]]) *ios.IOPipe9[A, B, C, D, E, F, G, H, I, T]
io.Pipe9OfValue[A, B, C, D, E, F, G, H, I, T any](f func(A, B, C, D, E, F, G, H, I) T) *ios.IOPipe9[A, B, C, D, E, F, G, H, I, T]
io.Pipe9OfResult[A, B, C, D, E, F, G, H, I, T any](f func(A, B, C, D, E, F, G, H, I) *result.Result[T]) *ios.IOPipe9[A, B, C, D, E, F, G, H, I, T]
io.Pipe9OfOption[A, B, C, D, E, F, G, H, I, T any](f func(A, B, C, D, E, F, G, H, I) *option.Option[T]) *ios.IOPipe9[A, B, C, D, E, F, G, H, I, T]
io.Pipe10IO[A, B, C, D, E, F, G, H, I, J, T any](f func(A, B, C, D, E, F, G, H, I, J) types.IORunnable) *ios.IOPipe10[A, B, C, D, E, F, G, H, I, J, T]
io.Pipe10[A, B, C, D, E, F, G, H, I, J, T any](f func(A, B, C, D, E, F, G, H, I, J) *result.Result[*option.Option[T]]) *ios.IOPipe10[A, B, C, D, E, F, G, H, I, J, T]
io.Pipe10OfValue[A, B, C, D, E, F, G, H, I, J, T any](f func(A, B, C, D, E, F, G, H, I, J) T) *ios.IOPipe10[A, B, C, D, E, F, G, H, I, J, T]
io.Pipe10OfResult[A, B, C, D, E, F, G, H, I, J, T any](f func(A, B, C, D, E, F, G, H, I, J) *result.Result[T]) *ios.IOPipe10[A, B, C, D, E, F, G, H, I, J, T]
io.Pipe10OfOption[A, B, C, D, E, F, G, H, I, J, T any](f func(A, B, C, D, E, F, G, H, I, J) *option.Option[T]) *ios.IOPipe10[A, B, C, D, E, F, G, H, I, J, T]

Documentation

The Go Gopher

There is no documentation for this package.

Directories

Path Synopsis
io
ios

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL