mirror of
https://github.com/IBM/fp-go.git
synced 2025-08-30 19:52:00 +02:00
Compare commits
23 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
e7428549e4 | ||
|
aef0048119 | ||
|
709d74b135 | ||
|
38c6541254 | ||
|
813b83b423 | ||
|
9139dedbbe | ||
|
5e15119653 | ||
|
986aa21055 | ||
|
3a4c46ec1e | ||
|
96c3ee20ff | ||
|
7af9acfd99 | ||
|
36eefbcd27 | ||
|
973138c822 | ||
|
12ef79184b | ||
|
5ac47440a1 | ||
|
3aa55c74d4 | ||
|
a6f55a199c | ||
|
2b500d15da | ||
|
599b8256b6 | ||
|
cf70b47984 | ||
|
7bceb856f8 | ||
|
49e89de783 | ||
|
a87de2f644 |
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
@@ -60,7 +60,7 @@ jobs:
|
|||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Set up Node.js ${{ env.NODE_VERSION }}
|
- name: Set up Node.js ${{ env.NODE_VERSION }}
|
||||||
uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0
|
uses: actions/setup-node@b39b52d1213e96004bfcb1c61a8a6fa8ab84f3e8 # v4.0.1
|
||||||
with:
|
with:
|
||||||
node-version: ${{ env.NODE_VERSION }}
|
node-version: ${{ env.NODE_VERSION }}
|
||||||
|
|
||||||
|
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,3 +1,4 @@
|
|||||||
fp-go.exe
|
fp-go.exe
|
||||||
main.exe
|
main.exe
|
||||||
build/
|
build/
|
||||||
|
.idea
|
@@ -17,6 +17,7 @@ package array
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
G "github.com/IBM/fp-go/array/generic"
|
G "github.com/IBM/fp-go/array/generic"
|
||||||
|
EM "github.com/IBM/fp-go/endomorphism"
|
||||||
F "github.com/IBM/fp-go/function"
|
F "github.com/IBM/fp-go/function"
|
||||||
"github.com/IBM/fp-go/internal/array"
|
"github.com/IBM/fp-go/internal/array"
|
||||||
M "github.com/IBM/fp-go/monoid"
|
M "github.com/IBM/fp-go/monoid"
|
||||||
@@ -89,16 +90,16 @@ func filterMapRef[A, B any](fa []A, pred func(a *A) bool, f func(a *A) B) []B {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Filter returns a new array with all elements from the original array that match a predicate
|
// Filter returns a new array with all elements from the original array that match a predicate
|
||||||
func Filter[A any](pred func(A) bool) func([]A) []A {
|
func Filter[A any](pred func(A) bool) EM.Endomorphism[[]A] {
|
||||||
return G.Filter[[]A](pred)
|
return G.Filter[[]A](pred)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FilterWithIndex returns a new array with all elements from the original array that match a predicate
|
// FilterWithIndex returns a new array with all elements from the original array that match a predicate
|
||||||
func FilterWithIndex[A any](pred func(int, A) bool) func([]A) []A {
|
func FilterWithIndex[A any](pred func(int, A) bool) EM.Endomorphism[[]A] {
|
||||||
return G.FilterWithIndex[[]A](pred)
|
return G.FilterWithIndex[[]A](pred)
|
||||||
}
|
}
|
||||||
|
|
||||||
func FilterRef[A any](pred func(*A) bool) func([]A) []A {
|
func FilterRef[A any](pred func(*A) bool) EM.Endomorphism[[]A] {
|
||||||
return F.Bind2nd(filterRef[A], pred)
|
return F.Bind2nd(filterRef[A], pred)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -227,7 +228,7 @@ func Last[A any](as []A) O.Option[A] {
|
|||||||
return G.Last(as)
|
return G.Last(as)
|
||||||
}
|
}
|
||||||
|
|
||||||
func PrependAll[A any](middle A) func([]A) []A {
|
func PrependAll[A any](middle A) EM.Endomorphism[[]A] {
|
||||||
return func(as []A) []A {
|
return func(as []A) []A {
|
||||||
count := len(as)
|
count := len(as)
|
||||||
dst := count * 2
|
dst := count * 2
|
||||||
@@ -242,7 +243,7 @@ func PrependAll[A any](middle A) func([]A) []A {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func Intersperse[A any](middle A) func([]A) []A {
|
func Intersperse[A any](middle A) EM.Endomorphism[[]A] {
|
||||||
prepend := PrependAll(middle)
|
prepend := PrependAll(middle)
|
||||||
return func(as []A) []A {
|
return func(as []A) []A {
|
||||||
if IsEmpty(as) {
|
if IsEmpty(as) {
|
||||||
@@ -271,7 +272,7 @@ func Lookup[A any](idx int) func([]A) O.Option[A] {
|
|||||||
return G.Lookup[[]A](idx)
|
return G.Lookup[[]A](idx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func UpsertAt[A any](a A) func([]A) []A {
|
func UpsertAt[A any](a A) EM.Endomorphism[[]A] {
|
||||||
return G.UpsertAt[[]A](a)
|
return G.UpsertAt[[]A](a)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -304,7 +305,7 @@ func ConstNil[A any]() []A {
|
|||||||
return array.ConstNil[[]A]()
|
return array.ConstNil[[]A]()
|
||||||
}
|
}
|
||||||
|
|
||||||
func SliceRight[A any](start int) func([]A) []A {
|
func SliceRight[A any](start int) EM.Endomorphism[[]A] {
|
||||||
return G.SliceRight[[]A](start)
|
return G.SliceRight[[]A](start)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -333,8 +334,8 @@ func Fold[A any](m M.Monoid[A]) func([]A) A {
|
|||||||
return G.Fold[[]A](m)
|
return G.Fold[[]A](m)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Push[A any](a A) func([]A) []A {
|
func Push[A any](a A) EM.Endomorphism[[]A] {
|
||||||
return G.Push[[]A](a)
|
return G.Push[EM.Endomorphism[[]A]](a)
|
||||||
}
|
}
|
||||||
|
|
||||||
func MonadFlap[B, A any](fab []func(A) B, a A) []B {
|
func MonadFlap[B, A any](fab []func(A) B, a A) []B {
|
||||||
@@ -344,3 +345,7 @@ func MonadFlap[B, A any](fab []func(A) B, a A) []B {
|
|||||||
func Flap[B, A any](a A) func([]func(A) B) []B {
|
func Flap[B, A any](a A) func([]func(A) B) []B {
|
||||||
return G.Flap[func(A) B, []func(A) B, []B, A, B](a)
|
return G.Flap[func(A) B, []func(A) B, []B, A, B](a)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Prepend[A any](head A) EM.Endomorphism[[]A] {
|
||||||
|
return G.Prepend[EM.Endomorphism[[]A]](head)
|
||||||
|
}
|
||||||
|
@@ -335,7 +335,7 @@ func Fold[AS ~[]A, A any](m M.Monoid[A]) func(AS) A {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func Push[GA ~[]A, A any](a A) func(GA) GA {
|
func Push[ENDO ~func(GA) GA, GA ~[]A, A any](a A) ENDO {
|
||||||
return F.Bind2nd(array.Push[GA, A], a)
|
return F.Bind2nd(array.Push[GA, A], a)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -346,3 +346,7 @@ func MonadFlap[FAB ~func(A) B, GFAB ~[]FAB, GB ~[]B, A, B any](fab GFAB, a A) GB
|
|||||||
func Flap[FAB ~func(A) B, GFAB ~[]FAB, GB ~[]B, A, B any](a A) func(GFAB) GB {
|
func Flap[FAB ~func(A) B, GFAB ~[]FAB, GB ~[]B, A, B any](a A) func(GFAB) GB {
|
||||||
return F.Bind2nd(MonadFlap[FAB, GFAB, GB, A, B], a)
|
return F.Bind2nd(MonadFlap[FAB, GFAB, GB, A, B], a)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Prepend[ENDO ~func(AS) AS, AS []A, A any](head A) ENDO {
|
||||||
|
return array.Prepend[ENDO](head)
|
||||||
|
}
|
||||||
|
@@ -17,6 +17,7 @@ package nonempty
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
G "github.com/IBM/fp-go/array/generic"
|
G "github.com/IBM/fp-go/array/generic"
|
||||||
|
EM "github.com/IBM/fp-go/endomorphism"
|
||||||
F "github.com/IBM/fp-go/function"
|
F "github.com/IBM/fp-go/function"
|
||||||
"github.com/IBM/fp-go/internal/array"
|
"github.com/IBM/fp-go/internal/array"
|
||||||
S "github.com/IBM/fp-go/semigroup"
|
S "github.com/IBM/fp-go/semigroup"
|
||||||
@@ -65,6 +66,12 @@ func Reduce[A, B any](f func(B, A) B, initial B) func(NonEmptyArray[A]) B {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ReduceRight[A, B any](f func(A, B) B, initial B) func(NonEmptyArray[A]) B {
|
||||||
|
return func(as NonEmptyArray[A]) B {
|
||||||
|
return array.ReduceRight(as, f, initial)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func Tail[A any](as NonEmptyArray[A]) []A {
|
func Tail[A any](as NonEmptyArray[A]) []A {
|
||||||
return as[1:]
|
return as[1:]
|
||||||
}
|
}
|
||||||
@@ -122,3 +129,8 @@ func Fold[A any](s S.Semigroup[A]) func(NonEmptyArray[A]) A {
|
|||||||
return array.Reduce(Tail(as), s.Concat, Head(as))
|
return array.Reduce(Tail(as), s.Concat, Head(as))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Prepend prepends a single value to an array
|
||||||
|
func Prepend[A any](head A) EM.Endomorphism[NonEmptyArray[A]] {
|
||||||
|
return array.Prepend[EM.Endomorphism[NonEmptyArray[A]]](head)
|
||||||
|
}
|
||||||
|
@@ -34,5 +34,6 @@ func Commands() []*C.Command {
|
|||||||
IOEitherCommand(),
|
IOEitherCommand(),
|
||||||
IOCommand(),
|
IOCommand(),
|
||||||
IOOptionCommand(),
|
IOOptionCommand(),
|
||||||
|
DICommand(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
231
cli/di.go
Normal file
231
cli/di.go
Normal file
@@ -0,0 +1,231 @@
|
|||||||
|
// Copyright (c) 2023 IBM Corp.
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package cli
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
C "github.com/urfave/cli/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func generateMakeProvider(f *os.File, i int) {
|
||||||
|
// non generic version
|
||||||
|
fmt.Fprintf(f, "\n// MakeProvider%d creates a [DIE.Provider] for an [InjectionToken] from a function with %d dependencies\n", i, i)
|
||||||
|
fmt.Fprintf(f, "func MakeProvider%d[", i)
|
||||||
|
for j := 0; j < i; j++ {
|
||||||
|
if j > 0 {
|
||||||
|
fmt.Fprintf(f, ", ")
|
||||||
|
}
|
||||||
|
fmt.Fprintf(f, "T%d", j+1)
|
||||||
|
}
|
||||||
|
fmt.Fprintf(f, " any, R any](\n")
|
||||||
|
fmt.Fprintf(f, " token InjectionToken[R],\n")
|
||||||
|
for j := 0; j < i; j++ {
|
||||||
|
fmt.Fprintf(f, " d%d Dependency[T%d],\n", j+1, j+1)
|
||||||
|
}
|
||||||
|
fmt.Fprintf(f, " f func(")
|
||||||
|
for j := 0; j < i; j++ {
|
||||||
|
if j > 0 {
|
||||||
|
fmt.Fprintf(f, ", ")
|
||||||
|
}
|
||||||
|
fmt.Fprintf(f, "T%d", j+1)
|
||||||
|
}
|
||||||
|
fmt.Fprintf(f, ") IOE.IOEither[error, R],\n")
|
||||||
|
fmt.Fprintf(f, ") DIE.Provider {\n")
|
||||||
|
fmt.Fprint(f, " return DIE.MakeProvider(\n")
|
||||||
|
fmt.Fprint(f, " token,\n")
|
||||||
|
fmt.Fprintf(f, " MakeProviderFactory%d(\n", i)
|
||||||
|
for j := 0; j < i; j++ {
|
||||||
|
fmt.Fprintf(f, " d%d,\n", j+1)
|
||||||
|
}
|
||||||
|
fmt.Fprint(f, " f,\n")
|
||||||
|
fmt.Fprint(f, " ))\n")
|
||||||
|
fmt.Fprintf(f, "}\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateMakeTokenWithDefault(f *os.File, i int) {
|
||||||
|
// non generic version
|
||||||
|
fmt.Fprintf(f, "\n// MakeTokenWithDefault%d creates an [InjectionToken] with a default implementation with %d dependencies\n", i, i)
|
||||||
|
fmt.Fprintf(f, "func MakeTokenWithDefault%d[", i)
|
||||||
|
for j := 0; j < i; j++ {
|
||||||
|
if j > 0 {
|
||||||
|
fmt.Fprintf(f, ", ")
|
||||||
|
}
|
||||||
|
fmt.Fprintf(f, "T%d", j+1)
|
||||||
|
}
|
||||||
|
fmt.Fprintf(f, " any, R any](\n")
|
||||||
|
fmt.Fprintf(f, " name string,\n")
|
||||||
|
for j := 0; j < i; j++ {
|
||||||
|
fmt.Fprintf(f, " d%d Dependency[T%d],\n", j+1, j+1)
|
||||||
|
}
|
||||||
|
fmt.Fprintf(f, " f func(")
|
||||||
|
for j := 0; j < i; j++ {
|
||||||
|
if j > 0 {
|
||||||
|
fmt.Fprintf(f, ", ")
|
||||||
|
}
|
||||||
|
fmt.Fprintf(f, "T%d", j+1)
|
||||||
|
}
|
||||||
|
fmt.Fprintf(f, ") IOE.IOEither[error, R],\n")
|
||||||
|
fmt.Fprintf(f, ") InjectionToken[R] {\n")
|
||||||
|
fmt.Fprintf(f, " return MakeTokenWithDefault[R](name, MakeProviderFactory%d(\n", i)
|
||||||
|
for j := 0; j < i; j++ {
|
||||||
|
fmt.Fprintf(f, " d%d,\n", j+1)
|
||||||
|
}
|
||||||
|
fmt.Fprint(f, " f,\n")
|
||||||
|
fmt.Fprint(f, " ))\n")
|
||||||
|
fmt.Fprintf(f, "}\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateMakeProviderFactory(f *os.File, i int) {
|
||||||
|
// non generic version
|
||||||
|
fmt.Fprintf(f, "\n// MakeProviderFactory%d creates a [DIE.ProviderFactory] from a function with %d arguments and %d dependencies\n", i, i, i)
|
||||||
|
fmt.Fprintf(f, "func MakeProviderFactory%d[", i)
|
||||||
|
for j := 0; j < i; j++ {
|
||||||
|
if j > 0 {
|
||||||
|
fmt.Fprintf(f, ", ")
|
||||||
|
}
|
||||||
|
fmt.Fprintf(f, "T%d", j+1)
|
||||||
|
}
|
||||||
|
fmt.Fprintf(f, " any, R any](\n")
|
||||||
|
for j := 0; j < i; j++ {
|
||||||
|
fmt.Fprintf(f, " d%d Dependency[T%d],\n", j+1, j+1)
|
||||||
|
}
|
||||||
|
fmt.Fprintf(f, " f func(")
|
||||||
|
for j := 0; j < i; j++ {
|
||||||
|
if j > 0 {
|
||||||
|
fmt.Fprintf(f, ", ")
|
||||||
|
}
|
||||||
|
fmt.Fprintf(f, "T%d", j+1)
|
||||||
|
}
|
||||||
|
fmt.Fprintf(f, ") IOE.IOEither[error, R],\n")
|
||||||
|
fmt.Fprintf(f, ") DIE.ProviderFactory {\n")
|
||||||
|
fmt.Fprint(f, " return DIE.MakeProviderFactory(\n")
|
||||||
|
fmt.Fprint(f, " A.From[DIE.Dependency](\n")
|
||||||
|
for j := 0; j < i; j++ {
|
||||||
|
fmt.Fprintf(f, " d%d,\n", j+1)
|
||||||
|
}
|
||||||
|
fmt.Fprint(f, " ),\n")
|
||||||
|
fmt.Fprintf(f, " eraseProviderFactory%d(\n", i)
|
||||||
|
for j := 0; j < i; j++ {
|
||||||
|
fmt.Fprintf(f, " d%d,\n", j+1)
|
||||||
|
}
|
||||||
|
fmt.Fprint(f, " f,\n")
|
||||||
|
fmt.Fprint(f, " ),\n")
|
||||||
|
fmt.Fprint(f, " )\n")
|
||||||
|
fmt.Fprintf(f, "}\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateEraseProviderFactory(f *os.File, i int) {
|
||||||
|
// non generic version
|
||||||
|
fmt.Fprintf(f, "\n// eraseProviderFactory%d creates a function that takes a variadic number of untyped arguments and from a function of %d strongly typed arguments and %d dependencies\n", i, i, i)
|
||||||
|
fmt.Fprintf(f, "func eraseProviderFactory%d[", i)
|
||||||
|
for j := 0; j < i; j++ {
|
||||||
|
if j > 0 {
|
||||||
|
fmt.Fprintf(f, ", ")
|
||||||
|
}
|
||||||
|
fmt.Fprintf(f, "T%d", j+1)
|
||||||
|
}
|
||||||
|
fmt.Fprintf(f, " any, R any](\n")
|
||||||
|
for j := 0; j < i; j++ {
|
||||||
|
fmt.Fprintf(f, " d%d Dependency[T%d],\n", j+1, j+1)
|
||||||
|
}
|
||||||
|
fmt.Fprintf(f, " f func(")
|
||||||
|
for j := 0; j < i; j++ {
|
||||||
|
if j > 0 {
|
||||||
|
fmt.Fprintf(f, ", ")
|
||||||
|
}
|
||||||
|
fmt.Fprintf(f, "T%d", j+1)
|
||||||
|
}
|
||||||
|
fmt.Fprintf(f, ") IOE.IOEither[error, R]) func(params ...any) IOE.IOEither[error, any] {\n")
|
||||||
|
fmt.Fprintf(f, " ft := eraseTuple(T.Tupled%d(f))\n", i)
|
||||||
|
for j := 0; j < i; j++ {
|
||||||
|
fmt.Fprintf(f, " t%d := lookupAt[T%d](%d, d%d)\n", j+1, j+1, j, j+1)
|
||||||
|
}
|
||||||
|
fmt.Fprint(f, " return func(params ...any) IOE.IOEither[error, any] {\n")
|
||||||
|
fmt.Fprintf(f, " return ft(E.SequenceT%d(\n", i)
|
||||||
|
for j := 0; j < i; j++ {
|
||||||
|
fmt.Fprintf(f, " t%d(params),\n", j+1)
|
||||||
|
}
|
||||||
|
fmt.Fprint(f, " ))\n")
|
||||||
|
fmt.Fprint(f, " }\n")
|
||||||
|
fmt.Fprintf(f, "}\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateDIHelpers(filename string, count int) error {
|
||||||
|
dir, err := os.Getwd()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
absDir, err := filepath.Abs(dir)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
pkg := filepath.Base(absDir)
|
||||||
|
f, err := os.Create(filepath.Clean(filename))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
// log
|
||||||
|
log.Printf("Generating code in [%s] for package [%s] with [%d] repetitions ...", filename, pkg, count)
|
||||||
|
|
||||||
|
// some header
|
||||||
|
fmt.Fprintln(f, "// Code generated by go generate; DO NOT EDIT.")
|
||||||
|
fmt.Fprintln(f, "// This file was generated by robots at")
|
||||||
|
fmt.Fprintf(f, "// %s\n\n", time.Now())
|
||||||
|
|
||||||
|
fmt.Fprintf(f, "package %s\n\n", pkg)
|
||||||
|
|
||||||
|
fmt.Fprint(f, `
|
||||||
|
import (
|
||||||
|
E "github.com/IBM/fp-go/either"
|
||||||
|
IOE "github.com/IBM/fp-go/ioeither"
|
||||||
|
T "github.com/IBM/fp-go/tuple"
|
||||||
|
A "github.com/IBM/fp-go/array"
|
||||||
|
DIE "github.com/IBM/fp-go/di/erasure"
|
||||||
|
)
|
||||||
|
`)
|
||||||
|
|
||||||
|
for i := 1; i <= count; i++ {
|
||||||
|
generateEraseProviderFactory(f, i)
|
||||||
|
generateMakeProviderFactory(f, i)
|
||||||
|
generateMakeTokenWithDefault(f, i)
|
||||||
|
generateMakeProvider(f, i)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func DICommand() *C.Command {
|
||||||
|
return &C.Command{
|
||||||
|
Name: "di",
|
||||||
|
Usage: "generate code for the dependency injection package",
|
||||||
|
Flags: []C.Flag{
|
||||||
|
flagCount,
|
||||||
|
flagFilename,
|
||||||
|
},
|
||||||
|
Action: func(ctx *C.Context) error {
|
||||||
|
return generateDIHelpers(
|
||||||
|
ctx.String(keyFilename),
|
||||||
|
ctx.Int(keyCount),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
28
cli/pipe.go
28
cli/pipe.go
@@ -295,15 +295,16 @@ func recurseCurry(f *os.File, indent string, total, count int) {
|
|||||||
func generateCurry(f *os.File, i int) {
|
func generateCurry(f *os.File, i int) {
|
||||||
// Create the curry version
|
// Create the curry version
|
||||||
fmt.Fprintf(f, "\n// Curry%d takes a function with %d parameters and returns a cascade of functions each taking only one parameter.\n// The inverse function is [Uncurry%d]\n", i, i, i)
|
fmt.Fprintf(f, "\n// Curry%d takes a function with %d parameters and returns a cascade of functions each taking only one parameter.\n// The inverse function is [Uncurry%d]\n", i, i, i)
|
||||||
fmt.Fprintf(f, "func Curry%d[T0", i)
|
fmt.Fprintf(f, "func Curry%d[FCT ~func(T0", i)
|
||||||
for j := 1; j <= i; j++ {
|
for j := 1; j < i; j++ {
|
||||||
fmt.Fprintf(f, ", T%d", j)
|
fmt.Fprintf(f, ", T%d", j)
|
||||||
}
|
}
|
||||||
fmt.Fprintf(f, " any](f func(T0")
|
fmt.Fprintf(f, ") T%d", i)
|
||||||
for j := 2; j <= i; j++ {
|
// type arguments
|
||||||
fmt.Fprintf(f, ", T%d", j-1)
|
for j := 0; j <= i; j++ {
|
||||||
|
fmt.Fprintf(f, ", T%d", j)
|
||||||
}
|
}
|
||||||
fmt.Fprintf(f, ") T%d) func(T0)", i)
|
fmt.Fprintf(f, " any](f FCT) func(T0)")
|
||||||
for j := 2; j <= i; j++ {
|
for j := 2; j <= i; j++ {
|
||||||
fmt.Fprintf(f, " func(T%d)", j-1)
|
fmt.Fprintf(f, " func(T%d)", j-1)
|
||||||
}
|
}
|
||||||
@@ -315,15 +316,16 @@ func generateCurry(f *os.File, i int) {
|
|||||||
func generateUncurry(f *os.File, i int) {
|
func generateUncurry(f *os.File, i int) {
|
||||||
// Create the uncurry version
|
// Create the uncurry version
|
||||||
fmt.Fprintf(f, "\n// Uncurry%d takes a cascade of %d functions each taking only one parameter and returns a function with %d parameters .\n// The inverse function is [Curry%d]\n", i, i, i, i)
|
fmt.Fprintf(f, "\n// Uncurry%d takes a cascade of %d functions each taking only one parameter and returns a function with %d parameters .\n// The inverse function is [Curry%d]\n", i, i, i, i)
|
||||||
fmt.Fprintf(f, "func Uncurry%d[T0", i)
|
fmt.Fprintf(f, "func Uncurry%d[FCT ~func(T0)", i)
|
||||||
for j := 1; j <= i; j++ {
|
for j := 1; j < i; j++ {
|
||||||
|
fmt.Fprintf(f, " func(T%d)", j)
|
||||||
|
}
|
||||||
|
fmt.Fprintf(f, " T%d", i)
|
||||||
|
// the type parameters
|
||||||
|
for j := 0; j <= i; j++ {
|
||||||
fmt.Fprintf(f, ", T%d", j)
|
fmt.Fprintf(f, ", T%d", j)
|
||||||
}
|
}
|
||||||
fmt.Fprintf(f, " any](f")
|
fmt.Fprintf(f, " any](f FCT) func(")
|
||||||
for j := 1; j <= i; j++ {
|
|
||||||
fmt.Fprintf(f, " func(T%d)", j-1)
|
|
||||||
}
|
|
||||||
fmt.Fprintf(f, " T%d) func(", i)
|
|
||||||
for j := 1; j <= i; j++ {
|
for j := 1; j <= i; j++ {
|
||||||
if j > 1 {
|
if j > 1 {
|
||||||
fmt.Fprintf(f, ", ")
|
fmt.Fprintf(f, ", ")
|
||||||
|
72
context/readerioeither/http/builder/builder.go
Normal file
72
context/readerioeither/http/builder/builder.go
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
// Copyright (c) 2023 IBM Corp.
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package builder
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
RIOE "github.com/IBM/fp-go/context/readerioeither"
|
||||||
|
RIOEH "github.com/IBM/fp-go/context/readerioeither/http"
|
||||||
|
E "github.com/IBM/fp-go/either"
|
||||||
|
F "github.com/IBM/fp-go/function"
|
||||||
|
R "github.com/IBM/fp-go/http/builder"
|
||||||
|
H "github.com/IBM/fp-go/http/headers"
|
||||||
|
LZ "github.com/IBM/fp-go/lazy"
|
||||||
|
O "github.com/IBM/fp-go/option"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Requester(builder *R.Builder) RIOEH.Requester {
|
||||||
|
|
||||||
|
withBody := F.Curry3(func(data []byte, url string, method string) RIOE.ReaderIOEither[*http.Request] {
|
||||||
|
return RIOE.TryCatch(func(ctx context.Context) func() (*http.Request, error) {
|
||||||
|
return func() (*http.Request, error) {
|
||||||
|
req, err := http.NewRequestWithContext(ctx, method, url, bytes.NewReader(data))
|
||||||
|
if err == nil {
|
||||||
|
req.Header.Set(H.ContentLength, strconv.Itoa(len(data)))
|
||||||
|
H.Monoid.Concat(req.Header, builder.GetHeaders())
|
||||||
|
}
|
||||||
|
return req, err
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
withoutBody := F.Curry2(func(url string, method string) RIOE.ReaderIOEither[*http.Request] {
|
||||||
|
return RIOE.TryCatch(func(ctx context.Context) func() (*http.Request, error) {
|
||||||
|
return func() (*http.Request, error) {
|
||||||
|
req, err := http.NewRequestWithContext(ctx, method, url, nil)
|
||||||
|
if err == nil {
|
||||||
|
H.Monoid.Concat(req.Header, builder.GetHeaders())
|
||||||
|
}
|
||||||
|
return req, err
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
return F.Pipe5(
|
||||||
|
builder.GetBody(),
|
||||||
|
O.Fold(LZ.Of(E.Of[error](withoutBody)), E.Map[error](withBody)),
|
||||||
|
E.Ap[func(string) RIOE.ReaderIOEither[*http.Request]](builder.GetTargetUrl()),
|
||||||
|
E.Flap[error, RIOE.ReaderIOEither[*http.Request]](builder.GetMethod()),
|
||||||
|
E.GetOrElse(RIOE.Left[*http.Request]),
|
||||||
|
RIOE.Map(func(req *http.Request) *http.Request {
|
||||||
|
req.Header = H.Monoid.Concat(req.Header, builder.GetHeaders())
|
||||||
|
return req
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
}
|
59
context/readerioeither/http/builder/builder_test.go
Normal file
59
context/readerioeither/http/builder/builder_test.go
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
// Copyright (c) 2023 IBM Corp.
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package builder
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
RIOE "github.com/IBM/fp-go/context/readerioeither"
|
||||||
|
E "github.com/IBM/fp-go/either"
|
||||||
|
F "github.com/IBM/fp-go/function"
|
||||||
|
R "github.com/IBM/fp-go/http/builder"
|
||||||
|
IO "github.com/IBM/fp-go/io"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestBuilderWithQuery(t *testing.T) {
|
||||||
|
// add some query
|
||||||
|
withLimit := R.WithQueryArg("limit")("10")
|
||||||
|
withUrl := R.WithUrl("http://www.example.org?a=b")
|
||||||
|
|
||||||
|
b := F.Pipe2(
|
||||||
|
R.Default,
|
||||||
|
withLimit,
|
||||||
|
withUrl,
|
||||||
|
)
|
||||||
|
|
||||||
|
req := F.Pipe3(
|
||||||
|
b,
|
||||||
|
Requester,
|
||||||
|
RIOE.Map(func(r *http.Request) *url.URL {
|
||||||
|
return r.URL
|
||||||
|
}),
|
||||||
|
RIOE.ChainFirstIOK(func(u *url.URL) IO.IO[any] {
|
||||||
|
return IO.FromImpure(func() {
|
||||||
|
q := u.Query()
|
||||||
|
assert.Equal(t, "10", q.Get("limit"))
|
||||||
|
assert.Equal(t, "b", q.Get("a"))
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
|
assert.True(t, E.IsRight(req(context.Background())()))
|
||||||
|
}
|
38
di/app.go
Normal file
38
di/app.go
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
// Copyright (c) 2023 IBM Corp.
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package di
|
||||||
|
|
||||||
|
import (
|
||||||
|
DIE "github.com/IBM/fp-go/di/erasure"
|
||||||
|
F "github.com/IBM/fp-go/function"
|
||||||
|
IO "github.com/IBM/fp-go/io"
|
||||||
|
IOE "github.com/IBM/fp-go/ioeither"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// InjMain is the [InjectionToken] for the main application
|
||||||
|
InjMain = MakeToken[any]("APP")
|
||||||
|
|
||||||
|
// Main is the resolver for the main application
|
||||||
|
Main = Resolve(InjMain)
|
||||||
|
)
|
||||||
|
|
||||||
|
// RunMain runs the main application from a set of [DIE.Provider]s
|
||||||
|
var RunMain = F.Flow3(
|
||||||
|
DIE.MakeInjector,
|
||||||
|
Main,
|
||||||
|
IOE.Fold(IO.Of[error], F.Constant1[any](IO.Of[error](nil))),
|
||||||
|
)
|
43
di/doc.go
Normal file
43
di/doc.go
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
// Copyright (c) 2023 IBM Corp.
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
// Package di implements functions and data types supporting dependency injection patterns
|
||||||
|
//
|
||||||
|
// The fundamental building block is the concept of a [Dependency]. This describes the abstract concept of a function, service or value together with its type.
|
||||||
|
// Examples for dependencies can be as simple as configuration values such as the API URL for a service, the current username, a [Dependency] could be the map
|
||||||
|
// of the configuration environment, an http client or as complex as a service interface. Important is that a [Dependency] only defines the concept but
|
||||||
|
// not the implementation.
|
||||||
|
//
|
||||||
|
// The implementation of a [Dependency] is called a [Provider], the dependency of an `API URL` could e.g. be realized by a provider that consults the environment to read the information
|
||||||
|
// or a config file or simply hardcode it.
|
||||||
|
// In many cases the implementation of a [Provider] depends in turn on other [Dependency] (but never directly on other [Provider]s), a provider for an `API URL` that reads
|
||||||
|
// the information from the environment would e.g. depend on a [Dependency] that represents this environment.
|
||||||
|
//
|
||||||
|
// It is the resposibility of the [InjectableFactory] to create an instance of a [Dependency]. All instances are considered singletons. Create an [InjectableFactory] via the [MakeInjector] method. Use [Resolve] to create a strongly typed
|
||||||
|
// factory for a particular [InjectionToken].
|
||||||
|
//
|
||||||
|
// In most cases it is not required to use [InjectableFactory] directly, instead you would create a [Provider] via the [MakeProvider2] method (suffix indicates the number of dependencies). In this call
|
||||||
|
// you give a number of (strongly typed) [Dependency] identifiers and a (strongly typed) factory function for the implementation. The dependency injection framework makes
|
||||||
|
// sure to resolve the dependencies before calling the factory method.
|
||||||
|
//
|
||||||
|
// For convenience purposes it can be helpful to attach a default implementation of a [Dependency]. In this case use the [MakeTokenWithDefault2] method (suffix indicates the number of dependencies)
|
||||||
|
// to define the [InjectionToken].
|
||||||
|
//
|
||||||
|
// [Provider]: [github.com/IBM/fp-go/di/erasure.Provider]
|
||||||
|
// [InjectableFactory]: [github.com/IBM/fp-go/di/erasure.InjectableFactory]
|
||||||
|
// [MakeInjector]: [github.com/IBM/fp-go/di/erasure.MakeInjector]
|
||||||
|
package di
|
||||||
|
|
||||||
|
//go:generate go run .. di --count 10 --filename gen.go
|
@@ -7,7 +7,6 @@
|
|||||||
//
|
//
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
//
|
//
|
||||||
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
@@ -115,6 +114,9 @@ func itemProviderFactory(fcts []ProviderFactory) ProviderFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// MakeInjector creates an [InjectableFactory] based on a set of [Provider]s
|
// MakeInjector creates an [InjectableFactory] based on a set of [Provider]s
|
||||||
|
//
|
||||||
|
// The resulting [InjectableFactory] can then be used to retrieve service instances given their [Dependency]. The implementation
|
||||||
|
// makes sure to transitively resolve the required dependencies.
|
||||||
func MakeInjector(providers []Provider) InjectableFactory {
|
func MakeInjector(providers []Provider) InjectableFactory {
|
||||||
|
|
||||||
type Result = IOE.IOEither[error, any]
|
type Result = IOE.IOEither[error, any]
|
||||||
|
@@ -31,25 +31,29 @@ import (
|
|||||||
R "github.com/IBM/fp-go/record"
|
R "github.com/IBM/fp-go/record"
|
||||||
)
|
)
|
||||||
|
|
||||||
type InjectableFactory = func(Dependency) IOE.IOEither[error, any]
|
type (
|
||||||
type ProviderFactory = func(InjectableFactory) IOE.IOEither[error, any]
|
// InjectableFactory is a factory function that can create an untyped instance of a service based on its [Dependency] identifier
|
||||||
|
InjectableFactory = func(Dependency) IOE.IOEither[error, any]
|
||||||
|
ProviderFactory = func(InjectableFactory) IOE.IOEither[error, any]
|
||||||
|
|
||||||
type paramIndex = map[int]int
|
paramIndex = map[int]int
|
||||||
type paramValue = map[int]any
|
paramValue = map[int]any
|
||||||
type handler = func(paramIndex) func([]IOE.IOEither[error, any]) IOE.IOEither[error, paramValue]
|
handler = func(paramIndex) func([]IOE.IOEither[error, any]) IOE.IOEither[error, paramValue]
|
||||||
|
mapping = map[int]paramIndex
|
||||||
|
|
||||||
type Provider interface {
|
Provider interface {
|
||||||
fmt.Stringer
|
fmt.Stringer
|
||||||
// Provides returns the [Dependency] implemented by this provider
|
// Provides returns the [Dependency] implemented by this provider
|
||||||
Provides() Dependency
|
Provides() Dependency
|
||||||
// Factory returns s function that can create an instance of the dependency based on an [InjectableFactory]
|
// Factory returns s function that can create an instance of the dependency based on an [InjectableFactory]
|
||||||
Factory() ProviderFactory
|
Factory() ProviderFactory
|
||||||
}
|
}
|
||||||
|
|
||||||
type provider struct {
|
provider struct {
|
||||||
provides Dependency
|
provides Dependency
|
||||||
factory ProviderFactory
|
factory ProviderFactory
|
||||||
}
|
}
|
||||||
|
)
|
||||||
|
|
||||||
func (p *provider) Provides() Dependency {
|
func (p *provider) Provides() Dependency {
|
||||||
return p.provides
|
return p.provides
|
||||||
@@ -72,11 +76,16 @@ func mapFromToken(idx int, token Dependency) map[int]paramIndex {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
// Empty is the empty array of providers
|
||||||
|
Empty = A.Empty[Provider]()
|
||||||
|
|
||||||
mergeTokenMaps = R.UnionMonoid[int](R.UnionLastSemigroup[int, int]())
|
mergeTokenMaps = R.UnionMonoid[int](R.UnionLastSemigroup[int, int]())
|
||||||
foldDeps = A.FoldMapWithIndex[Dependency](mergeTokenMaps)(mapFromToken)
|
foldDeps = A.FoldMapWithIndex[Dependency](mergeTokenMaps)(mapFromToken)
|
||||||
mergeMaps = R.UnionLastMonoid[int, any]()
|
mergeMaps = R.UnionLastMonoid[int, any]()
|
||||||
collectParams = R.CollectOrd[any, any](Int.Ord)(F.SK[int, any])
|
collectParams = R.CollectOrd[any, any](Int.Ord)(F.SK[int, any])
|
||||||
|
|
||||||
|
mapDeps = F.Curry2(A.MonadMap[Dependency, IOE.IOEither[error, any]])
|
||||||
|
|
||||||
handlers = map[int]handler{
|
handlers = map[int]handler{
|
||||||
Identity: func(mp paramIndex) func([]IOE.IOEither[error, any]) IOE.IOEither[error, paramValue] {
|
Identity: func(mp paramIndex) func([]IOE.IOEither[error, any]) IOE.IOEither[error, paramValue] {
|
||||||
return func(res []IOE.IOEither[error, any]) IOE.IOEither[error, paramValue] {
|
return func(res []IOE.IOEither[error, any]) IOE.IOEither[error, paramValue] {
|
||||||
@@ -127,15 +136,13 @@ var (
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
type Mapping = map[int]paramIndex
|
|
||||||
|
|
||||||
func getAt[T any](ar []T) func(idx int) T {
|
func getAt[T any](ar []T) func(idx int) T {
|
||||||
return func(idx int) T {
|
return func(idx int) T {
|
||||||
return ar[idx]
|
return ar[idx]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleMapping(mp Mapping) func(res []IOE.IOEither[error, any]) IOE.IOEither[error, []any] {
|
func handleMapping(mp mapping) func(res []IOE.IOEither[error, any]) IOE.IOEither[error, []any] {
|
||||||
preFct := F.Pipe1(
|
preFct := F.Pipe1(
|
||||||
mp,
|
mp,
|
||||||
R.Collect(func(idx int, p paramIndex) func([]IOE.IOEither[error, any]) IOE.IOEither[error, paramValue] {
|
R.Collect(func(idx int, p paramIndex) func([]IOE.IOEither[error, any]) IOE.IOEither[error, paramValue] {
|
||||||
@@ -167,7 +174,7 @@ func MakeProviderFactory(
|
|||||||
fct func(param ...any) IOE.IOEither[error, any]) ProviderFactory {
|
fct func(param ...any) IOE.IOEither[error, any]) ProviderFactory {
|
||||||
|
|
||||||
return F.Flow3(
|
return F.Flow3(
|
||||||
F.Curry2(A.MonadMap[Dependency, IOE.IOEither[error, any]])(deps),
|
mapDeps(deps),
|
||||||
handleMapping(foldDeps(deps)),
|
handleMapping(foldDeps(deps)),
|
||||||
IOE.Chain(F.Unvariadic0(fct)),
|
IOE.Chain(F.Unvariadic0(fct)),
|
||||||
)
|
)
|
||||||
|
@@ -7,7 +7,6 @@
|
|||||||
//
|
//
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
//
|
//
|
||||||
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
234
di/provider.go
234
di/provider.go
@@ -12,6 +12,7 @@
|
|||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
package di
|
package di
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -21,7 +22,6 @@ import (
|
|||||||
"github.com/IBM/fp-go/errors"
|
"github.com/IBM/fp-go/errors"
|
||||||
F "github.com/IBM/fp-go/function"
|
F "github.com/IBM/fp-go/function"
|
||||||
IOE "github.com/IBM/fp-go/ioeither"
|
IOE "github.com/IBM/fp-go/ioeither"
|
||||||
T "github.com/IBM/fp-go/tuple"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func lookupAt[T any](idx int, token Dependency[T]) func(params []any) E.Either[error, T] {
|
func lookupAt[T any](idx int, token Dependency[T]) func(params []any) E.Either[error, T] {
|
||||||
@@ -32,89 +32,25 @@ func lookupAt[T any](idx int, token Dependency[T]) func(params []any) E.Either[e
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func eraseProviderFactory0[R any](f func() IOE.IOEither[error, R]) func(params ...any) IOE.IOEither[error, any] {
|
func eraseTuple[A, R any](f func(A) IOE.IOEither[error, R]) func(E.Either[error, A]) IOE.IOEither[error, any] {
|
||||||
|
return F.Flow3(
|
||||||
|
IOE.FromEither[error, A],
|
||||||
|
IOE.Chain(f),
|
||||||
|
IOE.Map[error](F.ToAny[R]),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func eraseProviderFactory0[R any](f IOE.IOEither[error, R]) func(params ...any) IOE.IOEither[error, any] {
|
||||||
return func(params ...any) IOE.IOEither[error, any] {
|
return func(params ...any) IOE.IOEither[error, any] {
|
||||||
return F.Pipe1(
|
return F.Pipe1(
|
||||||
f(),
|
f,
|
||||||
IOE.Map[error](F.ToAny[R]),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func eraseProviderFactory1[T1 any, R any](
|
|
||||||
d1 Dependency[T1],
|
|
||||||
f func(T1) IOE.IOEither[error, R]) func(params ...any) IOE.IOEither[error, any] {
|
|
||||||
ft := T.Tupled1(f)
|
|
||||||
t1 := lookupAt[T1](0, d1)
|
|
||||||
return func(params ...any) IOE.IOEither[error, any] {
|
|
||||||
return F.Pipe3(
|
|
||||||
E.SequenceT1(t1(params)),
|
|
||||||
IOE.FromEither[error, T.Tuple1[T1]],
|
|
||||||
IOE.Chain(ft),
|
|
||||||
IOE.Map[error](F.ToAny[R]),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func eraseProviderFactory2[T1, T2 any, R any](
|
|
||||||
d1 Dependency[T1],
|
|
||||||
d2 Dependency[T2],
|
|
||||||
f func(T1, T2) IOE.IOEither[error, R]) func(params ...any) IOE.IOEither[error, any] {
|
|
||||||
ft := T.Tupled2(f)
|
|
||||||
t1 := lookupAt[T1](0, d1)
|
|
||||||
t2 := lookupAt[T2](1, d2)
|
|
||||||
return func(params ...any) IOE.IOEither[error, any] {
|
|
||||||
return F.Pipe3(
|
|
||||||
E.SequenceT2(t1(params), t2(params)),
|
|
||||||
IOE.FromEither[error, T.Tuple2[T1, T2]],
|
|
||||||
IOE.Chain(ft),
|
|
||||||
IOE.Map[error](F.ToAny[R]),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func eraseProviderFactory3[T1, T2, T3 any, R any](
|
|
||||||
d1 Dependency[T1],
|
|
||||||
d2 Dependency[T2],
|
|
||||||
d3 Dependency[T3],
|
|
||||||
f func(T1, T2, T3) IOE.IOEither[error, R]) func(params ...any) IOE.IOEither[error, any] {
|
|
||||||
ft := T.Tupled3(f)
|
|
||||||
t1 := lookupAt[T1](0, d1)
|
|
||||||
t2 := lookupAt[T2](1, d2)
|
|
||||||
t3 := lookupAt[T3](2, d3)
|
|
||||||
return func(params ...any) IOE.IOEither[error, any] {
|
|
||||||
return F.Pipe3(
|
|
||||||
E.SequenceT3(t1(params), t2(params), t3(params)),
|
|
||||||
IOE.FromEither[error, T.Tuple3[T1, T2, T3]],
|
|
||||||
IOE.Chain(ft),
|
|
||||||
IOE.Map[error](F.ToAny[R]),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func eraseProviderFactory4[T1, T2, T3, T4 any, R any](
|
|
||||||
d1 Dependency[T1],
|
|
||||||
d2 Dependency[T2],
|
|
||||||
d3 Dependency[T3],
|
|
||||||
d4 Dependency[T4],
|
|
||||||
f func(T1, T2, T3, T4) IOE.IOEither[error, R]) func(params ...any) IOE.IOEither[error, any] {
|
|
||||||
ft := T.Tupled4(f)
|
|
||||||
t1 := lookupAt[T1](0, d1)
|
|
||||||
t2 := lookupAt[T2](1, d2)
|
|
||||||
t3 := lookupAt[T3](2, d3)
|
|
||||||
t4 := lookupAt[T4](3, d4)
|
|
||||||
return func(params ...any) IOE.IOEither[error, any] {
|
|
||||||
return F.Pipe3(
|
|
||||||
E.SequenceT4(t1(params), t2(params), t3(params), t4(params)),
|
|
||||||
IOE.FromEither[error, T.Tuple4[T1, T2, T3, T4]],
|
|
||||||
IOE.Chain(ft),
|
|
||||||
IOE.Map[error](F.ToAny[R]),
|
IOE.Map[error](F.ToAny[R]),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func MakeProviderFactory0[R any](
|
func MakeProviderFactory0[R any](
|
||||||
fct func() IOE.IOEither[error, R],
|
fct IOE.IOEither[error, R],
|
||||||
) DIE.ProviderFactory {
|
) DIE.ProviderFactory {
|
||||||
return DIE.MakeProviderFactory(
|
return DIE.MakeProviderFactory(
|
||||||
A.Empty[DIE.Dependency](),
|
A.Empty[DIE.Dependency](),
|
||||||
@@ -122,14 +58,14 @@ func MakeProviderFactory0[R any](
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MakeTokenWithDefault0 create a unique `InjectionToken` for a specific type with an attached default provider
|
// MakeTokenWithDefault0 creates a unique [InjectionToken] for a specific type with an attached default [DIE.Provider]
|
||||||
func MakeTokenWithDefault0[R any](name string, fct func() IOE.IOEither[error, R]) InjectionToken[R] {
|
func MakeTokenWithDefault0[R any](name string, fct IOE.IOEither[error, R]) InjectionToken[R] {
|
||||||
return MakeTokenWithDefault[R](name, MakeProviderFactory0(fct))
|
return MakeTokenWithDefault[R](name, MakeProviderFactory0(fct))
|
||||||
}
|
}
|
||||||
|
|
||||||
func MakeProvider0[R any](
|
func MakeProvider0[R any](
|
||||||
token InjectionToken[R],
|
token InjectionToken[R],
|
||||||
fct func() IOE.IOEither[error, R],
|
fct IOE.IOEither[error, R],
|
||||||
) DIE.Provider {
|
) DIE.Provider {
|
||||||
return DIE.MakeProvider(
|
return DIE.MakeProvider(
|
||||||
token,
|
token,
|
||||||
@@ -137,145 +73,7 @@ func MakeProvider0[R any](
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func MakeProviderFactory1[T1, R any](
|
|
||||||
d1 Dependency[T1],
|
|
||||||
fct func(T1) IOE.IOEither[error, R],
|
|
||||||
) DIE.ProviderFactory {
|
|
||||||
|
|
||||||
return DIE.MakeProviderFactory(
|
|
||||||
A.From[DIE.Dependency](d1),
|
|
||||||
eraseProviderFactory1(d1, fct),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MakeTokenWithDefault1 create a unique `InjectionToken` for a specific type with an attached default provider
|
|
||||||
func MakeTokenWithDefault1[T1, R any](name string,
|
|
||||||
d1 Dependency[T1],
|
|
||||||
fct func(T1) IOE.IOEither[error, R]) InjectionToken[R] {
|
|
||||||
return MakeTokenWithDefault[R](name, MakeProviderFactory1(d1, fct))
|
|
||||||
}
|
|
||||||
|
|
||||||
func MakeProvider1[T1, R any](
|
|
||||||
token InjectionToken[R],
|
|
||||||
d1 Dependency[T1],
|
|
||||||
fct func(T1) IOE.IOEither[error, R],
|
|
||||||
) DIE.Provider {
|
|
||||||
|
|
||||||
return DIE.MakeProvider(
|
|
||||||
token,
|
|
||||||
MakeProviderFactory1(d1, fct),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func MakeProviderFactory2[T1, T2, R any](
|
|
||||||
d1 Dependency[T1],
|
|
||||||
d2 Dependency[T2],
|
|
||||||
fct func(T1, T2) IOE.IOEither[error, R],
|
|
||||||
) DIE.ProviderFactory {
|
|
||||||
|
|
||||||
return DIE.MakeProviderFactory(
|
|
||||||
A.From[DIE.Dependency](d1, d2),
|
|
||||||
eraseProviderFactory2(d1, d2, fct),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MakeTokenWithDefault2 create a unique `InjectionToken` for a specific type with an attached default provider
|
|
||||||
func MakeTokenWithDefault2[T1, T2, R any](name string,
|
|
||||||
d1 Dependency[T1],
|
|
||||||
d2 Dependency[T2],
|
|
||||||
fct func(T1, T2) IOE.IOEither[error, R]) InjectionToken[R] {
|
|
||||||
return MakeTokenWithDefault[R](name, MakeProviderFactory2(d1, d2, fct))
|
|
||||||
}
|
|
||||||
|
|
||||||
func MakeProvider2[T1, T2, R any](
|
|
||||||
token InjectionToken[R],
|
|
||||||
d1 Dependency[T1],
|
|
||||||
d2 Dependency[T2],
|
|
||||||
fct func(T1, T2) IOE.IOEither[error, R],
|
|
||||||
) DIE.Provider {
|
|
||||||
|
|
||||||
return DIE.MakeProvider(
|
|
||||||
token,
|
|
||||||
MakeProviderFactory2(d1, d2, fct),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func MakeProviderFactory3[T1, T2, T3, R any](
|
|
||||||
d1 Dependency[T1],
|
|
||||||
d2 Dependency[T2],
|
|
||||||
d3 Dependency[T3],
|
|
||||||
fct func(T1, T2, T3) IOE.IOEither[error, R],
|
|
||||||
) DIE.ProviderFactory {
|
|
||||||
|
|
||||||
return DIE.MakeProviderFactory(
|
|
||||||
A.From[DIE.Dependency](d1, d2, d3),
|
|
||||||
eraseProviderFactory3(d1, d2, d3, fct),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MakeTokenWithDefault3 create a unique `InjectionToken` for a specific type with an attached default provider
|
|
||||||
func MakeTokenWithDefault3[T1, T2, T3, R any](name string,
|
|
||||||
d1 Dependency[T1],
|
|
||||||
d2 Dependency[T2],
|
|
||||||
d3 Dependency[T3],
|
|
||||||
fct func(T1, T2, T3) IOE.IOEither[error, R]) InjectionToken[R] {
|
|
||||||
return MakeTokenWithDefault[R](name, MakeProviderFactory3(d1, d2, d3, fct))
|
|
||||||
}
|
|
||||||
|
|
||||||
func MakeProvider3[T1, T2, T3, R any](
|
|
||||||
token InjectionToken[R],
|
|
||||||
d1 Dependency[T1],
|
|
||||||
d2 Dependency[T2],
|
|
||||||
d3 Dependency[T3],
|
|
||||||
fct func(T1, T2, T3) IOE.IOEither[error, R],
|
|
||||||
) DIE.Provider {
|
|
||||||
|
|
||||||
return DIE.MakeProvider(
|
|
||||||
token,
|
|
||||||
MakeProviderFactory3(d1, d2, d3, fct),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func MakeProviderFactory4[T1, T2, T3, T4, R any](
|
|
||||||
d1 Dependency[T1],
|
|
||||||
d2 Dependency[T2],
|
|
||||||
d3 Dependency[T3],
|
|
||||||
d4 Dependency[T4],
|
|
||||||
fct func(T1, T2, T3, T4) IOE.IOEither[error, R],
|
|
||||||
) DIE.ProviderFactory {
|
|
||||||
|
|
||||||
return DIE.MakeProviderFactory(
|
|
||||||
A.From[DIE.Dependency](d1, d2, d3, d4),
|
|
||||||
eraseProviderFactory4(d1, d2, d3, d4, fct),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MakeTokenWithDefault4 create a unique `InjectionToken` for a specific type with an attached default provider
|
|
||||||
func MakeTokenWithDefault4[T1, T2, T3, T4, R any](name string,
|
|
||||||
d1 Dependency[T1],
|
|
||||||
d2 Dependency[T2],
|
|
||||||
d3 Dependency[T3],
|
|
||||||
d4 Dependency[T4],
|
|
||||||
fct func(T1, T2, T3, T4) IOE.IOEither[error, R]) InjectionToken[R] {
|
|
||||||
return MakeTokenWithDefault[R](name, MakeProviderFactory4(d1, d2, d3, d4, fct))
|
|
||||||
}
|
|
||||||
|
|
||||||
func MakeProvider4[T1, T2, T3, T4, R any](
|
|
||||||
token InjectionToken[R],
|
|
||||||
d1 Dependency[T1],
|
|
||||||
d2 Dependency[T2],
|
|
||||||
d3 Dependency[T3],
|
|
||||||
d4 Dependency[T4],
|
|
||||||
fct func(T1, T2, T3, T4) IOE.IOEither[error, R],
|
|
||||||
) DIE.Provider {
|
|
||||||
|
|
||||||
return DIE.MakeProvider(
|
|
||||||
token,
|
|
||||||
MakeProviderFactory4(d1, d2, d3, d4, fct),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ConstProvider simple implementation for a provider with a constant value
|
// ConstProvider simple implementation for a provider with a constant value
|
||||||
func ConstProvider[R any](token InjectionToken[R], value R) DIE.Provider {
|
func ConstProvider[R any](token InjectionToken[R], value R) DIE.Provider {
|
||||||
return MakeProvider0[R](token, F.Constant(IOE.Of[error](value)))
|
return MakeProvider0[R](token, IOE.Of[error](value))
|
||||||
}
|
}
|
||||||
|
@@ -12,6 +12,7 @@
|
|||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
package di
|
package di
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -38,12 +39,10 @@ func TestSimpleProvider(t *testing.T) {
|
|||||||
|
|
||||||
var staticCount int
|
var staticCount int
|
||||||
|
|
||||||
staticValue := func(value string) func() IOE.IOEither[error, string] {
|
staticValue := func(value string) IOE.IOEither[error, string] {
|
||||||
return func() IOE.IOEither[error, string] {
|
return func() E.Either[error, string] {
|
||||||
return func() E.Either[error, string] {
|
staticCount++
|
||||||
staticCount++
|
return E.Of[error](fmt.Sprintf("Static based on [%s], at [%s]", value, time.Now()))
|
||||||
return E.Of[error](fmt.Sprintf("Static based on [%s], at [%s]", value, time.Now()))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,12 +81,10 @@ func TestOptionalProvider(t *testing.T) {
|
|||||||
|
|
||||||
var staticCount int
|
var staticCount int
|
||||||
|
|
||||||
staticValue := func(value string) func() IOE.IOEither[error, string] {
|
staticValue := func(value string) IOE.IOEither[error, string] {
|
||||||
return func() IOE.IOEither[error, string] {
|
return func() E.Either[error, string] {
|
||||||
return func() E.Either[error, string] {
|
staticCount++
|
||||||
staticCount++
|
return E.Of[error](fmt.Sprintf("Static based on [%s], at [%s]", value, time.Now()))
|
||||||
return E.Of[error](fmt.Sprintf("Static based on [%s], at [%s]", value, time.Now()))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -182,12 +179,10 @@ func TestEagerAndLazyProvider(t *testing.T) {
|
|||||||
|
|
||||||
var staticCount int
|
var staticCount int
|
||||||
|
|
||||||
staticValue := func(value string) func() IOE.IOEither[error, string] {
|
staticValue := func(value string) IOE.IOEither[error, string] {
|
||||||
return func() IOE.IOEither[error, string] {
|
return func() E.Either[error, string] {
|
||||||
return func() E.Either[error, string] {
|
staticCount++
|
||||||
staticCount++
|
return E.Of[error](fmt.Sprintf("Static based on [%s], at [%s]", value, time.Now()))
|
||||||
return E.Of[error](fmt.Sprintf("Static based on [%s], at [%s]", value, time.Now()))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -307,7 +302,7 @@ func TestTokenWithDefaultProvider(t *testing.T) {
|
|||||||
// token without a default
|
// token without a default
|
||||||
injToken1 := MakeToken[string]("Token1")
|
injToken1 := MakeToken[string]("Token1")
|
||||||
// token with a default
|
// token with a default
|
||||||
injToken2 := MakeTokenWithDefault0("Token2", F.Constant(IOE.Of[error]("Carsten")))
|
injToken2 := MakeTokenWithDefault0("Token2", IOE.Of[error]("Carsten"))
|
||||||
// dependency
|
// dependency
|
||||||
injToken3 := MakeToken[string]("Token3")
|
injToken3 := MakeToken[string]("Token3")
|
||||||
|
|
||||||
@@ -330,7 +325,7 @@ func TestTokenWithDefaultProvider(t *testing.T) {
|
|||||||
|
|
||||||
func TestTokenWithDefaultProviderAndOverride(t *testing.T) {
|
func TestTokenWithDefaultProviderAndOverride(t *testing.T) {
|
||||||
// token with a default
|
// token with a default
|
||||||
injToken2 := MakeTokenWithDefault0("Token2", F.Constant(IOE.Of[error]("Carsten")))
|
injToken2 := MakeTokenWithDefault0("Token2", IOE.Of[error]("Carsten"))
|
||||||
// dependency
|
// dependency
|
||||||
injToken3 := MakeToken[string]("Token3")
|
injToken3 := MakeToken[string]("Token3")
|
||||||
|
|
||||||
|
17
di/token.go
17
di/token.go
@@ -42,20 +42,21 @@ type InjectionToken[T any] interface {
|
|||||||
// Identity idenifies this dependency as a mandatory, required dependency, it will be resolved eagerly and injected as `T`.
|
// Identity idenifies this dependency as a mandatory, required dependency, it will be resolved eagerly and injected as `T`.
|
||||||
// If the dependency cannot be resolved, the resolution process fails
|
// If the dependency cannot be resolved, the resolution process fails
|
||||||
Identity() Dependency[T]
|
Identity() Dependency[T]
|
||||||
// Option identifies this dependency as optional, it will be resolved eagerly and injected as `O.Option[T]`.
|
// Option identifies this dependency as optional, it will be resolved eagerly and injected as [O.Option[T]].
|
||||||
// If the dependency cannot be resolved, the resolution process continues and the dependency is represented as `O.None[T]`
|
// If the dependency cannot be resolved, the resolution process continues and the dependency is represented as [O.None[T]]
|
||||||
Option() Dependency[O.Option[T]]
|
Option() Dependency[O.Option[T]]
|
||||||
// IOEither identifies this dependency as mandatory but it will be resolved lazily as a `IOE.IOEither[error, T]`. This
|
// IOEither identifies this dependency as mandatory but it will be resolved lazily as a [IOE.IOEither[error, T]]. This
|
||||||
// value is memoized to make sure the dependency is a singleton.
|
// value is memoized to make sure the dependency is a singleton.
|
||||||
// If the dependency cannot be resolved, the resolution process fails
|
// If the dependency cannot be resolved, the resolution process fails
|
||||||
IOEither() Dependency[IOE.IOEither[error, T]]
|
IOEither() Dependency[IOE.IOEither[error, T]]
|
||||||
// IOOption identifies this dependency as optional but it will be resolved lazily as a `IOO.IOOption[T]`. This
|
// IOOption identifies this dependency as optional but it will be resolved lazily as a [IOO.IOOption[T]]. This
|
||||||
// value is memoized to make sure the dependency is a singleton.
|
// value is memoized to make sure the dependency is a singleton.
|
||||||
// If the dependency cannot be resolved, the resolution process continues and the dependency is represented as the none value.
|
// If the dependency cannot be resolved, the resolution process continues and the dependency is represented as the none value.
|
||||||
IOOption() Dependency[IOO.IOOption[T]]
|
IOOption() Dependency[IOO.IOOption[T]]
|
||||||
}
|
}
|
||||||
|
|
||||||
// MultiInjectionToken uniquely identifies a dependency by giving it an Id, Type and name.
|
// MultiInjectionToken uniquely identifies a dependency by giving it an Id, Type and name that can have multiple implementations.
|
||||||
|
// Implementations are provided via the [MultiInjectionToken.Item] injection token.
|
||||||
type MultiInjectionToken[T any] interface {
|
type MultiInjectionToken[T any] interface {
|
||||||
// Container returns the injection token used to request an array of all provided items
|
// Container returns the injection token used to request an array of all provided items
|
||||||
Container() InjectionToken[[]T]
|
Container() InjectionToken[[]T]
|
||||||
@@ -146,7 +147,7 @@ func (m *multiInjectionToken[T]) Item() InjectionToken[T] {
|
|||||||
return m.item
|
return m.item
|
||||||
}
|
}
|
||||||
|
|
||||||
// makeToken create a unique `InjectionToken` for a specific type
|
// makeToken create a unique [InjectionToken] for a specific type
|
||||||
func makeInjectionToken[T any](name string, providerFactory O.Option[DIE.ProviderFactory]) InjectionToken[T] {
|
func makeInjectionToken[T any](name string, providerFactory O.Option[DIE.ProviderFactory]) InjectionToken[T] {
|
||||||
id := genId()
|
id := genId()
|
||||||
toIdentity := toType[T]()
|
toIdentity := toType[T]()
|
||||||
@@ -158,12 +159,12 @@ func makeInjectionToken[T any](name string, providerFactory O.Option[DIE.Provide
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MakeToken create a unique `InjectionToken` for a specific type
|
// MakeToken create a unique [InjectionToken] for a specific type
|
||||||
func MakeToken[T any](name string) InjectionToken[T] {
|
func MakeToken[T any](name string) InjectionToken[T] {
|
||||||
return makeInjectionToken[T](name, O.None[DIE.ProviderFactory]())
|
return makeInjectionToken[T](name, O.None[DIE.ProviderFactory]())
|
||||||
}
|
}
|
||||||
|
|
||||||
// MakeToken create a unique `InjectionToken` for a specific type
|
// MakeToken create a unique [InjectionToken] for a specific type
|
||||||
func MakeTokenWithDefault[T any](name string, providerFactory DIE.ProviderFactory) InjectionToken[T] {
|
func MakeTokenWithDefault[T any](name string, providerFactory DIE.ProviderFactory) InjectionToken[T] {
|
||||||
return makeInjectionToken[T](name, O.Of(providerFactory))
|
return makeInjectionToken[T](name, O.Of(providerFactory))
|
||||||
}
|
}
|
||||||
|
@@ -12,6 +12,7 @@
|
|||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
package di
|
package di
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@@ -12,6 +12,7 @@
|
|||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
package di
|
package di
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
30
endomorphism/curry.go
Normal file
30
endomorphism/curry.go
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
// Copyright (c) 2023 IBM Corp.
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package endomorphism
|
||||||
|
|
||||||
|
import (
|
||||||
|
G "github.com/IBM/fp-go/endomorphism/generic"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Curry2 curries a binary function
|
||||||
|
func Curry2[FCT ~func(T0, T1) T1, T0, T1 any](f FCT) func(T0) Endomorphism[T1] {
|
||||||
|
return G.Curry2[Endomorphism[T1]](f)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Curry3 curries a ternary function
|
||||||
|
func Curry3[FCT ~func(T0, T1, T2) T2, T0, T1, T2 any](f FCT) func(T0) func(T1) Endomorphism[T2] {
|
||||||
|
return G.Curry3[Endomorphism[T2]](f)
|
||||||
|
}
|
@@ -27,34 +27,10 @@ func Ap[A any](fa A) func(Endomorphism[A]) A {
|
|||||||
return G.Ap[Endomorphism[A]](fa)
|
return G.Ap[Endomorphism[A]](fa)
|
||||||
}
|
}
|
||||||
|
|
||||||
func MonadFlap[A any](fab Endomorphism[A], a A) A {
|
func MonadChain[A any](ma Endomorphism[A], f Endomorphism[A]) Endomorphism[A] {
|
||||||
return G.MonadFlap[Endomorphism[A]](fab, a)
|
|
||||||
}
|
|
||||||
|
|
||||||
func Flap[A any](a A) func(Endomorphism[A]) A {
|
|
||||||
return G.Flap[Endomorphism[A]](a)
|
|
||||||
}
|
|
||||||
|
|
||||||
func MonadMap[A any](fa A, f Endomorphism[A]) A {
|
|
||||||
return G.MonadMap[Endomorphism[A]](fa, f)
|
|
||||||
}
|
|
||||||
|
|
||||||
func Map[A any](f Endomorphism[A]) Endomorphism[A] {
|
|
||||||
return G.Map[Endomorphism[A]](f)
|
|
||||||
}
|
|
||||||
|
|
||||||
func MonadChain[A any](ma A, f Endomorphism[A]) A {
|
|
||||||
return G.MonadChain[Endomorphism[A]](ma, f)
|
return G.MonadChain[Endomorphism[A]](ma, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Chain[A any](f Endomorphism[A]) Endomorphism[A] {
|
func Chain[A any](f Endomorphism[A]) Endomorphism[Endomorphism[A]] {
|
||||||
return G.Chain[Endomorphism[A], A](f)
|
return G.Chain[Endomorphism[Endomorphism[A]], Endomorphism[A], A](f)
|
||||||
}
|
|
||||||
|
|
||||||
func MonadChainFirst[A any](fa A, f Endomorphism[A]) A {
|
|
||||||
return G.MonadChainFirst[Endomorphism[A]](fa, f)
|
|
||||||
}
|
|
||||||
|
|
||||||
func ChainFirst[A any](f Endomorphism[A]) Endomorphism[A] {
|
|
||||||
return G.ChainFirst[Endomorphism[A]](f)
|
|
||||||
}
|
}
|
||||||
|
36
endomorphism/generic/curry.go
Normal file
36
endomorphism/generic/curry.go
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
// Copyright (c) 2023 IBM Corp.
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package generic
|
||||||
|
|
||||||
|
// Curry2 is a duplicate of [F.Curry2] but because of the type system it's not compatible otherwise
|
||||||
|
func Curry2[GT1 ~func(T1) T1, FCT ~func(T0, T1) T1, T0, T1 any](f FCT) func(T0) GT1 {
|
||||||
|
return func(t0 T0) GT1 {
|
||||||
|
return func(t1 T1) T1 {
|
||||||
|
return f(t0, t1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Curry2 is a duplicate of [F.Curry2] but because of the type system it's not compatible otherwise
|
||||||
|
func Curry3[GT2 ~func(T2) T2, FCT ~func(T0, T1, T2) T2, T0, T1, T2 any](f FCT) func(T0) func(T1) GT2 {
|
||||||
|
return func(t0 T0) func(T1) GT2 {
|
||||||
|
return func(t1 T1) GT2 {
|
||||||
|
return func(t2 T2) T2 {
|
||||||
|
return f(t0, t1, t2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -16,6 +16,7 @@
|
|||||||
package generic
|
package generic
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
F "github.com/IBM/fp-go/function"
|
||||||
I "github.com/IBM/fp-go/identity/generic"
|
I "github.com/IBM/fp-go/identity/generic"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -27,34 +28,10 @@ func Ap[GA ~func(A) A, A any](fa A) func(GA) A {
|
|||||||
return I.Ap[GA, A, A](fa)
|
return I.Ap[GA, A, A](fa)
|
||||||
}
|
}
|
||||||
|
|
||||||
func MonadFlap[GA ~func(A) A, A any](fab GA, a A) A {
|
func MonadChain[GA ~func(A) A, A any](ma GA, f GA) GA {
|
||||||
return I.MonadFlap[GA, A, A](fab, a)
|
return Compose(ma, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Flap[GA ~func(A) A, A any](a A) func(GA) A {
|
func Chain[ENDO ~func(GA) GA, GA ~func(A) A, A any](f GA) ENDO {
|
||||||
return I.Flap[GA, A, A](a)
|
return Of[ENDO](F.Bind2nd(Compose[GA], f))
|
||||||
}
|
|
||||||
|
|
||||||
func MonadMap[GA ~func(A) A, A any](fa A, f GA) A {
|
|
||||||
return I.MonadMap[GA, A, A](fa, f)
|
|
||||||
}
|
|
||||||
|
|
||||||
func Map[GA ~func(A) A, A any](f GA) GA {
|
|
||||||
return I.Map[GA, A, A](f)
|
|
||||||
}
|
|
||||||
|
|
||||||
func MonadChain[GA ~func(A) A, A any](ma A, f GA) A {
|
|
||||||
return I.MonadChain[GA, A, A](ma, f)
|
|
||||||
}
|
|
||||||
|
|
||||||
func Chain[GA ~func(A) A, A any](f GA) GA {
|
|
||||||
return I.Chain[GA, A](f)
|
|
||||||
}
|
|
||||||
|
|
||||||
func MonadChainFirst[GA ~func(A) A, A any](fa A, f GA) A {
|
|
||||||
return I.MonadChainFirst[GA, A, A](fa, f)
|
|
||||||
}
|
|
||||||
|
|
||||||
func ChainFirst[GA ~func(A) A, A any](f GA) GA {
|
|
||||||
return I.ChainFirst[GA, A, A](f)
|
|
||||||
}
|
}
|
||||||
|
@@ -28,6 +28,16 @@ func Of[ENDO ~func(A) A, F ~func(A) A, A any](f F) ENDO {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Wrap converts any function to an [Endomorphism]
|
||||||
|
func Wrap[ENDO ~func(A) A, F ~func(A) A, A any](f F) ENDO {
|
||||||
|
return Of[ENDO](f)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unwrap converts any [Endomorphism] to a normal function
|
||||||
|
func Unwrap[F ~func(A) A, ENDO ~func(A) A, A any](f ENDO) F {
|
||||||
|
return Of[F](f)
|
||||||
|
}
|
||||||
|
|
||||||
func Identity[ENDO ~func(A) A, A any]() ENDO {
|
func Identity[ENDO ~func(A) A, A any]() ENDO {
|
||||||
return Of[ENDO](F.Identity[A])
|
return Of[ENDO](F.Identity[A])
|
||||||
}
|
}
|
||||||
|
@@ -29,6 +29,16 @@ func Of[F ~func(A) A, A any](f F) Endomorphism[A] {
|
|||||||
return G.Of[Endomorphism[A]](f)
|
return G.Of[Endomorphism[A]](f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Wrap converts any function to an [Endomorphism]
|
||||||
|
func Wrap[F ~func(A) A, A any](f F) Endomorphism[A] {
|
||||||
|
return G.Wrap[Endomorphism[A]](f)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unwrap converts any [Endomorphism] to a function
|
||||||
|
func Unwrap[F ~func(A) A, A any](f Endomorphism[A]) F {
|
||||||
|
return G.Unwrap[F](f)
|
||||||
|
}
|
||||||
|
|
||||||
// Identity returns the identity [Endomorphism]
|
// Identity returns the identity [Endomorphism]
|
||||||
func Identity[A any]() Endomorphism[A] {
|
func Identity[A any]() Endomorphism[A] {
|
||||||
return G.Identity[Endomorphism[A]]()
|
return G.Identity[Endomorphism[A]]()
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
// Code generated by go generate; DO NOT EDIT.
|
// Code generated by go generate; DO NOT EDIT.
|
||||||
// This file was generated by robots at
|
// This file was generated by robots at
|
||||||
// 2023-10-23 08:30:44.6474482 +0200 CEST m=+0.150851901
|
// 2023-12-18 09:38:59.1616876 +0100 CET m=+0.008641801
|
||||||
|
|
||||||
package function
|
package function
|
||||||
|
|
||||||
|
@@ -28,3 +28,14 @@ func Memoize[K comparable, T any](f func(K) T) func(K) T {
|
|||||||
func ContramapMemoize[A any, K comparable, T any](kf func(A) K) func(func(A) T) func(A) T {
|
func ContramapMemoize[A any, K comparable, T any](kf func(A) K) func(func(A) T) func(A) T {
|
||||||
return G.ContramapMemoize[func(A) T](kf)
|
return G.ContramapMemoize[func(A) T](kf)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CacheCallback converts a unary function into a unary function that caches the value depending on the parameter
|
||||||
|
func CacheCallback[
|
||||||
|
A any, K comparable, T any](kf func(A) K, getOrCreate func(K, func() func() T) func() T) func(func(A) T) func(A) T {
|
||||||
|
return G.CacheCallback[func(func(A) T) func(A) T](kf, getOrCreate)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SingleElementCache creates a cache function for use with the [CacheCallback] method that has a maximum capacity of one single item
|
||||||
|
func SingleElementCache[K comparable, T any]() func(K, func() func() T) func() T {
|
||||||
|
return G.SingleElementCache[func() func() T, K]()
|
||||||
|
}
|
||||||
|
@@ -16,6 +16,8 @@
|
|||||||
package function
|
package function
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"math/rand"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
@@ -48,3 +50,21 @@ func TestCache(t *testing.T) {
|
|||||||
assert.Equal(t, 10, cached(10))
|
assert.Equal(t, 10, cached(10))
|
||||||
assert.Equal(t, 2, count)
|
assert.Equal(t, 2, count)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSingleElementCache(t *testing.T) {
|
||||||
|
f := func(key string) string {
|
||||||
|
return fmt.Sprintf("%s: %d", key, rand.Int())
|
||||||
|
}
|
||||||
|
cb := CacheCallback(func(s string) string { return s }, SingleElementCache[string, string]())
|
||||||
|
cf := cb(f)
|
||||||
|
|
||||||
|
v1 := cf("1")
|
||||||
|
v2 := cf("1")
|
||||||
|
v3 := cf("2")
|
||||||
|
v4 := cf("1")
|
||||||
|
|
||||||
|
assert.Equal(t, v1, v2)
|
||||||
|
assert.NotEqual(t, v2, v3)
|
||||||
|
assert.NotEqual(t, v3, v4)
|
||||||
|
assert.NotEqual(t, v1, v4)
|
||||||
|
}
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
// Code generated by go generate; DO NOT EDIT.
|
// Code generated by go generate; DO NOT EDIT.
|
||||||
// This file was generated by robots at
|
// This file was generated by robots at
|
||||||
// 2023-10-23 08:30:41.7972101 +0200 CEST m=+0.008029101
|
// 2023-12-18 09:38:51.4946446 +0100 CET m=+0.008838401
|
||||||
|
|
||||||
package function
|
package function
|
||||||
|
|
||||||
@@ -55,7 +55,7 @@ func Nullary1[F1 ~func() T1, T1 any](f1 F1) func() T1 {
|
|||||||
|
|
||||||
// Curry1 takes a function with 1 parameters and returns a cascade of functions each taking only one parameter.
|
// Curry1 takes a function with 1 parameters and returns a cascade of functions each taking only one parameter.
|
||||||
// The inverse function is [Uncurry1]
|
// The inverse function is [Uncurry1]
|
||||||
func Curry1[T0, T1 any](f func(T0) T1) func(T0) T1 {
|
func Curry1[FCT ~func(T0) T1, T0, T1 any](f FCT) func(T0) T1 {
|
||||||
return func(t0 T0) T1 {
|
return func(t0 T0) T1 {
|
||||||
return f(t0)
|
return f(t0)
|
||||||
}
|
}
|
||||||
@@ -63,7 +63,7 @@ func Curry1[T0, T1 any](f func(T0) T1) func(T0) T1 {
|
|||||||
|
|
||||||
// Uncurry1 takes a cascade of 1 functions each taking only one parameter and returns a function with 1 parameters .
|
// Uncurry1 takes a cascade of 1 functions each taking only one parameter and returns a function with 1 parameters .
|
||||||
// The inverse function is [Curry1]
|
// The inverse function is [Curry1]
|
||||||
func Uncurry1[T0, T1 any](f func(T0) T1) func(T0) T1 {
|
func Uncurry1[FCT ~func(T0) T1, T0, T1 any](f FCT) func(T0) T1 {
|
||||||
return func(t0 T0) T1 {
|
return func(t0 T0) T1 {
|
||||||
return f(t0)
|
return f(t0)
|
||||||
}
|
}
|
||||||
@@ -115,7 +115,7 @@ func Nullary2[F1 ~func() T1, F2 ~func(T1) T2, T1, T2 any](f1 F1, f2 F2) func() T
|
|||||||
|
|
||||||
// Curry2 takes a function with 2 parameters and returns a cascade of functions each taking only one parameter.
|
// Curry2 takes a function with 2 parameters and returns a cascade of functions each taking only one parameter.
|
||||||
// The inverse function is [Uncurry2]
|
// The inverse function is [Uncurry2]
|
||||||
func Curry2[T0, T1, T2 any](f func(T0, T1) T2) func(T0) func(T1) T2 {
|
func Curry2[FCT ~func(T0, T1) T2, T0, T1, T2 any](f FCT) func(T0) func(T1) T2 {
|
||||||
return func(t0 T0) func(t1 T1) T2 {
|
return func(t0 T0) func(t1 T1) T2 {
|
||||||
return func(t1 T1) T2 {
|
return func(t1 T1) T2 {
|
||||||
return f(t0, t1)
|
return f(t0, t1)
|
||||||
@@ -125,7 +125,7 @@ func Curry2[T0, T1, T2 any](f func(T0, T1) T2) func(T0) func(T1) T2 {
|
|||||||
|
|
||||||
// Uncurry2 takes a cascade of 2 functions each taking only one parameter and returns a function with 2 parameters .
|
// Uncurry2 takes a cascade of 2 functions each taking only one parameter and returns a function with 2 parameters .
|
||||||
// The inverse function is [Curry2]
|
// The inverse function is [Curry2]
|
||||||
func Uncurry2[T0, T1, T2 any](f func(T0) func(T1) T2) func(T0, T1) T2 {
|
func Uncurry2[FCT ~func(T0) func(T1) T2, T0, T1, T2 any](f FCT) func(T0, T1) T2 {
|
||||||
return func(t0 T0, t1 T1) T2 {
|
return func(t0 T0, t1 T1) T2 {
|
||||||
return f(t0)(t1)
|
return f(t0)(t1)
|
||||||
}
|
}
|
||||||
@@ -178,7 +178,7 @@ func Nullary3[F1 ~func() T1, F2 ~func(T1) T2, F3 ~func(T2) T3, T1, T2, T3 any](f
|
|||||||
|
|
||||||
// Curry3 takes a function with 3 parameters and returns a cascade of functions each taking only one parameter.
|
// Curry3 takes a function with 3 parameters and returns a cascade of functions each taking only one parameter.
|
||||||
// The inverse function is [Uncurry3]
|
// The inverse function is [Uncurry3]
|
||||||
func Curry3[T0, T1, T2, T3 any](f func(T0, T1, T2) T3) func(T0) func(T1) func(T2) T3 {
|
func Curry3[FCT ~func(T0, T1, T2) T3, T0, T1, T2, T3 any](f FCT) func(T0) func(T1) func(T2) T3 {
|
||||||
return func(t0 T0) func(t1 T1) func(t2 T2) T3 {
|
return func(t0 T0) func(t1 T1) func(t2 T2) T3 {
|
||||||
return func(t1 T1) func(t2 T2) T3 {
|
return func(t1 T1) func(t2 T2) T3 {
|
||||||
return func(t2 T2) T3 {
|
return func(t2 T2) T3 {
|
||||||
@@ -190,7 +190,7 @@ func Curry3[T0, T1, T2, T3 any](f func(T0, T1, T2) T3) func(T0) func(T1) func(T2
|
|||||||
|
|
||||||
// Uncurry3 takes a cascade of 3 functions each taking only one parameter and returns a function with 3 parameters .
|
// Uncurry3 takes a cascade of 3 functions each taking only one parameter and returns a function with 3 parameters .
|
||||||
// The inverse function is [Curry3]
|
// The inverse function is [Curry3]
|
||||||
func Uncurry3[T0, T1, T2, T3 any](f func(T0) func(T1) func(T2) T3) func(T0, T1, T2) T3 {
|
func Uncurry3[FCT ~func(T0) func(T1) func(T2) T3, T0, T1, T2, T3 any](f FCT) func(T0, T1, T2) T3 {
|
||||||
return func(t0 T0, t1 T1, t2 T2) T3 {
|
return func(t0 T0, t1 T1, t2 T2) T3 {
|
||||||
return f(t0)(t1)(t2)
|
return f(t0)(t1)(t2)
|
||||||
}
|
}
|
||||||
@@ -244,7 +244,7 @@ func Nullary4[F1 ~func() T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4,
|
|||||||
|
|
||||||
// Curry4 takes a function with 4 parameters and returns a cascade of functions each taking only one parameter.
|
// Curry4 takes a function with 4 parameters and returns a cascade of functions each taking only one parameter.
|
||||||
// The inverse function is [Uncurry4]
|
// The inverse function is [Uncurry4]
|
||||||
func Curry4[T0, T1, T2, T3, T4 any](f func(T0, T1, T2, T3) T4) func(T0) func(T1) func(T2) func(T3) T4 {
|
func Curry4[FCT ~func(T0, T1, T2, T3) T4, T0, T1, T2, T3, T4 any](f FCT) func(T0) func(T1) func(T2) func(T3) T4 {
|
||||||
return func(t0 T0) func(t1 T1) func(t2 T2) func(t3 T3) T4 {
|
return func(t0 T0) func(t1 T1) func(t2 T2) func(t3 T3) T4 {
|
||||||
return func(t1 T1) func(t2 T2) func(t3 T3) T4 {
|
return func(t1 T1) func(t2 T2) func(t3 T3) T4 {
|
||||||
return func(t2 T2) func(t3 T3) T4 {
|
return func(t2 T2) func(t3 T3) T4 {
|
||||||
@@ -258,7 +258,7 @@ func Curry4[T0, T1, T2, T3, T4 any](f func(T0, T1, T2, T3) T4) func(T0) func(T1)
|
|||||||
|
|
||||||
// Uncurry4 takes a cascade of 4 functions each taking only one parameter and returns a function with 4 parameters .
|
// Uncurry4 takes a cascade of 4 functions each taking only one parameter and returns a function with 4 parameters .
|
||||||
// The inverse function is [Curry4]
|
// The inverse function is [Curry4]
|
||||||
func Uncurry4[T0, T1, T2, T3, T4 any](f func(T0) func(T1) func(T2) func(T3) T4) func(T0, T1, T2, T3) T4 {
|
func Uncurry4[FCT ~func(T0) func(T1) func(T2) func(T3) T4, T0, T1, T2, T3, T4 any](f FCT) func(T0, T1, T2, T3) T4 {
|
||||||
return func(t0 T0, t1 T1, t2 T2, t3 T3) T4 {
|
return func(t0 T0, t1 T1, t2 T2, t3 T3) T4 {
|
||||||
return f(t0)(t1)(t2)(t3)
|
return f(t0)(t1)(t2)(t3)
|
||||||
}
|
}
|
||||||
@@ -313,7 +313,7 @@ func Nullary5[F1 ~func() T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4,
|
|||||||
|
|
||||||
// Curry5 takes a function with 5 parameters and returns a cascade of functions each taking only one parameter.
|
// Curry5 takes a function with 5 parameters and returns a cascade of functions each taking only one parameter.
|
||||||
// The inverse function is [Uncurry5]
|
// The inverse function is [Uncurry5]
|
||||||
func Curry5[T0, T1, T2, T3, T4, T5 any](f func(T0, T1, T2, T3, T4) T5) func(T0) func(T1) func(T2) func(T3) func(T4) T5 {
|
func Curry5[FCT ~func(T0, T1, T2, T3, T4) T5, T0, T1, T2, T3, T4, T5 any](f FCT) func(T0) func(T1) func(T2) func(T3) func(T4) T5 {
|
||||||
return func(t0 T0) func(t1 T1) func(t2 T2) func(t3 T3) func(t4 T4) T5 {
|
return func(t0 T0) func(t1 T1) func(t2 T2) func(t3 T3) func(t4 T4) T5 {
|
||||||
return func(t1 T1) func(t2 T2) func(t3 T3) func(t4 T4) T5 {
|
return func(t1 T1) func(t2 T2) func(t3 T3) func(t4 T4) T5 {
|
||||||
return func(t2 T2) func(t3 T3) func(t4 T4) T5 {
|
return func(t2 T2) func(t3 T3) func(t4 T4) T5 {
|
||||||
@@ -329,7 +329,7 @@ func Curry5[T0, T1, T2, T3, T4, T5 any](f func(T0, T1, T2, T3, T4) T5) func(T0)
|
|||||||
|
|
||||||
// Uncurry5 takes a cascade of 5 functions each taking only one parameter and returns a function with 5 parameters .
|
// Uncurry5 takes a cascade of 5 functions each taking only one parameter and returns a function with 5 parameters .
|
||||||
// The inverse function is [Curry5]
|
// The inverse function is [Curry5]
|
||||||
func Uncurry5[T0, T1, T2, T3, T4, T5 any](f func(T0) func(T1) func(T2) func(T3) func(T4) T5) func(T0, T1, T2, T3, T4) T5 {
|
func Uncurry5[FCT ~func(T0) func(T1) func(T2) func(T3) func(T4) T5, T0, T1, T2, T3, T4, T5 any](f FCT) func(T0, T1, T2, T3, T4) T5 {
|
||||||
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4) T5 {
|
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4) T5 {
|
||||||
return f(t0)(t1)(t2)(t3)(t4)
|
return f(t0)(t1)(t2)(t3)(t4)
|
||||||
}
|
}
|
||||||
@@ -385,7 +385,7 @@ func Nullary6[F1 ~func() T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4,
|
|||||||
|
|
||||||
// Curry6 takes a function with 6 parameters and returns a cascade of functions each taking only one parameter.
|
// Curry6 takes a function with 6 parameters and returns a cascade of functions each taking only one parameter.
|
||||||
// The inverse function is [Uncurry6]
|
// The inverse function is [Uncurry6]
|
||||||
func Curry6[T0, T1, T2, T3, T4, T5, T6 any](f func(T0, T1, T2, T3, T4, T5) T6) func(T0) func(T1) func(T2) func(T3) func(T4) func(T5) T6 {
|
func Curry6[FCT ~func(T0, T1, T2, T3, T4, T5) T6, T0, T1, T2, T3, T4, T5, T6 any](f FCT) func(T0) func(T1) func(T2) func(T3) func(T4) func(T5) T6 {
|
||||||
return func(t0 T0) func(t1 T1) func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) T6 {
|
return func(t0 T0) func(t1 T1) func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) T6 {
|
||||||
return func(t1 T1) func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) T6 {
|
return func(t1 T1) func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) T6 {
|
||||||
return func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) T6 {
|
return func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) T6 {
|
||||||
@@ -403,7 +403,7 @@ func Curry6[T0, T1, T2, T3, T4, T5, T6 any](f func(T0, T1, T2, T3, T4, T5) T6) f
|
|||||||
|
|
||||||
// Uncurry6 takes a cascade of 6 functions each taking only one parameter and returns a function with 6 parameters .
|
// Uncurry6 takes a cascade of 6 functions each taking only one parameter and returns a function with 6 parameters .
|
||||||
// The inverse function is [Curry6]
|
// The inverse function is [Curry6]
|
||||||
func Uncurry6[T0, T1, T2, T3, T4, T5, T6 any](f func(T0) func(T1) func(T2) func(T3) func(T4) func(T5) T6) func(T0, T1, T2, T3, T4, T5) T6 {
|
func Uncurry6[FCT ~func(T0) func(T1) func(T2) func(T3) func(T4) func(T5) T6, T0, T1, T2, T3, T4, T5, T6 any](f FCT) func(T0, T1, T2, T3, T4, T5) T6 {
|
||||||
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4, t5 T5) T6 {
|
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4, t5 T5) T6 {
|
||||||
return f(t0)(t1)(t2)(t3)(t4)(t5)
|
return f(t0)(t1)(t2)(t3)(t4)(t5)
|
||||||
}
|
}
|
||||||
@@ -460,7 +460,7 @@ func Nullary7[F1 ~func() T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4,
|
|||||||
|
|
||||||
// Curry7 takes a function with 7 parameters and returns a cascade of functions each taking only one parameter.
|
// Curry7 takes a function with 7 parameters and returns a cascade of functions each taking only one parameter.
|
||||||
// The inverse function is [Uncurry7]
|
// The inverse function is [Uncurry7]
|
||||||
func Curry7[T0, T1, T2, T3, T4, T5, T6, T7 any](f func(T0, T1, T2, T3, T4, T5, T6) T7) func(T0) func(T1) func(T2) func(T3) func(T4) func(T5) func(T6) T7 {
|
func Curry7[FCT ~func(T0, T1, T2, T3, T4, T5, T6) T7, T0, T1, T2, T3, T4, T5, T6, T7 any](f FCT) func(T0) func(T1) func(T2) func(T3) func(T4) func(T5) func(T6) T7 {
|
||||||
return func(t0 T0) func(t1 T1) func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) T7 {
|
return func(t0 T0) func(t1 T1) func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) T7 {
|
||||||
return func(t1 T1) func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) T7 {
|
return func(t1 T1) func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) T7 {
|
||||||
return func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) T7 {
|
return func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) T7 {
|
||||||
@@ -480,7 +480,7 @@ func Curry7[T0, T1, T2, T3, T4, T5, T6, T7 any](f func(T0, T1, T2, T3, T4, T5, T
|
|||||||
|
|
||||||
// Uncurry7 takes a cascade of 7 functions each taking only one parameter and returns a function with 7 parameters .
|
// Uncurry7 takes a cascade of 7 functions each taking only one parameter and returns a function with 7 parameters .
|
||||||
// The inverse function is [Curry7]
|
// The inverse function is [Curry7]
|
||||||
func Uncurry7[T0, T1, T2, T3, T4, T5, T6, T7 any](f func(T0) func(T1) func(T2) func(T3) func(T4) func(T5) func(T6) T7) func(T0, T1, T2, T3, T4, T5, T6) T7 {
|
func Uncurry7[FCT ~func(T0) func(T1) func(T2) func(T3) func(T4) func(T5) func(T6) T7, T0, T1, T2, T3, T4, T5, T6, T7 any](f FCT) func(T0, T1, T2, T3, T4, T5, T6) T7 {
|
||||||
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6) T7 {
|
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6) T7 {
|
||||||
return f(t0)(t1)(t2)(t3)(t4)(t5)(t6)
|
return f(t0)(t1)(t2)(t3)(t4)(t5)(t6)
|
||||||
}
|
}
|
||||||
@@ -538,7 +538,7 @@ func Nullary8[F1 ~func() T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4,
|
|||||||
|
|
||||||
// Curry8 takes a function with 8 parameters and returns a cascade of functions each taking only one parameter.
|
// Curry8 takes a function with 8 parameters and returns a cascade of functions each taking only one parameter.
|
||||||
// The inverse function is [Uncurry8]
|
// The inverse function is [Uncurry8]
|
||||||
func Curry8[T0, T1, T2, T3, T4, T5, T6, T7, T8 any](f func(T0, T1, T2, T3, T4, T5, T6, T7) T8) func(T0) func(T1) func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) T8 {
|
func Curry8[FCT ~func(T0, T1, T2, T3, T4, T5, T6, T7) T8, T0, T1, T2, T3, T4, T5, T6, T7, T8 any](f FCT) func(T0) func(T1) func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) T8 {
|
||||||
return func(t0 T0) func(t1 T1) func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) func(t7 T7) T8 {
|
return func(t0 T0) func(t1 T1) func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) func(t7 T7) T8 {
|
||||||
return func(t1 T1) func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) func(t7 T7) T8 {
|
return func(t1 T1) func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) func(t7 T7) T8 {
|
||||||
return func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) func(t7 T7) T8 {
|
return func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) func(t7 T7) T8 {
|
||||||
@@ -560,7 +560,7 @@ func Curry8[T0, T1, T2, T3, T4, T5, T6, T7, T8 any](f func(T0, T1, T2, T3, T4, T
|
|||||||
|
|
||||||
// Uncurry8 takes a cascade of 8 functions each taking only one parameter and returns a function with 8 parameters .
|
// Uncurry8 takes a cascade of 8 functions each taking only one parameter and returns a function with 8 parameters .
|
||||||
// The inverse function is [Curry8]
|
// The inverse function is [Curry8]
|
||||||
func Uncurry8[T0, T1, T2, T3, T4, T5, T6, T7, T8 any](f func(T0) func(T1) func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) T8) func(T0, T1, T2, T3, T4, T5, T6, T7) T8 {
|
func Uncurry8[FCT ~func(T0) func(T1) func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) T8, T0, T1, T2, T3, T4, T5, T6, T7, T8 any](f FCT) func(T0, T1, T2, T3, T4, T5, T6, T7) T8 {
|
||||||
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6, t7 T7) T8 {
|
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6, t7 T7) T8 {
|
||||||
return f(t0)(t1)(t2)(t3)(t4)(t5)(t6)(t7)
|
return f(t0)(t1)(t2)(t3)(t4)(t5)(t6)(t7)
|
||||||
}
|
}
|
||||||
@@ -619,7 +619,7 @@ func Nullary9[F1 ~func() T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4,
|
|||||||
|
|
||||||
// Curry9 takes a function with 9 parameters and returns a cascade of functions each taking only one parameter.
|
// Curry9 takes a function with 9 parameters and returns a cascade of functions each taking only one parameter.
|
||||||
// The inverse function is [Uncurry9]
|
// The inverse function is [Uncurry9]
|
||||||
func Curry9[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9 any](f func(T0, T1, T2, T3, T4, T5, T6, T7, T8) T9) func(T0) func(T1) func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) T9 {
|
func Curry9[FCT ~func(T0, T1, T2, T3, T4, T5, T6, T7, T8) T9, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9 any](f FCT) func(T0) func(T1) func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) T9 {
|
||||||
return func(t0 T0) func(t1 T1) func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) func(t7 T7) func(t8 T8) T9 {
|
return func(t0 T0) func(t1 T1) func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) func(t7 T7) func(t8 T8) T9 {
|
||||||
return func(t1 T1) func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) func(t7 T7) func(t8 T8) T9 {
|
return func(t1 T1) func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) func(t7 T7) func(t8 T8) T9 {
|
||||||
return func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) func(t7 T7) func(t8 T8) T9 {
|
return func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) func(t7 T7) func(t8 T8) T9 {
|
||||||
@@ -643,7 +643,7 @@ func Curry9[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9 any](f func(T0, T1, T2, T3, T
|
|||||||
|
|
||||||
// Uncurry9 takes a cascade of 9 functions each taking only one parameter and returns a function with 9 parameters .
|
// Uncurry9 takes a cascade of 9 functions each taking only one parameter and returns a function with 9 parameters .
|
||||||
// The inverse function is [Curry9]
|
// The inverse function is [Curry9]
|
||||||
func Uncurry9[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9 any](f func(T0) func(T1) func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) T9) func(T0, T1, T2, T3, T4, T5, T6, T7, T8) T9 {
|
func Uncurry9[FCT ~func(T0) func(T1) func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) T9, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9 any](f FCT) func(T0, T1, T2, T3, T4, T5, T6, T7, T8) T9 {
|
||||||
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6, t7 T7, t8 T8) T9 {
|
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6, t7 T7, t8 T8) T9 {
|
||||||
return f(t0)(t1)(t2)(t3)(t4)(t5)(t6)(t7)(t8)
|
return f(t0)(t1)(t2)(t3)(t4)(t5)(t6)(t7)(t8)
|
||||||
}
|
}
|
||||||
@@ -703,7 +703,7 @@ func Nullary10[F1 ~func() T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4,
|
|||||||
|
|
||||||
// Curry10 takes a function with 10 parameters and returns a cascade of functions each taking only one parameter.
|
// Curry10 takes a function with 10 parameters and returns a cascade of functions each taking only one parameter.
|
||||||
// The inverse function is [Uncurry10]
|
// The inverse function is [Uncurry10]
|
||||||
func Curry10[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10 any](f func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9) T10) func(T0) func(T1) func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) T10 {
|
func Curry10[FCT ~func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9) T10, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10 any](f FCT) func(T0) func(T1) func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) T10 {
|
||||||
return func(t0 T0) func(t1 T1) func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) func(t7 T7) func(t8 T8) func(t9 T9) T10 {
|
return func(t0 T0) func(t1 T1) func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) func(t7 T7) func(t8 T8) func(t9 T9) T10 {
|
||||||
return func(t1 T1) func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) func(t7 T7) func(t8 T8) func(t9 T9) T10 {
|
return func(t1 T1) func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) func(t7 T7) func(t8 T8) func(t9 T9) T10 {
|
||||||
return func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) func(t7 T7) func(t8 T8) func(t9 T9) T10 {
|
return func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) func(t7 T7) func(t8 T8) func(t9 T9) T10 {
|
||||||
@@ -729,7 +729,7 @@ func Curry10[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10 any](f func(T0, T1, T2,
|
|||||||
|
|
||||||
// Uncurry10 takes a cascade of 10 functions each taking only one parameter and returns a function with 10 parameters .
|
// Uncurry10 takes a cascade of 10 functions each taking only one parameter and returns a function with 10 parameters .
|
||||||
// The inverse function is [Curry10]
|
// The inverse function is [Curry10]
|
||||||
func Uncurry10[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10 any](f func(T0) func(T1) func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) T10) func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9) T10 {
|
func Uncurry10[FCT ~func(T0) func(T1) func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) T10, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10 any](f FCT) func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9) T10 {
|
||||||
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6, t7 T7, t8 T8, t9 T9) T10 {
|
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6, t7 T7, t8 T8, t9 T9) T10 {
|
||||||
return f(t0)(t1)(t2)(t3)(t4)(t5)(t6)(t7)(t8)(t9)
|
return f(t0)(t1)(t2)(t3)(t4)(t5)(t6)(t7)(t8)(t9)
|
||||||
}
|
}
|
||||||
@@ -790,7 +790,7 @@ func Nullary11[F1 ~func() T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4,
|
|||||||
|
|
||||||
// Curry11 takes a function with 11 parameters and returns a cascade of functions each taking only one parameter.
|
// Curry11 takes a function with 11 parameters and returns a cascade of functions each taking only one parameter.
|
||||||
// The inverse function is [Uncurry11]
|
// The inverse function is [Uncurry11]
|
||||||
func Curry11[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11 any](f func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10) T11) func(T0) func(T1) func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) T11 {
|
func Curry11[FCT ~func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10) T11, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11 any](f FCT) func(T0) func(T1) func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) T11 {
|
||||||
return func(t0 T0) func(t1 T1) func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) func(t7 T7) func(t8 T8) func(t9 T9) func(t10 T10) T11 {
|
return func(t0 T0) func(t1 T1) func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) func(t7 T7) func(t8 T8) func(t9 T9) func(t10 T10) T11 {
|
||||||
return func(t1 T1) func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) func(t7 T7) func(t8 T8) func(t9 T9) func(t10 T10) T11 {
|
return func(t1 T1) func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) func(t7 T7) func(t8 T8) func(t9 T9) func(t10 T10) T11 {
|
||||||
return func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) func(t7 T7) func(t8 T8) func(t9 T9) func(t10 T10) T11 {
|
return func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) func(t7 T7) func(t8 T8) func(t9 T9) func(t10 T10) T11 {
|
||||||
@@ -818,7 +818,7 @@ func Curry11[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11 any](f func(T0, T1
|
|||||||
|
|
||||||
// Uncurry11 takes a cascade of 11 functions each taking only one parameter and returns a function with 11 parameters .
|
// Uncurry11 takes a cascade of 11 functions each taking only one parameter and returns a function with 11 parameters .
|
||||||
// The inverse function is [Curry11]
|
// The inverse function is [Curry11]
|
||||||
func Uncurry11[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11 any](f func(T0) func(T1) func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) T11) func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10) T11 {
|
func Uncurry11[FCT ~func(T0) func(T1) func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) T11, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11 any](f FCT) func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10) T11 {
|
||||||
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6, t7 T7, t8 T8, t9 T9, t10 T10) T11 {
|
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6, t7 T7, t8 T8, t9 T9, t10 T10) T11 {
|
||||||
return f(t0)(t1)(t2)(t3)(t4)(t5)(t6)(t7)(t8)(t9)(t10)
|
return f(t0)(t1)(t2)(t3)(t4)(t5)(t6)(t7)(t8)(t9)(t10)
|
||||||
}
|
}
|
||||||
@@ -880,7 +880,7 @@ func Nullary12[F1 ~func() T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4,
|
|||||||
|
|
||||||
// Curry12 takes a function with 12 parameters and returns a cascade of functions each taking only one parameter.
|
// Curry12 takes a function with 12 parameters and returns a cascade of functions each taking only one parameter.
|
||||||
// The inverse function is [Uncurry12]
|
// The inverse function is [Uncurry12]
|
||||||
func Curry12[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12 any](f func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11) T12) func(T0) func(T1) func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) T12 {
|
func Curry12[FCT ~func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11) T12, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12 any](f FCT) func(T0) func(T1) func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) T12 {
|
||||||
return func(t0 T0) func(t1 T1) func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) func(t7 T7) func(t8 T8) func(t9 T9) func(t10 T10) func(t11 T11) T12 {
|
return func(t0 T0) func(t1 T1) func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) func(t7 T7) func(t8 T8) func(t9 T9) func(t10 T10) func(t11 T11) T12 {
|
||||||
return func(t1 T1) func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) func(t7 T7) func(t8 T8) func(t9 T9) func(t10 T10) func(t11 T11) T12 {
|
return func(t1 T1) func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) func(t7 T7) func(t8 T8) func(t9 T9) func(t10 T10) func(t11 T11) T12 {
|
||||||
return func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) func(t7 T7) func(t8 T8) func(t9 T9) func(t10 T10) func(t11 T11) T12 {
|
return func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) func(t7 T7) func(t8 T8) func(t9 T9) func(t10 T10) func(t11 T11) T12 {
|
||||||
@@ -910,7 +910,7 @@ func Curry12[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12 any](f func(T
|
|||||||
|
|
||||||
// Uncurry12 takes a cascade of 12 functions each taking only one parameter and returns a function with 12 parameters .
|
// Uncurry12 takes a cascade of 12 functions each taking only one parameter and returns a function with 12 parameters .
|
||||||
// The inverse function is [Curry12]
|
// The inverse function is [Curry12]
|
||||||
func Uncurry12[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12 any](f func(T0) func(T1) func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) T12) func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11) T12 {
|
func Uncurry12[FCT ~func(T0) func(T1) func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) T12, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12 any](f FCT) func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11) T12 {
|
||||||
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6, t7 T7, t8 T8, t9 T9, t10 T10, t11 T11) T12 {
|
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6, t7 T7, t8 T8, t9 T9, t10 T10, t11 T11) T12 {
|
||||||
return f(t0)(t1)(t2)(t3)(t4)(t5)(t6)(t7)(t8)(t9)(t10)(t11)
|
return f(t0)(t1)(t2)(t3)(t4)(t5)(t6)(t7)(t8)(t9)(t10)(t11)
|
||||||
}
|
}
|
||||||
@@ -973,7 +973,7 @@ func Nullary13[F1 ~func() T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4,
|
|||||||
|
|
||||||
// Curry13 takes a function with 13 parameters and returns a cascade of functions each taking only one parameter.
|
// Curry13 takes a function with 13 parameters and returns a cascade of functions each taking only one parameter.
|
||||||
// The inverse function is [Uncurry13]
|
// The inverse function is [Uncurry13]
|
||||||
func Curry13[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13 any](f func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12) T13) func(T0) func(T1) func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) T13 {
|
func Curry13[FCT ~func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12) T13, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13 any](f FCT) func(T0) func(T1) func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) T13 {
|
||||||
return func(t0 T0) func(t1 T1) func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) func(t7 T7) func(t8 T8) func(t9 T9) func(t10 T10) func(t11 T11) func(t12 T12) T13 {
|
return func(t0 T0) func(t1 T1) func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) func(t7 T7) func(t8 T8) func(t9 T9) func(t10 T10) func(t11 T11) func(t12 T12) T13 {
|
||||||
return func(t1 T1) func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) func(t7 T7) func(t8 T8) func(t9 T9) func(t10 T10) func(t11 T11) func(t12 T12) T13 {
|
return func(t1 T1) func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) func(t7 T7) func(t8 T8) func(t9 T9) func(t10 T10) func(t11 T11) func(t12 T12) T13 {
|
||||||
return func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) func(t7 T7) func(t8 T8) func(t9 T9) func(t10 T10) func(t11 T11) func(t12 T12) T13 {
|
return func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) func(t7 T7) func(t8 T8) func(t9 T9) func(t10 T10) func(t11 T11) func(t12 T12) T13 {
|
||||||
@@ -1005,7 +1005,7 @@ func Curry13[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13 any](f f
|
|||||||
|
|
||||||
// Uncurry13 takes a cascade of 13 functions each taking only one parameter and returns a function with 13 parameters .
|
// Uncurry13 takes a cascade of 13 functions each taking only one parameter and returns a function with 13 parameters .
|
||||||
// The inverse function is [Curry13]
|
// The inverse function is [Curry13]
|
||||||
func Uncurry13[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13 any](f func(T0) func(T1) func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) T13) func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12) T13 {
|
func Uncurry13[FCT ~func(T0) func(T1) func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) T13, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13 any](f FCT) func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12) T13 {
|
||||||
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6, t7 T7, t8 T8, t9 T9, t10 T10, t11 T11, t12 T12) T13 {
|
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6, t7 T7, t8 T8, t9 T9, t10 T10, t11 T11, t12 T12) T13 {
|
||||||
return f(t0)(t1)(t2)(t3)(t4)(t5)(t6)(t7)(t8)(t9)(t10)(t11)(t12)
|
return f(t0)(t1)(t2)(t3)(t4)(t5)(t6)(t7)(t8)(t9)(t10)(t11)(t12)
|
||||||
}
|
}
|
||||||
@@ -1069,7 +1069,7 @@ func Nullary14[F1 ~func() T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4,
|
|||||||
|
|
||||||
// Curry14 takes a function with 14 parameters and returns a cascade of functions each taking only one parameter.
|
// Curry14 takes a function with 14 parameters and returns a cascade of functions each taking only one parameter.
|
||||||
// The inverse function is [Uncurry14]
|
// The inverse function is [Uncurry14]
|
||||||
func Curry14[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14 any](f func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13) T14) func(T0) func(T1) func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) func(T13) T14 {
|
func Curry14[FCT ~func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13) T14, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14 any](f FCT) func(T0) func(T1) func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) func(T13) T14 {
|
||||||
return func(t0 T0) func(t1 T1) func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) func(t7 T7) func(t8 T8) func(t9 T9) func(t10 T10) func(t11 T11) func(t12 T12) func(t13 T13) T14 {
|
return func(t0 T0) func(t1 T1) func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) func(t7 T7) func(t8 T8) func(t9 T9) func(t10 T10) func(t11 T11) func(t12 T12) func(t13 T13) T14 {
|
||||||
return func(t1 T1) func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) func(t7 T7) func(t8 T8) func(t9 T9) func(t10 T10) func(t11 T11) func(t12 T12) func(t13 T13) T14 {
|
return func(t1 T1) func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) func(t7 T7) func(t8 T8) func(t9 T9) func(t10 T10) func(t11 T11) func(t12 T12) func(t13 T13) T14 {
|
||||||
return func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) func(t7 T7) func(t8 T8) func(t9 T9) func(t10 T10) func(t11 T11) func(t12 T12) func(t13 T13) T14 {
|
return func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) func(t7 T7) func(t8 T8) func(t9 T9) func(t10 T10) func(t11 T11) func(t12 T12) func(t13 T13) T14 {
|
||||||
@@ -1103,7 +1103,7 @@ func Curry14[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14 any
|
|||||||
|
|
||||||
// Uncurry14 takes a cascade of 14 functions each taking only one parameter and returns a function with 14 parameters .
|
// Uncurry14 takes a cascade of 14 functions each taking only one parameter and returns a function with 14 parameters .
|
||||||
// The inverse function is [Curry14]
|
// The inverse function is [Curry14]
|
||||||
func Uncurry14[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14 any](f func(T0) func(T1) func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) func(T13) T14) func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13) T14 {
|
func Uncurry14[FCT ~func(T0) func(T1) func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) func(T13) T14, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14 any](f FCT) func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13) T14 {
|
||||||
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6, t7 T7, t8 T8, t9 T9, t10 T10, t11 T11, t12 T12, t13 T13) T14 {
|
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6, t7 T7, t8 T8, t9 T9, t10 T10, t11 T11, t12 T12, t13 T13) T14 {
|
||||||
return f(t0)(t1)(t2)(t3)(t4)(t5)(t6)(t7)(t8)(t9)(t10)(t11)(t12)(t13)
|
return f(t0)(t1)(t2)(t3)(t4)(t5)(t6)(t7)(t8)(t9)(t10)(t11)(t12)(t13)
|
||||||
}
|
}
|
||||||
@@ -1168,7 +1168,7 @@ func Nullary15[F1 ~func() T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4,
|
|||||||
|
|
||||||
// Curry15 takes a function with 15 parameters and returns a cascade of functions each taking only one parameter.
|
// Curry15 takes a function with 15 parameters and returns a cascade of functions each taking only one parameter.
|
||||||
// The inverse function is [Uncurry15]
|
// The inverse function is [Uncurry15]
|
||||||
func Curry15[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15 any](f func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14) T15) func(T0) func(T1) func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) func(T13) func(T14) T15 {
|
func Curry15[FCT ~func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14) T15, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15 any](f FCT) func(T0) func(T1) func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) func(T13) func(T14) T15 {
|
||||||
return func(t0 T0) func(t1 T1) func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) func(t7 T7) func(t8 T8) func(t9 T9) func(t10 T10) func(t11 T11) func(t12 T12) func(t13 T13) func(t14 T14) T15 {
|
return func(t0 T0) func(t1 T1) func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) func(t7 T7) func(t8 T8) func(t9 T9) func(t10 T10) func(t11 T11) func(t12 T12) func(t13 T13) func(t14 T14) T15 {
|
||||||
return func(t1 T1) func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) func(t7 T7) func(t8 T8) func(t9 T9) func(t10 T10) func(t11 T11) func(t12 T12) func(t13 T13) func(t14 T14) T15 {
|
return func(t1 T1) func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) func(t7 T7) func(t8 T8) func(t9 T9) func(t10 T10) func(t11 T11) func(t12 T12) func(t13 T13) func(t14 T14) T15 {
|
||||||
return func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) func(t7 T7) func(t8 T8) func(t9 T9) func(t10 T10) func(t11 T11) func(t12 T12) func(t13 T13) func(t14 T14) T15 {
|
return func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) func(t7 T7) func(t8 T8) func(t9 T9) func(t10 T10) func(t11 T11) func(t12 T12) func(t13 T13) func(t14 T14) T15 {
|
||||||
@@ -1204,7 +1204,7 @@ func Curry15[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T1
|
|||||||
|
|
||||||
// Uncurry15 takes a cascade of 15 functions each taking only one parameter and returns a function with 15 parameters .
|
// Uncurry15 takes a cascade of 15 functions each taking only one parameter and returns a function with 15 parameters .
|
||||||
// The inverse function is [Curry15]
|
// The inverse function is [Curry15]
|
||||||
func Uncurry15[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15 any](f func(T0) func(T1) func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) func(T13) func(T14) T15) func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14) T15 {
|
func Uncurry15[FCT ~func(T0) func(T1) func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) func(T13) func(T14) T15, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15 any](f FCT) func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14) T15 {
|
||||||
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6, t7 T7, t8 T8, t9 T9, t10 T10, t11 T11, t12 T12, t13 T13, t14 T14) T15 {
|
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6, t7 T7, t8 T8, t9 T9, t10 T10, t11 T11, t12 T12, t13 T13, t14 T14) T15 {
|
||||||
return f(t0)(t1)(t2)(t3)(t4)(t5)(t6)(t7)(t8)(t9)(t10)(t11)(t12)(t13)(t14)
|
return f(t0)(t1)(t2)(t3)(t4)(t5)(t6)(t7)(t8)(t9)(t10)(t11)(t12)(t13)(t14)
|
||||||
}
|
}
|
||||||
@@ -1270,7 +1270,7 @@ func Nullary16[F1 ~func() T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4,
|
|||||||
|
|
||||||
// Curry16 takes a function with 16 parameters and returns a cascade of functions each taking only one parameter.
|
// Curry16 takes a function with 16 parameters and returns a cascade of functions each taking only one parameter.
|
||||||
// The inverse function is [Uncurry16]
|
// The inverse function is [Uncurry16]
|
||||||
func Curry16[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16 any](f func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15) T16) func(T0) func(T1) func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) func(T13) func(T14) func(T15) T16 {
|
func Curry16[FCT ~func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15) T16, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16 any](f FCT) func(T0) func(T1) func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) func(T13) func(T14) func(T15) T16 {
|
||||||
return func(t0 T0) func(t1 T1) func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) func(t7 T7) func(t8 T8) func(t9 T9) func(t10 T10) func(t11 T11) func(t12 T12) func(t13 T13) func(t14 T14) func(t15 T15) T16 {
|
return func(t0 T0) func(t1 T1) func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) func(t7 T7) func(t8 T8) func(t9 T9) func(t10 T10) func(t11 T11) func(t12 T12) func(t13 T13) func(t14 T14) func(t15 T15) T16 {
|
||||||
return func(t1 T1) func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) func(t7 T7) func(t8 T8) func(t9 T9) func(t10 T10) func(t11 T11) func(t12 T12) func(t13 T13) func(t14 T14) func(t15 T15) T16 {
|
return func(t1 T1) func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) func(t7 T7) func(t8 T8) func(t9 T9) func(t10 T10) func(t11 T11) func(t12 T12) func(t13 T13) func(t14 T14) func(t15 T15) T16 {
|
||||||
return func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) func(t7 T7) func(t8 T8) func(t9 T9) func(t10 T10) func(t11 T11) func(t12 T12) func(t13 T13) func(t14 T14) func(t15 T15) T16 {
|
return func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) func(t7 T7) func(t8 T8) func(t9 T9) func(t10 T10) func(t11 T11) func(t12 T12) func(t13 T13) func(t14 T14) func(t15 T15) T16 {
|
||||||
@@ -1308,7 +1308,7 @@ func Curry16[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T1
|
|||||||
|
|
||||||
// Uncurry16 takes a cascade of 16 functions each taking only one parameter and returns a function with 16 parameters .
|
// Uncurry16 takes a cascade of 16 functions each taking only one parameter and returns a function with 16 parameters .
|
||||||
// The inverse function is [Curry16]
|
// The inverse function is [Curry16]
|
||||||
func Uncurry16[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16 any](f func(T0) func(T1) func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) func(T13) func(T14) func(T15) T16) func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15) T16 {
|
func Uncurry16[FCT ~func(T0) func(T1) func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) func(T13) func(T14) func(T15) T16, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16 any](f FCT) func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15) T16 {
|
||||||
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6, t7 T7, t8 T8, t9 T9, t10 T10, t11 T11, t12 T12, t13 T13, t14 T14, t15 T15) T16 {
|
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6, t7 T7, t8 T8, t9 T9, t10 T10, t11 T11, t12 T12, t13 T13, t14 T14, t15 T15) T16 {
|
||||||
return f(t0)(t1)(t2)(t3)(t4)(t5)(t6)(t7)(t8)(t9)(t10)(t11)(t12)(t13)(t14)(t15)
|
return f(t0)(t1)(t2)(t3)(t4)(t5)(t6)(t7)(t8)(t9)(t10)(t11)(t12)(t13)(t14)(t15)
|
||||||
}
|
}
|
||||||
@@ -1375,7 +1375,7 @@ func Nullary17[F1 ~func() T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4,
|
|||||||
|
|
||||||
// Curry17 takes a function with 17 parameters and returns a cascade of functions each taking only one parameter.
|
// Curry17 takes a function with 17 parameters and returns a cascade of functions each taking only one parameter.
|
||||||
// The inverse function is [Uncurry17]
|
// The inverse function is [Uncurry17]
|
||||||
func Curry17[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17 any](f func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16) T17) func(T0) func(T1) func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) func(T13) func(T14) func(T15) func(T16) T17 {
|
func Curry17[FCT ~func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16) T17, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17 any](f FCT) func(T0) func(T1) func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) func(T13) func(T14) func(T15) func(T16) T17 {
|
||||||
return func(t0 T0) func(t1 T1) func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) func(t7 T7) func(t8 T8) func(t9 T9) func(t10 T10) func(t11 T11) func(t12 T12) func(t13 T13) func(t14 T14) func(t15 T15) func(t16 T16) T17 {
|
return func(t0 T0) func(t1 T1) func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) func(t7 T7) func(t8 T8) func(t9 T9) func(t10 T10) func(t11 T11) func(t12 T12) func(t13 T13) func(t14 T14) func(t15 T15) func(t16 T16) T17 {
|
||||||
return func(t1 T1) func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) func(t7 T7) func(t8 T8) func(t9 T9) func(t10 T10) func(t11 T11) func(t12 T12) func(t13 T13) func(t14 T14) func(t15 T15) func(t16 T16) T17 {
|
return func(t1 T1) func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) func(t7 T7) func(t8 T8) func(t9 T9) func(t10 T10) func(t11 T11) func(t12 T12) func(t13 T13) func(t14 T14) func(t15 T15) func(t16 T16) T17 {
|
||||||
return func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) func(t7 T7) func(t8 T8) func(t9 T9) func(t10 T10) func(t11 T11) func(t12 T12) func(t13 T13) func(t14 T14) func(t15 T15) func(t16 T16) T17 {
|
return func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) func(t7 T7) func(t8 T8) func(t9 T9) func(t10 T10) func(t11 T11) func(t12 T12) func(t13 T13) func(t14 T14) func(t15 T15) func(t16 T16) T17 {
|
||||||
@@ -1415,7 +1415,7 @@ func Curry17[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T1
|
|||||||
|
|
||||||
// Uncurry17 takes a cascade of 17 functions each taking only one parameter and returns a function with 17 parameters .
|
// Uncurry17 takes a cascade of 17 functions each taking only one parameter and returns a function with 17 parameters .
|
||||||
// The inverse function is [Curry17]
|
// The inverse function is [Curry17]
|
||||||
func Uncurry17[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17 any](f func(T0) func(T1) func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) func(T13) func(T14) func(T15) func(T16) T17) func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16) T17 {
|
func Uncurry17[FCT ~func(T0) func(T1) func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) func(T13) func(T14) func(T15) func(T16) T17, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17 any](f FCT) func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16) T17 {
|
||||||
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6, t7 T7, t8 T8, t9 T9, t10 T10, t11 T11, t12 T12, t13 T13, t14 T14, t15 T15, t16 T16) T17 {
|
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6, t7 T7, t8 T8, t9 T9, t10 T10, t11 T11, t12 T12, t13 T13, t14 T14, t15 T15, t16 T16) T17 {
|
||||||
return f(t0)(t1)(t2)(t3)(t4)(t5)(t6)(t7)(t8)(t9)(t10)(t11)(t12)(t13)(t14)(t15)(t16)
|
return f(t0)(t1)(t2)(t3)(t4)(t5)(t6)(t7)(t8)(t9)(t10)(t11)(t12)(t13)(t14)(t15)(t16)
|
||||||
}
|
}
|
||||||
@@ -1483,7 +1483,7 @@ func Nullary18[F1 ~func() T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4,
|
|||||||
|
|
||||||
// Curry18 takes a function with 18 parameters and returns a cascade of functions each taking only one parameter.
|
// Curry18 takes a function with 18 parameters and returns a cascade of functions each taking only one parameter.
|
||||||
// The inverse function is [Uncurry18]
|
// The inverse function is [Uncurry18]
|
||||||
func Curry18[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18 any](f func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17) T18) func(T0) func(T1) func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) func(T13) func(T14) func(T15) func(T16) func(T17) T18 {
|
func Curry18[FCT ~func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17) T18, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18 any](f FCT) func(T0) func(T1) func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) func(T13) func(T14) func(T15) func(T16) func(T17) T18 {
|
||||||
return func(t0 T0) func(t1 T1) func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) func(t7 T7) func(t8 T8) func(t9 T9) func(t10 T10) func(t11 T11) func(t12 T12) func(t13 T13) func(t14 T14) func(t15 T15) func(t16 T16) func(t17 T17) T18 {
|
return func(t0 T0) func(t1 T1) func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) func(t7 T7) func(t8 T8) func(t9 T9) func(t10 T10) func(t11 T11) func(t12 T12) func(t13 T13) func(t14 T14) func(t15 T15) func(t16 T16) func(t17 T17) T18 {
|
||||||
return func(t1 T1) func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) func(t7 T7) func(t8 T8) func(t9 T9) func(t10 T10) func(t11 T11) func(t12 T12) func(t13 T13) func(t14 T14) func(t15 T15) func(t16 T16) func(t17 T17) T18 {
|
return func(t1 T1) func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) func(t7 T7) func(t8 T8) func(t9 T9) func(t10 T10) func(t11 T11) func(t12 T12) func(t13 T13) func(t14 T14) func(t15 T15) func(t16 T16) func(t17 T17) T18 {
|
||||||
return func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) func(t7 T7) func(t8 T8) func(t9 T9) func(t10 T10) func(t11 T11) func(t12 T12) func(t13 T13) func(t14 T14) func(t15 T15) func(t16 T16) func(t17 T17) T18 {
|
return func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) func(t7 T7) func(t8 T8) func(t9 T9) func(t10 T10) func(t11 T11) func(t12 T12) func(t13 T13) func(t14 T14) func(t15 T15) func(t16 T16) func(t17 T17) T18 {
|
||||||
@@ -1525,7 +1525,7 @@ func Curry18[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T1
|
|||||||
|
|
||||||
// Uncurry18 takes a cascade of 18 functions each taking only one parameter and returns a function with 18 parameters .
|
// Uncurry18 takes a cascade of 18 functions each taking only one parameter and returns a function with 18 parameters .
|
||||||
// The inverse function is [Curry18]
|
// The inverse function is [Curry18]
|
||||||
func Uncurry18[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18 any](f func(T0) func(T1) func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) func(T13) func(T14) func(T15) func(T16) func(T17) T18) func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17) T18 {
|
func Uncurry18[FCT ~func(T0) func(T1) func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) func(T13) func(T14) func(T15) func(T16) func(T17) T18, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18 any](f FCT) func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17) T18 {
|
||||||
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6, t7 T7, t8 T8, t9 T9, t10 T10, t11 T11, t12 T12, t13 T13, t14 T14, t15 T15, t16 T16, t17 T17) T18 {
|
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6, t7 T7, t8 T8, t9 T9, t10 T10, t11 T11, t12 T12, t13 T13, t14 T14, t15 T15, t16 T16, t17 T17) T18 {
|
||||||
return f(t0)(t1)(t2)(t3)(t4)(t5)(t6)(t7)(t8)(t9)(t10)(t11)(t12)(t13)(t14)(t15)(t16)(t17)
|
return f(t0)(t1)(t2)(t3)(t4)(t5)(t6)(t7)(t8)(t9)(t10)(t11)(t12)(t13)(t14)(t15)(t16)(t17)
|
||||||
}
|
}
|
||||||
@@ -1594,7 +1594,7 @@ func Nullary19[F1 ~func() T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4,
|
|||||||
|
|
||||||
// Curry19 takes a function with 19 parameters and returns a cascade of functions each taking only one parameter.
|
// Curry19 takes a function with 19 parameters and returns a cascade of functions each taking only one parameter.
|
||||||
// The inverse function is [Uncurry19]
|
// The inverse function is [Uncurry19]
|
||||||
func Curry19[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19 any](f func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18) T19) func(T0) func(T1) func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) func(T13) func(T14) func(T15) func(T16) func(T17) func(T18) T19 {
|
func Curry19[FCT ~func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18) T19, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19 any](f FCT) func(T0) func(T1) func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) func(T13) func(T14) func(T15) func(T16) func(T17) func(T18) T19 {
|
||||||
return func(t0 T0) func(t1 T1) func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) func(t7 T7) func(t8 T8) func(t9 T9) func(t10 T10) func(t11 T11) func(t12 T12) func(t13 T13) func(t14 T14) func(t15 T15) func(t16 T16) func(t17 T17) func(t18 T18) T19 {
|
return func(t0 T0) func(t1 T1) func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) func(t7 T7) func(t8 T8) func(t9 T9) func(t10 T10) func(t11 T11) func(t12 T12) func(t13 T13) func(t14 T14) func(t15 T15) func(t16 T16) func(t17 T17) func(t18 T18) T19 {
|
||||||
return func(t1 T1) func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) func(t7 T7) func(t8 T8) func(t9 T9) func(t10 T10) func(t11 T11) func(t12 T12) func(t13 T13) func(t14 T14) func(t15 T15) func(t16 T16) func(t17 T17) func(t18 T18) T19 {
|
return func(t1 T1) func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) func(t7 T7) func(t8 T8) func(t9 T9) func(t10 T10) func(t11 T11) func(t12 T12) func(t13 T13) func(t14 T14) func(t15 T15) func(t16 T16) func(t17 T17) func(t18 T18) T19 {
|
||||||
return func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) func(t7 T7) func(t8 T8) func(t9 T9) func(t10 T10) func(t11 T11) func(t12 T12) func(t13 T13) func(t14 T14) func(t15 T15) func(t16 T16) func(t17 T17) func(t18 T18) T19 {
|
return func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) func(t7 T7) func(t8 T8) func(t9 T9) func(t10 T10) func(t11 T11) func(t12 T12) func(t13 T13) func(t14 T14) func(t15 T15) func(t16 T16) func(t17 T17) func(t18 T18) T19 {
|
||||||
@@ -1638,7 +1638,7 @@ func Curry19[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T1
|
|||||||
|
|
||||||
// Uncurry19 takes a cascade of 19 functions each taking only one parameter and returns a function with 19 parameters .
|
// Uncurry19 takes a cascade of 19 functions each taking only one parameter and returns a function with 19 parameters .
|
||||||
// The inverse function is [Curry19]
|
// The inverse function is [Curry19]
|
||||||
func Uncurry19[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19 any](f func(T0) func(T1) func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) func(T13) func(T14) func(T15) func(T16) func(T17) func(T18) T19) func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18) T19 {
|
func Uncurry19[FCT ~func(T0) func(T1) func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) func(T13) func(T14) func(T15) func(T16) func(T17) func(T18) T19, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19 any](f FCT) func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18) T19 {
|
||||||
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6, t7 T7, t8 T8, t9 T9, t10 T10, t11 T11, t12 T12, t13 T13, t14 T14, t15 T15, t16 T16, t17 T17, t18 T18) T19 {
|
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6, t7 T7, t8 T8, t9 T9, t10 T10, t11 T11, t12 T12, t13 T13, t14 T14, t15 T15, t16 T16, t17 T17, t18 T18) T19 {
|
||||||
return f(t0)(t1)(t2)(t3)(t4)(t5)(t6)(t7)(t8)(t9)(t10)(t11)(t12)(t13)(t14)(t15)(t16)(t17)(t18)
|
return f(t0)(t1)(t2)(t3)(t4)(t5)(t6)(t7)(t8)(t9)(t10)(t11)(t12)(t13)(t14)(t15)(t16)(t17)(t18)
|
||||||
}
|
}
|
||||||
@@ -1708,7 +1708,7 @@ func Nullary20[F1 ~func() T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4,
|
|||||||
|
|
||||||
// Curry20 takes a function with 20 parameters and returns a cascade of functions each taking only one parameter.
|
// Curry20 takes a function with 20 parameters and returns a cascade of functions each taking only one parameter.
|
||||||
// The inverse function is [Uncurry20]
|
// The inverse function is [Uncurry20]
|
||||||
func Curry20[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20 any](f func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19) T20) func(T0) func(T1) func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) func(T13) func(T14) func(T15) func(T16) func(T17) func(T18) func(T19) T20 {
|
func Curry20[FCT ~func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19) T20, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20 any](f FCT) func(T0) func(T1) func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) func(T13) func(T14) func(T15) func(T16) func(T17) func(T18) func(T19) T20 {
|
||||||
return func(t0 T0) func(t1 T1) func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) func(t7 T7) func(t8 T8) func(t9 T9) func(t10 T10) func(t11 T11) func(t12 T12) func(t13 T13) func(t14 T14) func(t15 T15) func(t16 T16) func(t17 T17) func(t18 T18) func(t19 T19) T20 {
|
return func(t0 T0) func(t1 T1) func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) func(t7 T7) func(t8 T8) func(t9 T9) func(t10 T10) func(t11 T11) func(t12 T12) func(t13 T13) func(t14 T14) func(t15 T15) func(t16 T16) func(t17 T17) func(t18 T18) func(t19 T19) T20 {
|
||||||
return func(t1 T1) func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) func(t7 T7) func(t8 T8) func(t9 T9) func(t10 T10) func(t11 T11) func(t12 T12) func(t13 T13) func(t14 T14) func(t15 T15) func(t16 T16) func(t17 T17) func(t18 T18) func(t19 T19) T20 {
|
return func(t1 T1) func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) func(t7 T7) func(t8 T8) func(t9 T9) func(t10 T10) func(t11 T11) func(t12 T12) func(t13 T13) func(t14 T14) func(t15 T15) func(t16 T16) func(t17 T17) func(t18 T18) func(t19 T19) T20 {
|
||||||
return func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) func(t7 T7) func(t8 T8) func(t9 T9) func(t10 T10) func(t11 T11) func(t12 T12) func(t13 T13) func(t14 T14) func(t15 T15) func(t16 T16) func(t17 T17) func(t18 T18) func(t19 T19) T20 {
|
return func(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) func(t7 T7) func(t8 T8) func(t9 T9) func(t10 T10) func(t11 T11) func(t12 T12) func(t13 T13) func(t14 T14) func(t15 T15) func(t16 T16) func(t17 T17) func(t18 T18) func(t19 T19) T20 {
|
||||||
@@ -1754,7 +1754,7 @@ func Curry20[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T1
|
|||||||
|
|
||||||
// Uncurry20 takes a cascade of 20 functions each taking only one parameter and returns a function with 20 parameters .
|
// Uncurry20 takes a cascade of 20 functions each taking only one parameter and returns a function with 20 parameters .
|
||||||
// The inverse function is [Curry20]
|
// The inverse function is [Curry20]
|
||||||
func Uncurry20[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20 any](f func(T0) func(T1) func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) func(T13) func(T14) func(T15) func(T16) func(T17) func(T18) func(T19) T20) func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19) T20 {
|
func Uncurry20[FCT ~func(T0) func(T1) func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) func(T13) func(T14) func(T15) func(T16) func(T17) func(T18) func(T19) T20, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20 any](f FCT) func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19) T20 {
|
||||||
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6, t7 T7, t8 T8, t9 T9, t10 T10, t11 T11, t12 T12, t13 T13, t14 T14, t15 T15, t16 T16, t17 T17, t18 T18, t19 T19) T20 {
|
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6, t7 T7, t8 T8, t9 T9, t10 T10, t11 T11, t12 T12, t13 T13, t14 T14, t15 T15, t16 T16, t17 T17, t18 T18, t19 T19) T20 {
|
||||||
return f(t0)(t1)(t2)(t3)(t4)(t5)(t6)(t7)(t8)(t9)(t10)(t11)(t12)(t13)(t14)(t15)(t16)(t17)(t18)(t19)
|
return f(t0)(t1)(t2)(t3)(t4)(t5)(t6)(t7)(t8)(t9)(t10)(t11)(t12)(t13)(t14)(t15)(t16)(t17)(t18)(t19)
|
||||||
}
|
}
|
||||||
|
@@ -28,7 +28,7 @@ func Memoize[F ~func(K) T, K comparable, T any](f F) F {
|
|||||||
|
|
||||||
// ContramapMemoize converts a unary function into a unary function that caches the value depending on the parameter
|
// ContramapMemoize converts a unary function into a unary function that caches the value depending on the parameter
|
||||||
func ContramapMemoize[F ~func(A) T, KF func(A) K, A any, K comparable, T any](kf KF) func(F) F {
|
func ContramapMemoize[F ~func(A) T, KF func(A) K, A any, K comparable, T any](kf KF) func(F) F {
|
||||||
return CacheCallback[F](kf, getOrCreate[K, T]())
|
return CacheCallback[func(F) F, func() func() T](kf, getOrCreate[K, T]())
|
||||||
}
|
}
|
||||||
|
|
||||||
// getOrCreate is a naive implementation of a cache, without bounds
|
// getOrCreate is a naive implementation of a cache, without bounds
|
||||||
@@ -50,13 +50,51 @@ func getOrCreate[K comparable, T any]() func(K, func() func() T) func() T {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SingleElementCache is a cache with a capacity of a single element
|
||||||
|
func SingleElementCache[
|
||||||
|
LLT ~func() LT, // generator of the generator
|
||||||
|
K comparable, // key into the cache
|
||||||
|
LT ~func() T, // generator of a value
|
||||||
|
T any, // the cached data type
|
||||||
|
]() func(K, LLT) LT {
|
||||||
|
var l sync.Mutex
|
||||||
|
|
||||||
|
var key K
|
||||||
|
var value LT
|
||||||
|
hasKey := false
|
||||||
|
|
||||||
|
return func(k K, gen LLT) LT {
|
||||||
|
l.Lock()
|
||||||
|
|
||||||
|
existing := value
|
||||||
|
if !hasKey || key != k {
|
||||||
|
existing = gen()
|
||||||
|
// update state
|
||||||
|
key = k
|
||||||
|
value = existing
|
||||||
|
hasKey = true
|
||||||
|
}
|
||||||
|
|
||||||
|
l.Unlock()
|
||||||
|
|
||||||
|
return existing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// CacheCallback converts a unary function into a unary function that caches the value depending on the parameter
|
// CacheCallback converts a unary function into a unary function that caches the value depending on the parameter
|
||||||
func CacheCallback[F ~func(A) T, KF func(A) K, C ~func(K, func() func() T) func() T, A any, K comparable, T any](kf KF, getOrCreate C) func(F) F {
|
func CacheCallback[
|
||||||
|
EM ~func(F) F, // endomorphism of the function
|
||||||
|
LLT ~func() LT, // generator of the generator
|
||||||
|
LT ~func() T, // generator of a value
|
||||||
|
F ~func(A) T, // function to actually cache
|
||||||
|
KF func(A) K, // extracts the cache key from the input
|
||||||
|
C ~func(K, LLT) LT, // the cache callback function
|
||||||
|
A any, K comparable, T any](kf KF, getOrCreate C) EM {
|
||||||
return func(f F) F {
|
return func(f F) F {
|
||||||
return func(a A) T {
|
return func(a A) T {
|
||||||
// cache entry
|
// cache entry
|
||||||
return getOrCreate(kf(a), func() func() T {
|
return getOrCreate(kf(a), func() LT {
|
||||||
return L.Memoize[func() T](func() T {
|
return L.Memoize[LT](func() T {
|
||||||
return f(a)
|
return f(a)
|
||||||
})
|
})
|
||||||
})()
|
})()
|
||||||
|
4
go.mod
4
go.mod
@@ -4,7 +4,7 @@ go 1.20
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/stretchr/testify v1.8.4
|
github.com/stretchr/testify v1.8.4
|
||||||
github.com/urfave/cli/v2 v2.26.0
|
github.com/urfave/cli/v2 v2.27.1
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
@@ -12,6 +12,6 @@ require (
|
|||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
|
github.com/xrash/smetrics v0.0.0-20231213231151-1d8dd44e695e // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
)
|
)
|
||||||
|
10
go.sum
10
go.sum
@@ -8,12 +8,10 @@ github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf
|
|||||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||||
github.com/urfave/cli/v2 v2.25.7 h1:VAzn5oq403l5pHjc4OhD54+XGO9cdKVL/7lDjF+iKUs=
|
github.com/urfave/cli/v2 v2.27.1 h1:8xSQ6szndafKVRmfyeUMxkNUJQMjL1F2zmsZ+qHpfho=
|
||||||
github.com/urfave/cli/v2 v2.25.7/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ=
|
github.com/urfave/cli/v2 v2.27.1/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ=
|
||||||
github.com/urfave/cli/v2 v2.26.0 h1:3f3AMg3HpThFNT4I++TKOejZO8yU55t3JnnSr4S4QEI=
|
github.com/xrash/smetrics v0.0.0-20231213231151-1d8dd44e695e h1:+SOyEddqYF09QP7vr7CgJ1eti3pY9Fn3LHO1M1r/0sI=
|
||||||
github.com/urfave/cli/v2 v2.26.0/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ=
|
github.com/xrash/smetrics v0.0.0-20231213231151-1d8dd44e695e/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
|
||||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
|
|
||||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
|
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
311
http/builder/builder.go
Normal file
311
http/builder/builder.go
Normal file
@@ -0,0 +1,311 @@
|
|||||||
|
// Copyright (c) 2023 IBM Corp.
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package builder
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
|
||||||
|
E "github.com/IBM/fp-go/either"
|
||||||
|
ENDO "github.com/IBM/fp-go/endomorphism"
|
||||||
|
F "github.com/IBM/fp-go/function"
|
||||||
|
C "github.com/IBM/fp-go/http/content"
|
||||||
|
FM "github.com/IBM/fp-go/http/form"
|
||||||
|
H "github.com/IBM/fp-go/http/headers"
|
||||||
|
J "github.com/IBM/fp-go/json"
|
||||||
|
LZ "github.com/IBM/fp-go/lazy"
|
||||||
|
L "github.com/IBM/fp-go/optics/lens"
|
||||||
|
O "github.com/IBM/fp-go/option"
|
||||||
|
S "github.com/IBM/fp-go/string"
|
||||||
|
T "github.com/IBM/fp-go/tuple"
|
||||||
|
)
|
||||||
|
|
||||||
|
type (
|
||||||
|
Builder struct {
|
||||||
|
method O.Option[string]
|
||||||
|
url string
|
||||||
|
headers http.Header
|
||||||
|
body O.Option[E.Either[error, []byte]]
|
||||||
|
query url.Values
|
||||||
|
}
|
||||||
|
|
||||||
|
// Endomorphism returns an [ENDO.Endomorphism] that transforms a builder
|
||||||
|
Endomorphism = ENDO.Endomorphism[*Builder]
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// Default is the default builder
|
||||||
|
Default = &Builder{method: O.Some(defaultMethod()), headers: make(http.Header), body: noBody}
|
||||||
|
|
||||||
|
defaultMethod = F.Constant(http.MethodGet)
|
||||||
|
|
||||||
|
// Monoid is the [M.Monoid] for the [Endomorphism]
|
||||||
|
Monoid = ENDO.Monoid[*Builder]()
|
||||||
|
|
||||||
|
// Url is a [L.Lens] for the URL
|
||||||
|
Url = L.MakeLensRef((*Builder).GetUrl, (*Builder).SetUrl)
|
||||||
|
// Method is a [L.Lens] for the HTTP method
|
||||||
|
Method = L.MakeLensRef((*Builder).GetMethod, (*Builder).SetMethod)
|
||||||
|
// Body is a [L.Lens] for the request body
|
||||||
|
Body = L.MakeLensRef((*Builder).GetBody, (*Builder).SetBody)
|
||||||
|
// Headers is a [L.Lens] for the complete set of request headers
|
||||||
|
Headers = L.MakeLensRef((*Builder).GetHeaders, (*Builder).SetHeaders)
|
||||||
|
// Query is a [L.Lens] for the set of query parameters
|
||||||
|
Query = L.MakeLensRef((*Builder).GetQuery, (*Builder).SetQuery)
|
||||||
|
|
||||||
|
rawQuery = L.MakeLensRef(getRawQuery, setRawQuery)
|
||||||
|
|
||||||
|
getHeader = F.Bind2of2((*Builder).GetHeader)
|
||||||
|
delHeader = F.Bind2of2((*Builder).DelHeader)
|
||||||
|
setHeader = F.Bind2of3((*Builder).SetHeader)
|
||||||
|
|
||||||
|
noHeader = O.None[string]()
|
||||||
|
noBody = O.None[E.Either[error, []byte]]()
|
||||||
|
noQueryArg = O.None[string]()
|
||||||
|
|
||||||
|
parseUrl = E.Eitherize1(url.Parse)
|
||||||
|
parseQuery = E.Eitherize1(url.ParseQuery)
|
||||||
|
|
||||||
|
// WithQuery creates a [Endomorphism] for a complete set of query parameters
|
||||||
|
WithQuery = Query.Set
|
||||||
|
// WithMethod creates a [Endomorphism] for a certain method
|
||||||
|
WithMethod = Method.Set
|
||||||
|
// WithUrl creates a [Endomorphism] for a certain method
|
||||||
|
WithUrl = Url.Set
|
||||||
|
// WithHeaders creates a [Endomorphism] for a set of headers
|
||||||
|
WithHeaders = Headers.Set
|
||||||
|
// WithBody creates a [Endomorphism] for a request body
|
||||||
|
WithBody = F.Flow2(
|
||||||
|
O.Of[E.Either[error, []byte]],
|
||||||
|
Body.Set,
|
||||||
|
)
|
||||||
|
// WithBytes creates a [Endomorphism] for a request body using bytes
|
||||||
|
WithBytes = F.Flow2(
|
||||||
|
E.Of[error, []byte],
|
||||||
|
WithBody,
|
||||||
|
)
|
||||||
|
// WithContentType adds the [H.ContentType] header
|
||||||
|
WithContentType = WithHeader(H.ContentType)
|
||||||
|
// WithAuthorization adds the [H.Authorization] header
|
||||||
|
WithAuthorization = WithHeader(H.Authorization)
|
||||||
|
|
||||||
|
// WithGet adds the [http.MethodGet] method
|
||||||
|
WithGet = WithMethod(http.MethodGet)
|
||||||
|
// WithPost adds the [http.MethodPost] method
|
||||||
|
WithPost = WithMethod(http.MethodPost)
|
||||||
|
// WithPut adds the [http.MethodPut] method
|
||||||
|
WithPut = WithMethod(http.MethodPut)
|
||||||
|
// WithDelete adds the [http.MethodDelete] method
|
||||||
|
WithDelete = WithMethod(http.MethodDelete)
|
||||||
|
|
||||||
|
// WithBearer creates a [Endomorphism] to add a Bearer [H.Authorization] header
|
||||||
|
WithBearer = F.Flow2(
|
||||||
|
S.Format[string]("Bearer %s"),
|
||||||
|
WithAuthorization,
|
||||||
|
)
|
||||||
|
|
||||||
|
// WithoutBody creates a [Endomorphism] to remove the body
|
||||||
|
WithoutBody = F.Pipe1(
|
||||||
|
noBody,
|
||||||
|
Body.Set,
|
||||||
|
)
|
||||||
|
|
||||||
|
// WithFormData creates a [Endomorphism] to send form data payload
|
||||||
|
WithFormData = F.Flow4(
|
||||||
|
url.Values.Encode,
|
||||||
|
S.ToBytes,
|
||||||
|
WithBytes,
|
||||||
|
ENDO.Chain(WithContentType(C.FormEncoded)),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
func setRawQuery(u *url.URL, raw string) *url.URL {
|
||||||
|
u.RawQuery = raw
|
||||||
|
return u
|
||||||
|
}
|
||||||
|
|
||||||
|
func getRawQuery(u *url.URL) string {
|
||||||
|
return u.RawQuery
|
||||||
|
}
|
||||||
|
|
||||||
|
func (builder *Builder) clone() *Builder {
|
||||||
|
cpy := *builder
|
||||||
|
cpy.headers = cpy.headers.Clone()
|
||||||
|
return &cpy
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetTargetUrl constructs a full URL with query parameters on top of the provided URL string
|
||||||
|
func (builder *Builder) GetTargetUrl() E.Either[error, string] {
|
||||||
|
// construct the final URL
|
||||||
|
return F.Pipe3(
|
||||||
|
builder,
|
||||||
|
Url.Get,
|
||||||
|
parseUrl,
|
||||||
|
E.Chain(F.Flow4(
|
||||||
|
T.Replicate2[*url.URL],
|
||||||
|
T.Map2(
|
||||||
|
F.Flow2(
|
||||||
|
F.Curry2(setRawQuery),
|
||||||
|
E.Of[error, func(string) *url.URL],
|
||||||
|
),
|
||||||
|
F.Flow3(
|
||||||
|
rawQuery.Get,
|
||||||
|
parseQuery,
|
||||||
|
E.Map[error](F.Flow2(
|
||||||
|
F.Curry2(FM.ValuesMonoid.Concat)(builder.GetQuery()),
|
||||||
|
(url.Values).Encode,
|
||||||
|
)),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
T.Tupled2(E.MonadAp[*url.URL, error, string]),
|
||||||
|
E.Map[error]((*url.URL).String),
|
||||||
|
)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (builder *Builder) GetUrl() string {
|
||||||
|
return builder.url
|
||||||
|
}
|
||||||
|
|
||||||
|
func (builder *Builder) GetMethod() string {
|
||||||
|
return F.Pipe1(
|
||||||
|
builder.method,
|
||||||
|
O.GetOrElse(defaultMethod),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (builder *Builder) GetHeaders() http.Header {
|
||||||
|
return builder.headers
|
||||||
|
}
|
||||||
|
|
||||||
|
func (builder *Builder) GetQuery() url.Values {
|
||||||
|
return builder.query
|
||||||
|
}
|
||||||
|
|
||||||
|
func (builder *Builder) SetQuery(query url.Values) *Builder {
|
||||||
|
builder.query = query
|
||||||
|
return builder
|
||||||
|
}
|
||||||
|
|
||||||
|
func (builder *Builder) GetBody() O.Option[E.Either[error, []byte]] {
|
||||||
|
return builder.body
|
||||||
|
}
|
||||||
|
|
||||||
|
func (builder *Builder) SetMethod(method string) *Builder {
|
||||||
|
builder.method = O.Some(method)
|
||||||
|
return builder
|
||||||
|
}
|
||||||
|
|
||||||
|
func (builder *Builder) SetUrl(url string) *Builder {
|
||||||
|
builder.url = url
|
||||||
|
return builder
|
||||||
|
}
|
||||||
|
|
||||||
|
func (builder *Builder) SetHeaders(headers http.Header) *Builder {
|
||||||
|
builder.headers = headers
|
||||||
|
return builder
|
||||||
|
}
|
||||||
|
|
||||||
|
func (builder *Builder) SetBody(body O.Option[E.Either[error, []byte]]) *Builder {
|
||||||
|
builder.body = body
|
||||||
|
return builder
|
||||||
|
}
|
||||||
|
|
||||||
|
func (builder *Builder) SetHeader(name, value string) *Builder {
|
||||||
|
builder.headers.Set(name, value)
|
||||||
|
return builder
|
||||||
|
}
|
||||||
|
|
||||||
|
func (builder *Builder) DelHeader(name string) *Builder {
|
||||||
|
builder.headers.Del(name)
|
||||||
|
return builder
|
||||||
|
}
|
||||||
|
|
||||||
|
func (builder *Builder) GetHeader(name string) O.Option[string] {
|
||||||
|
return F.Pipe2(
|
||||||
|
name,
|
||||||
|
builder.headers.Get,
|
||||||
|
O.FromPredicate(S.IsNonEmpty),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (builder *Builder) GetHeaderValues(name string) []string {
|
||||||
|
return builder.headers.Values(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Header returns a [L.Lens] for a single header
|
||||||
|
func Header(name string) L.Lens[*Builder, O.Option[string]] {
|
||||||
|
get := getHeader(name)
|
||||||
|
set := F.Bind1of2(setHeader(name))
|
||||||
|
del := F.Flow2(
|
||||||
|
LZ.Of[*Builder],
|
||||||
|
LZ.Map(delHeader(name)),
|
||||||
|
)
|
||||||
|
|
||||||
|
return L.MakeLens(get, func(b *Builder, value O.Option[string]) *Builder {
|
||||||
|
cpy := b.clone()
|
||||||
|
return F.Pipe1(
|
||||||
|
value,
|
||||||
|
O.Fold(del(cpy), set(cpy)),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithHeader creates a [Endomorphism] for a certain header
|
||||||
|
func WithHeader(name string) func(value string) Endomorphism {
|
||||||
|
return F.Flow2(
|
||||||
|
O.Of[string],
|
||||||
|
Header(name).Set,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithoutHeader creates a [Endomorphism] to remove a certain header
|
||||||
|
func WithoutHeader(name string) Endomorphism {
|
||||||
|
return Header(name).Set(noHeader)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithJson creates a [Endomorphism] to send JSON payload
|
||||||
|
func WithJson[T any](data T) Endomorphism {
|
||||||
|
return Monoid.Concat(
|
||||||
|
F.Pipe2(
|
||||||
|
data,
|
||||||
|
J.Marshal[T],
|
||||||
|
WithBody,
|
||||||
|
),
|
||||||
|
WithContentType(C.Json),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// QueryArg is a [L.Lens] for the first value of a query argument
|
||||||
|
func QueryArg(name string) L.Lens[*Builder, O.Option[string]] {
|
||||||
|
return F.Pipe1(
|
||||||
|
Query,
|
||||||
|
L.Compose[*Builder](FM.AtValue(name)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithQueryArg creates a [Endomorphism] for a certain query argument
|
||||||
|
func WithQueryArg(name string) func(value string) Endomorphism {
|
||||||
|
return F.Flow2(
|
||||||
|
O.Of[string],
|
||||||
|
QueryArg(name).Set,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithoutQueryArg creates a [Endomorphism] that removes a query argument
|
||||||
|
func WithoutQueryArg(name string) Endomorphism {
|
||||||
|
return QueryArg(name).Set(noQueryArg)
|
||||||
|
}
|
68
http/builder/builder_test.go
Normal file
68
http/builder/builder_test.go
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
// Copyright (c) 2023 IBM Corp.
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package builder
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
F "github.com/IBM/fp-go/function"
|
||||||
|
C "github.com/IBM/fp-go/http/content"
|
||||||
|
FD "github.com/IBM/fp-go/http/form"
|
||||||
|
H "github.com/IBM/fp-go/http/headers"
|
||||||
|
O "github.com/IBM/fp-go/option"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestBuilder(t *testing.T) {
|
||||||
|
|
||||||
|
name := H.ContentType
|
||||||
|
withContentType := WithHeader(name)
|
||||||
|
withoutContentType := WithoutHeader(name)
|
||||||
|
|
||||||
|
b1 := F.Pipe1(
|
||||||
|
Default,
|
||||||
|
withContentType(C.Json),
|
||||||
|
)
|
||||||
|
|
||||||
|
b2 := F.Pipe1(
|
||||||
|
b1,
|
||||||
|
withContentType(C.TextPlain),
|
||||||
|
)
|
||||||
|
|
||||||
|
b3 := F.Pipe1(
|
||||||
|
b2,
|
||||||
|
withoutContentType,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert.Equal(t, O.None[string](), Default.GetHeader(name))
|
||||||
|
assert.Equal(t, O.Of(C.Json), b1.GetHeader(name))
|
||||||
|
assert.Equal(t, O.Of(C.TextPlain), b2.GetHeader(name))
|
||||||
|
assert.Equal(t, O.None[string](), b3.GetHeader(name))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWithFormData(t *testing.T) {
|
||||||
|
data := F.Pipe1(
|
||||||
|
FD.Default,
|
||||||
|
FD.WithValue("a")("b"),
|
||||||
|
)
|
||||||
|
|
||||||
|
res := F.Pipe1(
|
||||||
|
Default,
|
||||||
|
WithFormData(data),
|
||||||
|
)
|
||||||
|
|
||||||
|
assert.Equal(t, C.FormEncoded, Headers.Get(res).Get(H.ContentType))
|
||||||
|
}
|
22
http/content/content.go
Normal file
22
http/content/content.go
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
// Copyright (c) 2023 IBM Corp.
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package content
|
||||||
|
|
||||||
|
const (
|
||||||
|
TextPlain = "text/plain"
|
||||||
|
Json = "application/json"
|
||||||
|
FormEncoded = "application/x-www-form-urlencoded"
|
||||||
|
)
|
@@ -25,6 +25,7 @@ import (
|
|||||||
LA "github.com/IBM/fp-go/optics/lens/array"
|
LA "github.com/IBM/fp-go/optics/lens/array"
|
||||||
LRG "github.com/IBM/fp-go/optics/lens/record/generic"
|
LRG "github.com/IBM/fp-go/optics/lens/record/generic"
|
||||||
O "github.com/IBM/fp-go/option"
|
O "github.com/IBM/fp-go/option"
|
||||||
|
RG "github.com/IBM/fp-go/record/generic"
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
@@ -41,6 +42,9 @@ var (
|
|||||||
// FormMonoid is the [M.Monoid] for the [Endomorphism]
|
// FormMonoid is the [M.Monoid] for the [Endomorphism]
|
||||||
Monoid = ENDO.Monoid[url.Values]()
|
Monoid = ENDO.Monoid[url.Values]()
|
||||||
|
|
||||||
|
// ValuesMonoid is a [M.Monoid] to concatenate [url.Values] maps
|
||||||
|
ValuesMonoid = RG.UnionMonoid[url.Values](A.Semigroup[string]())
|
||||||
|
|
||||||
// AtValues is a [L.Lens] that focusses on the values of a form field
|
// AtValues is a [L.Lens] that focusses on the values of a form field
|
||||||
AtValues = LRG.AtRecord[url.Values, []string]
|
AtValues = LRG.AtRecord[url.Values, []string]
|
||||||
|
|
||||||
@@ -58,10 +62,9 @@ var (
|
|||||||
|
|
||||||
// WithValue creates a [FormBuilder] for a certain field
|
// WithValue creates a [FormBuilder] for a certain field
|
||||||
func WithValue(name string) func(value string) Endomorphism {
|
func WithValue(name string) func(value string) Endomorphism {
|
||||||
return F.Flow3(
|
return F.Flow2(
|
||||||
O.Of[string],
|
O.Of[string],
|
||||||
AtValue(name).Set,
|
AtValue(name).Set,
|
||||||
ENDO.Of[func(url.Values) url.Values],
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
58
http/headers/headers.go
Normal file
58
http/headers/headers.go
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
// Copyright (c) 2023 IBM Corp.
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package headers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"net/textproto"
|
||||||
|
|
||||||
|
A "github.com/IBM/fp-go/array"
|
||||||
|
F "github.com/IBM/fp-go/function"
|
||||||
|
L "github.com/IBM/fp-go/optics/lens"
|
||||||
|
LA "github.com/IBM/fp-go/optics/lens/array"
|
||||||
|
LRG "github.com/IBM/fp-go/optics/lens/record/generic"
|
||||||
|
RG "github.com/IBM/fp-go/record/generic"
|
||||||
|
)
|
||||||
|
|
||||||
|
// HTTP headers
|
||||||
|
const (
|
||||||
|
Accept = "Accept"
|
||||||
|
Authorization = "Authorization"
|
||||||
|
ContentType = "Content-Type"
|
||||||
|
ContentLength = "Content-Length"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// Monoid is a [M.Monoid] to concatenate [http.Header] maps
|
||||||
|
Monoid = RG.UnionMonoid[http.Header](A.Semigroup[string]())
|
||||||
|
|
||||||
|
// AtValues is a [L.Lens] that focusses on the values of a header
|
||||||
|
AtValues = F.Flow2(
|
||||||
|
textproto.CanonicalMIMEHeaderKey,
|
||||||
|
LRG.AtRecord[http.Header, []string],
|
||||||
|
)
|
||||||
|
|
||||||
|
composeHead = F.Pipe1(
|
||||||
|
LA.AtHead[string](),
|
||||||
|
L.ComposeOptions[http.Header, string](A.Empty[string]()),
|
||||||
|
)
|
||||||
|
|
||||||
|
// AtValue is a [L.Lens] that focusses on first value of a header
|
||||||
|
AtValue = F.Flow2(
|
||||||
|
AtValues,
|
||||||
|
composeHead,
|
||||||
|
)
|
||||||
|
)
|
58
http/headers/headers_test.go
Normal file
58
http/headers/headers_test.go
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
// Copyright (c) 2023 IBM Corp.
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package headers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
A "github.com/IBM/fp-go/array"
|
||||||
|
"github.com/IBM/fp-go/eq"
|
||||||
|
LT "github.com/IBM/fp-go/optics/lens/testing"
|
||||||
|
O "github.com/IBM/fp-go/option"
|
||||||
|
RG "github.com/IBM/fp-go/record/generic"
|
||||||
|
S "github.com/IBM/fp-go/string"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
sEq = eq.FromEquals(S.Eq)
|
||||||
|
valuesEq = RG.Eq[http.Header](A.Eq(sEq))
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestLaws(t *testing.T) {
|
||||||
|
name := "Content-Type"
|
||||||
|
fieldLaws := LT.AssertLaws[http.Header, O.Option[string]](t, O.Eq(sEq), valuesEq)(AtValue(name))
|
||||||
|
|
||||||
|
n := O.None[string]()
|
||||||
|
s1 := O.Some("s1")
|
||||||
|
|
||||||
|
def := make(http.Header)
|
||||||
|
|
||||||
|
v1 := make(http.Header)
|
||||||
|
v1.Set(name, "v1")
|
||||||
|
|
||||||
|
v2 := make(http.Header)
|
||||||
|
v2.Set("Other-Header", "v2")
|
||||||
|
|
||||||
|
assert.True(t, fieldLaws(def, n))
|
||||||
|
assert.True(t, fieldLaws(v1, n))
|
||||||
|
assert.True(t, fieldLaws(v2, n))
|
||||||
|
|
||||||
|
assert.True(t, fieldLaws(def, s1))
|
||||||
|
assert.True(t, fieldLaws(v1, s1))
|
||||||
|
assert.True(t, fieldLaws(v2, s1))
|
||||||
|
}
|
@@ -20,6 +20,7 @@ import (
|
|||||||
|
|
||||||
E "github.com/IBM/fp-go/either"
|
E "github.com/IBM/fp-go/either"
|
||||||
F "github.com/IBM/fp-go/function"
|
F "github.com/IBM/fp-go/function"
|
||||||
|
C "github.com/IBM/fp-go/http/content"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -38,7 +39,7 @@ func Error[A any](t *testing.T) func(E.Either[error, A]) bool {
|
|||||||
func TestValidateJsonContentTypeString(t *testing.T) {
|
func TestValidateJsonContentTypeString(t *testing.T) {
|
||||||
|
|
||||||
res := F.Pipe1(
|
res := F.Pipe1(
|
||||||
validateJsonContentTypeString("application/json"),
|
validateJsonContentTypeString(C.Json),
|
||||||
NoError[ParsedMediaType](t),
|
NoError[ParsedMediaType](t),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
28
internal/array/prepend.go
Normal file
28
internal/array/prepend.go
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
// Copyright (c) 2023 IBM Corp.
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package array
|
||||||
|
|
||||||
|
// Prepend prepends a single value to an array
|
||||||
|
func Prepend[ENDO ~func(AS) AS, AS ~[]A, A any](head A) ENDO {
|
||||||
|
return func(as AS) AS {
|
||||||
|
l := len(as)
|
||||||
|
cpy := make(AS, l+1)
|
||||||
|
copy(cpy[1:], as)
|
||||||
|
cpy[0] = head
|
||||||
|
return cpy
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@@ -133,6 +133,29 @@ func Delay[GA ~func() A, A any](delay time.Duration) func(GA) GA {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func after(timestamp time.Time) func() {
|
||||||
|
return func() {
|
||||||
|
// check if we need to wait
|
||||||
|
current := time.Now()
|
||||||
|
if current.Before(timestamp) {
|
||||||
|
time.Sleep(timestamp.Sub(current))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// After creates an operation that passes after the given timestamp
|
||||||
|
func After[GA ~func() A, A any](timestamp time.Time) func(GA) GA {
|
||||||
|
aft := after(timestamp)
|
||||||
|
return func(ga GA) GA {
|
||||||
|
return MakeIO[GA](func() A {
|
||||||
|
// wait as long as necessary
|
||||||
|
aft()
|
||||||
|
// execute after wait
|
||||||
|
return ga()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Now returns the current timestamp
|
// Now returns the current timestamp
|
||||||
func Now[GA ~func() time.Time]() GA {
|
func Now[GA ~func() time.Time]() GA {
|
||||||
return MakeIO[GA](time.Now)
|
return MakeIO[GA](time.Now)
|
||||||
|
10
io/io.go
10
io/io.go
@@ -146,3 +146,13 @@ func MonadFlap[B, A any](fab IO[func(A) B], a A) IO[B] {
|
|||||||
func Flap[FAB ~func(A) B, GFAB ~func() FAB, GB ~func() B, A, B any](a A) func(IO[func(A) B]) IO[B] {
|
func Flap[FAB ~func(A) B, GFAB ~func() FAB, GB ~func() B, A, B any](a A) func(IO[func(A) B]) IO[B] {
|
||||||
return G.Flap[func(A) B, IO[func(A) B], IO[B], A, B](a)
|
return G.Flap[func(A) B, IO[func(A) B], IO[B], A, B](a)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Delay creates an operation that passes in the value after some delay
|
||||||
|
func Delay[A any](delay time.Duration) func(IO[A]) IO[A] {
|
||||||
|
return G.Delay[IO[A]](delay)
|
||||||
|
}
|
||||||
|
|
||||||
|
// After creates an operation that passes after the given timestamp
|
||||||
|
func After[A any](timestamp time.Time) func(IO[A]) IO[A] {
|
||||||
|
return G.After[IO[A]](timestamp)
|
||||||
|
}
|
||||||
|
@@ -207,11 +207,16 @@ func MapLeft[GA1 ~func() ET.Either[E1, A], GA2 ~func() ET.Either[E2, A], E1, E2,
|
|||||||
return F.Bind2nd(MonadMapLeft[GA1, GA2, E1, E2, A], f)
|
return F.Bind2nd(MonadMapLeft[GA1, GA2, E1, E2, A], f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delay creates an operation that passes in the value after some delay
|
// Delay creates an operation that passes in the value after some [time.Duration]
|
||||||
func Delay[GA ~func() ET.Either[E, A], E, A any](delay time.Duration) func(GA) GA {
|
func Delay[GA ~func() ET.Either[E, A], E, A any](delay time.Duration) func(GA) GA {
|
||||||
return IO.Delay[GA](delay)
|
return IO.Delay[GA](delay)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// After creates an operation that passes after the given [time.Time]
|
||||||
|
func After[GA ~func() ET.Either[E, A], E, A any](timestamp time.Time) func(GA) GA {
|
||||||
|
return IO.After[GA](timestamp)
|
||||||
|
}
|
||||||
|
|
||||||
func MonadBiMap[GA ~func() ET.Either[E1, A], GB ~func() ET.Either[E2, B], E1, E2, A, B any](fa GA, f func(E1) E2, g func(A) B) GB {
|
func MonadBiMap[GA ~func() ET.Either[E1, A], GB ~func() ET.Either[E2, B], E1, E2, A, B any](fa GA, f func(E1) E2, g func(A) B) GB {
|
||||||
return eithert.MonadBiMap(IO.MonadMap[GA, GB, ET.Either[E1, A], ET.Either[E2, B]], fa, f, g)
|
return eithert.MonadBiMap(IO.MonadMap[GA, GB, ET.Either[E1, A], ET.Either[E2, B]], fa, f, g)
|
||||||
}
|
}
|
||||||
|
@@ -18,250 +18,50 @@ package builder
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
ENDO "github.com/IBM/fp-go/endomorphism"
|
E "github.com/IBM/fp-go/either"
|
||||||
F "github.com/IBM/fp-go/function"
|
F "github.com/IBM/fp-go/function"
|
||||||
|
R "github.com/IBM/fp-go/http/builder"
|
||||||
|
H "github.com/IBM/fp-go/http/headers"
|
||||||
IOE "github.com/IBM/fp-go/ioeither"
|
IOE "github.com/IBM/fp-go/ioeither"
|
||||||
IOEH "github.com/IBM/fp-go/ioeither/http"
|
IOEH "github.com/IBM/fp-go/ioeither/http"
|
||||||
J "github.com/IBM/fp-go/json"
|
|
||||||
LZ "github.com/IBM/fp-go/lazy"
|
LZ "github.com/IBM/fp-go/lazy"
|
||||||
L "github.com/IBM/fp-go/optics/lens"
|
|
||||||
O "github.com/IBM/fp-go/option"
|
O "github.com/IBM/fp-go/option"
|
||||||
S "github.com/IBM/fp-go/string"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
func Requester(builder *R.Builder) IOEH.Requester {
|
||||||
Builder struct {
|
|
||||||
method O.Option[string]
|
|
||||||
url string
|
|
||||||
headers http.Header
|
|
||||||
body O.Option[IOE.IOEither[error, []byte]]
|
|
||||||
}
|
|
||||||
|
|
||||||
// Endomorphism returns an [ENDO.Endomorphism] that transforms a builder
|
withBody := F.Curry3(func(data []byte, url string, method string) IOE.IOEither[error, *http.Request] {
|
||||||
Endomorphism = ENDO.Endomorphism[*Builder]
|
return IOE.TryCatchError(func() (*http.Request, error) {
|
||||||
)
|
req, err := http.NewRequest(method, url, bytes.NewReader(data))
|
||||||
|
if err == nil {
|
||||||
|
req.Header.Set(H.ContentLength, strconv.Itoa(len(data)))
|
||||||
|
H.Monoid.Concat(req.Header, builder.GetHeaders())
|
||||||
|
}
|
||||||
|
return req, err
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
var (
|
withoutBody := F.Curry2(func(url string, method string) IOE.IOEither[error, *http.Request] {
|
||||||
// Default is the default builder
|
return IOE.TryCatchError(func() (*http.Request, error) {
|
||||||
Default = &Builder{method: O.Some(defaultMethod()), headers: make(http.Header), body: noBody}
|
req, err := http.NewRequest(method, url, nil)
|
||||||
|
if err == nil {
|
||||||
|
H.Monoid.Concat(req.Header, builder.GetHeaders())
|
||||||
|
}
|
||||||
|
return req, err
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
defaultMethod = F.Constant(http.MethodGet)
|
return F.Pipe5(
|
||||||
|
|
||||||
// Monoid is the [M.Monoid] for the [Endomorphism]
|
|
||||||
Monoid = ENDO.Monoid[*Builder]()
|
|
||||||
|
|
||||||
// Url is a [L.Lens] for the URL
|
|
||||||
Url = L.MakeLensRef((*Builder).GetUrl, (*Builder).SetUrl)
|
|
||||||
// Method is a [L.Lens] for the HTTP method
|
|
||||||
Method = L.MakeLensRef((*Builder).GetMethod, (*Builder).SetMethod)
|
|
||||||
// Body is a [L.Lens] for the request body
|
|
||||||
Body = L.MakeLensRef((*Builder).GetBody, (*Builder).SetBody)
|
|
||||||
// Headers is a [L.Lens] for the complete set of request headers
|
|
||||||
Headers = L.MakeLensRef((*Builder).GetHeaders, (*Builder).SetHeaders)
|
|
||||||
|
|
||||||
getHeader = F.Bind2of2((*Builder).GetHeader)
|
|
||||||
delHeader = F.Bind2of2((*Builder).DelHeader)
|
|
||||||
setHeader = F.Bind2of3((*Builder).SetHeader)
|
|
||||||
|
|
||||||
noHeader = O.None[string]()
|
|
||||||
noBody = O.None[IOE.IOEither[error, []byte]]()
|
|
||||||
|
|
||||||
// WithMethod creates a [BuilderBuilder] for a certain method
|
|
||||||
WithMethod = F.Flow2(
|
|
||||||
Method.Set,
|
|
||||||
ENDO.Of[func(*Builder) *Builder],
|
|
||||||
)
|
|
||||||
// WithUrl creates a [BuilderBuilder] for a certain method
|
|
||||||
WithUrl = F.Flow2(
|
|
||||||
Url.Set,
|
|
||||||
ENDO.Of[func(*Builder) *Builder],
|
|
||||||
)
|
|
||||||
// WithHeaders creates a [BuilderBuilder] for a set of headers
|
|
||||||
WithHeaders = F.Flow2(
|
|
||||||
Headers.Set,
|
|
||||||
ENDO.Of[func(*Builder) *Builder],
|
|
||||||
)
|
|
||||||
// WithBody creates a [BuilderBuilder] for a request body
|
|
||||||
WithBody = F.Flow3(
|
|
||||||
O.Of[IOE.IOEither[error, []byte]],
|
|
||||||
Body.Set,
|
|
||||||
ENDO.Of[func(*Builder) *Builder],
|
|
||||||
)
|
|
||||||
// WithContentType adds the content type header
|
|
||||||
WithContentType = WithHeader("Content-Type")
|
|
||||||
|
|
||||||
// WithGet adds the [http.MethodGet] method
|
|
||||||
WithGet = WithMethod(http.MethodGet)
|
|
||||||
// WithPost adds the [http.MethodPost] method
|
|
||||||
WithPost = WithMethod(http.MethodPost)
|
|
||||||
// WithPut adds the [http.MethodPut] method
|
|
||||||
WithPut = WithMethod(http.MethodPut)
|
|
||||||
// WithDelete adds the [http.MethodDelete] method
|
|
||||||
WithDelete = WithMethod(http.MethodDelete)
|
|
||||||
|
|
||||||
// Requester creates a requester from a builder
|
|
||||||
Requester = (*Builder).Requester
|
|
||||||
|
|
||||||
// WithoutBody creates a [BuilderBuilder] to remove the body
|
|
||||||
WithoutBody = F.Pipe2(
|
|
||||||
noBody,
|
|
||||||
Body.Set,
|
|
||||||
ENDO.Of[func(*Builder) *Builder],
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
func (builder *Builder) clone() *Builder {
|
|
||||||
cpy := *builder
|
|
||||||
cpy.headers = cpy.headers.Clone()
|
|
||||||
return &cpy
|
|
||||||
}
|
|
||||||
|
|
||||||
func (builder *Builder) GetUrl() string {
|
|
||||||
return builder.url
|
|
||||||
}
|
|
||||||
|
|
||||||
func (builder *Builder) GetMethod() string {
|
|
||||||
return F.Pipe1(
|
|
||||||
builder.method,
|
|
||||||
O.GetOrElse(defaultMethod),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (builder *Builder) GetHeaders() http.Header {
|
|
||||||
return builder.headers
|
|
||||||
}
|
|
||||||
|
|
||||||
func (builder *Builder) GetBody() O.Option[IOE.IOEither[error, []byte]] {
|
|
||||||
return builder.body
|
|
||||||
}
|
|
||||||
|
|
||||||
func (builder *Builder) SetMethod(method string) *Builder {
|
|
||||||
builder.method = O.Some(method)
|
|
||||||
return builder
|
|
||||||
}
|
|
||||||
|
|
||||||
func (builder *Builder) SetUrl(url string) *Builder {
|
|
||||||
builder.url = url
|
|
||||||
return builder
|
|
||||||
}
|
|
||||||
|
|
||||||
func (builder *Builder) SetHeaders(headers http.Header) *Builder {
|
|
||||||
builder.headers = headers
|
|
||||||
return builder
|
|
||||||
}
|
|
||||||
|
|
||||||
func (builder *Builder) SetBody(body O.Option[IOE.IOEither[error, []byte]]) *Builder {
|
|
||||||
builder.body = body
|
|
||||||
return builder
|
|
||||||
}
|
|
||||||
|
|
||||||
func (builder *Builder) SetHeader(name, value string) *Builder {
|
|
||||||
builder.headers.Set(name, value)
|
|
||||||
return builder
|
|
||||||
}
|
|
||||||
|
|
||||||
func (builder *Builder) DelHeader(name string) *Builder {
|
|
||||||
builder.headers.Del(name)
|
|
||||||
return builder
|
|
||||||
}
|
|
||||||
|
|
||||||
func (builder *Builder) GetHeader(name string) O.Option[string] {
|
|
||||||
return F.Pipe2(
|
|
||||||
name,
|
|
||||||
builder.headers.Get,
|
|
||||||
O.FromPredicate(S.IsNonEmpty),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (builder *Builder) GetHeaderValues(name string) []string {
|
|
||||||
return builder.headers.Values(name)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (builder *Builder) AddHeaderHeader(name, value string) *Builder {
|
|
||||||
builder.headers.Add(name, value)
|
|
||||||
return builder
|
|
||||||
}
|
|
||||||
|
|
||||||
func (builder *Builder) Requester() IOEH.Requester {
|
|
||||||
return F.Pipe3(
|
|
||||||
builder.GetBody(),
|
builder.GetBody(),
|
||||||
O.Map(IOE.Map[error](bytes.NewReader)),
|
O.Fold(LZ.Of(E.Of[error](withoutBody)), E.Map[error](withBody)),
|
||||||
O.GetOrElse(F.Constant(IOE.Of[error, *bytes.Reader](nil))),
|
E.Ap[func(string) IOE.IOEither[error, *http.Request]](builder.GetTargetUrl()),
|
||||||
IOE.Chain(func(rdr *bytes.Reader) IOE.IOEither[error, *http.Request] {
|
E.Flap[error, IOE.IOEither[error, *http.Request]](builder.GetMethod()),
|
||||||
return IOE.TryCatchError(func() (*http.Request, error) {
|
E.GetOrElse(IOE.Left[*http.Request, error]),
|
||||||
req, err := http.NewRequest(builder.GetMethod(), builder.GetUrl(), rdr)
|
IOE.Map[error](func(req *http.Request) *http.Request {
|
||||||
if err == nil {
|
req.Header = H.Monoid.Concat(req.Header, builder.GetHeaders())
|
||||||
for name, value := range builder.GetHeaders() {
|
return req
|
||||||
req.Header[name] = value
|
|
||||||
}
|
|
||||||
if rdr != nil {
|
|
||||||
req.Header.Set("Content-Length", strconv.FormatInt(rdr.Size(), 10))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return req, err
|
|
||||||
})
|
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Header returns a [L.Lens] for a single header
|
|
||||||
func Header(name string) L.Lens[*Builder, O.Option[string]] {
|
|
||||||
get := getHeader(name)
|
|
||||||
set := F.Bind1of2(setHeader(name))
|
|
||||||
del := F.Flow2(
|
|
||||||
LZ.Of[*Builder],
|
|
||||||
LZ.Map(delHeader(name)),
|
|
||||||
)
|
|
||||||
|
|
||||||
return L.MakeLens[*Builder, O.Option[string]](get, func(b *Builder, value O.Option[string]) *Builder {
|
|
||||||
cpy := b.clone()
|
|
||||||
return F.Pipe1(
|
|
||||||
value,
|
|
||||||
O.Fold(del(cpy), set(cpy)),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithHeader creates a [BuilderBuilder] for a certain header
|
|
||||||
func WithHeader(name string) func(value string) Endomorphism {
|
|
||||||
return F.Flow3(
|
|
||||||
O.Of[string],
|
|
||||||
Header(name).Set,
|
|
||||||
ENDO.Of[func(*Builder) *Builder],
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithoutHeader creates a [BuilderBuilder] to remove a certain header
|
|
||||||
func WithoutHeader(name string) Endomorphism {
|
|
||||||
return Header(name).Set(noHeader)
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithFormData creates a [BuilderBuilder] to send form data payload
|
|
||||||
func WithFormData(value url.Values) Endomorphism {
|
|
||||||
return F.Flow2(
|
|
||||||
F.Pipe4(
|
|
||||||
value,
|
|
||||||
url.Values.Encode,
|
|
||||||
S.ToBytes,
|
|
||||||
IOE.Of[error, []byte],
|
|
||||||
WithBody,
|
|
||||||
),
|
|
||||||
WithContentType("application/x-www-form-urlencoded"),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithJson creates a [BuilderBuilder] to send JSON payload
|
|
||||||
func WithJson[T any](data T) Endomorphism {
|
|
||||||
return F.Flow2(
|
|
||||||
F.Pipe3(
|
|
||||||
data,
|
|
||||||
J.Marshal[T],
|
|
||||||
IOE.FromEither[error, []byte],
|
|
||||||
WithBody,
|
|
||||||
),
|
|
||||||
WithContentType("application/json"),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
@@ -16,36 +16,43 @@
|
|||||||
package builder
|
package builder
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
E "github.com/IBM/fp-go/either"
|
||||||
F "github.com/IBM/fp-go/function"
|
F "github.com/IBM/fp-go/function"
|
||||||
O "github.com/IBM/fp-go/option"
|
R "github.com/IBM/fp-go/http/builder"
|
||||||
|
IO "github.com/IBM/fp-go/io"
|
||||||
|
IOE "github.com/IBM/fp-go/ioeither"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestBuiler(t *testing.T) {
|
func TestBuilderWithQuery(t *testing.T) {
|
||||||
|
// add some query
|
||||||
|
withLimit := R.WithQueryArg("limit")("10")
|
||||||
|
withUrl := R.WithUrl("http://www.example.org?a=b")
|
||||||
|
|
||||||
name := "Content-type"
|
b := F.Pipe2(
|
||||||
withContentType := WithHeader(name)
|
R.Default,
|
||||||
withoutContentType := WithoutHeader(name)
|
withLimit,
|
||||||
|
withUrl,
|
||||||
b1 := F.Pipe1(
|
|
||||||
Default,
|
|
||||||
withContentType("application/json"),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
b2 := F.Pipe1(
|
req := F.Pipe3(
|
||||||
b1,
|
b,
|
||||||
withContentType("text/plain"),
|
Requester,
|
||||||
|
IOE.Map[error](func(r *http.Request) *url.URL {
|
||||||
|
return r.URL
|
||||||
|
}),
|
||||||
|
IOE.ChainFirstIOK[error](func(u *url.URL) IO.IO[any] {
|
||||||
|
return IO.FromImpure(func() {
|
||||||
|
q := u.Query()
|
||||||
|
assert.Equal(t, "10", q.Get("limit"))
|
||||||
|
assert.Equal(t, "b", q.Get("a"))
|
||||||
|
})
|
||||||
|
}),
|
||||||
)
|
)
|
||||||
|
|
||||||
b3 := F.Pipe1(
|
assert.True(t, E.IsRight(req()))
|
||||||
b2,
|
|
||||||
withoutContentType,
|
|
||||||
)
|
|
||||||
|
|
||||||
assert.Equal(t, O.None[string](), Default.GetHeader(name))
|
|
||||||
assert.Equal(t, O.Of("application/json"), b1.GetHeader(name))
|
|
||||||
assert.Equal(t, O.Of("text/plain"), b2.GetHeader(name))
|
|
||||||
assert.Equal(t, O.None[string](), b3.GetHeader(name))
|
|
||||||
}
|
}
|
||||||
|
@@ -13,20 +13,20 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
package http
|
package di
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
DI "github.com/IBM/fp-go/di"
|
DI "github.com/IBM/fp-go/di"
|
||||||
IOE "github.com/IBM/fp-go/ioeither"
|
IOE "github.com/IBM/fp-go/ioeither"
|
||||||
L "github.com/IBM/fp-go/lazy"
|
IOEH "github.com/IBM/fp-go/ioeither/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// InjHttpClient is the injection token for the default http client
|
// InjHttpClient is the [DI.InjectionToken] for the [http.DefaultClient]
|
||||||
InjHttpClient = DI.MakeTokenWithDefault0("HTTP_CLIENT", L.Of(IOE.Of[error](http.DefaultClient)))
|
InjHttpClient = DI.MakeTokenWithDefault0("HTTP_CLIENT", IOE.Of[error](http.DefaultClient))
|
||||||
|
|
||||||
// InjClient is the injection token for the default [Client]
|
// InjClient is the [DI.InjectionToken] for the default [IOEH.Client]
|
||||||
InjClient = DI.MakeTokenWithDefault1("CLIENT", InjHttpClient.IOEither(), IOE.Map[error](MakeClient))
|
InjClient = DI.MakeTokenWithDefault1("CLIENT", InjHttpClient.IOEither(), IOE.Map[error](IOEH.MakeClient))
|
||||||
)
|
)
|
@@ -16,6 +16,8 @@
|
|||||||
package ioeither
|
package ioeither
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
ET "github.com/IBM/fp-go/either"
|
ET "github.com/IBM/fp-go/either"
|
||||||
I "github.com/IBM/fp-go/io"
|
I "github.com/IBM/fp-go/io"
|
||||||
G "github.com/IBM/fp-go/ioeither/generic"
|
G "github.com/IBM/fp-go/ioeither/generic"
|
||||||
@@ -276,3 +278,13 @@ func Flap[E, B, A any](a A) func(IOEither[E, func(A) B]) IOEither[E, B] {
|
|||||||
func ToIOOption[E, A any](ioe IOEither[E, A]) IOO.IOOption[A] {
|
func ToIOOption[E, A any](ioe IOEither[E, A]) IOO.IOOption[A] {
|
||||||
return G.ToIOOption[IOO.IOOption[A]](ioe)
|
return G.ToIOOption[IOO.IOOption[A]](ioe)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Delay creates an operation that passes in the value after some delay
|
||||||
|
func Delay[E, A any](delay time.Duration) func(IOEither[E, A]) IOEither[E, A] {
|
||||||
|
return G.Delay[IOEither[E, A]](delay)
|
||||||
|
}
|
||||||
|
|
||||||
|
// After creates an operation that passes after the given [time.Time]
|
||||||
|
func After[E, A any](timestamp time.Time) func(IOEither[E, A]) IOEither[E, A] {
|
||||||
|
return G.After[IOEither[E, A]](timestamp)
|
||||||
|
}
|
||||||
|
@@ -219,6 +219,11 @@ func Delay[GA ~func() O.Option[A], A any](delay time.Duration) func(GA) GA {
|
|||||||
return IO.Delay[GA](delay)
|
return IO.Delay[GA](delay)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// After creates an operation that passes after the given [time.Time]
|
||||||
|
func After[GA ~func() O.Option[A], A any](timestamp time.Time) func(GA) GA {
|
||||||
|
return IO.After[GA](timestamp)
|
||||||
|
}
|
||||||
|
|
||||||
// Fold convers an IOOption into an IO
|
// Fold convers an IOOption into an IO
|
||||||
func Fold[GA ~func() O.Option[A], GB ~func() B, A, B any](onNone func() GB, onSome func(A) GB) func(GA) GB {
|
func Fold[GA ~func() O.Option[A], GB ~func() B, A, B any](onNone func() GB, onSome func(A) GB) func(GA) GB {
|
||||||
return optiont.MatchE(IO.MonadChain[GA, GB, O.Option[A], B], onNone, onSome)
|
return optiont.MatchE(IO.MonadChain[GA, GB, O.Option[A], B], onNone, onSome)
|
||||||
|
@@ -16,6 +16,8 @@
|
|||||||
package iooption
|
package iooption
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
ET "github.com/IBM/fp-go/either"
|
ET "github.com/IBM/fp-go/either"
|
||||||
I "github.com/IBM/fp-go/io"
|
I "github.com/IBM/fp-go/io"
|
||||||
IO "github.com/IBM/fp-go/io"
|
IO "github.com/IBM/fp-go/io"
|
||||||
@@ -164,3 +166,13 @@ func MonadChainFirstIOK[A, B any](first IOOption[A], f func(A) IO.IO[B]) IOOptio
|
|||||||
func ChainFirstIOK[A, B any](f func(A) IO.IO[B]) func(IOOption[A]) IOOption[A] {
|
func ChainFirstIOK[A, B any](f func(A) IO.IO[B]) func(IOOption[A]) IOOption[A] {
|
||||||
return G.ChainFirstIOK[IOOption[A], IO.IO[B]](f)
|
return G.ChainFirstIOK[IOOption[A], IO.IO[B]](f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Delay creates an operation that passes in the value after some delay
|
||||||
|
func Delay[A any](delay time.Duration) func(IOOption[A]) IOOption[A] {
|
||||||
|
return G.Delay[IOOption[A]](delay)
|
||||||
|
}
|
||||||
|
|
||||||
|
// After creates an operation that passes after the given [time.Time]
|
||||||
|
func After[A any](timestamp time.Time) func(IOOption[A]) IOOption[A] {
|
||||||
|
return G.After[IOOption[A]](timestamp)
|
||||||
|
}
|
||||||
|
34
iterator/stateless/generic/io.go
Normal file
34
iterator/stateless/generic/io.go
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
// Copyright (c) 2023 IBM Corp.
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package generic
|
||||||
|
|
||||||
|
import (
|
||||||
|
F "github.com/IBM/fp-go/function"
|
||||||
|
L "github.com/IBM/fp-go/io/generic"
|
||||||
|
O "github.com/IBM/fp-go/option"
|
||||||
|
T "github.com/IBM/fp-go/tuple"
|
||||||
|
)
|
||||||
|
|
||||||
|
// FromLazy returns an iterator on top of a lazy function
|
||||||
|
func FromLazy[GU ~func() O.Option[T.Tuple2[GU, U]], LZ ~func() U, U any](l LZ) GU {
|
||||||
|
return F.Pipe1(
|
||||||
|
l,
|
||||||
|
L.Map[LZ, GU](F.Flow2(
|
||||||
|
F.Bind1st(T.MakeTuple2[GU, U], Empty[GU]()),
|
||||||
|
O.Of[T.Tuple2[GU, U]],
|
||||||
|
)),
|
||||||
|
)
|
||||||
|
}
|
32
iterator/stateless/io.go
Normal file
32
iterator/stateless/io.go
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
// Copyright (c) 2023 IBM Corp.
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package stateless
|
||||||
|
|
||||||
|
import (
|
||||||
|
IO "github.com/IBM/fp-go/io"
|
||||||
|
G "github.com/IBM/fp-go/iterator/stateless/generic"
|
||||||
|
L "github.com/IBM/fp-go/lazy"
|
||||||
|
)
|
||||||
|
|
||||||
|
// FromLazy returns an [Iterator] on top of a lazy function
|
||||||
|
func FromLazy[U any](l L.Lazy[U]) Iterator[U] {
|
||||||
|
return G.FromLazy[Iterator[U], L.Lazy[U]](l)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FromIO returns an [Iterator] on top of an IO function
|
||||||
|
func FromIO[U any](io IO.IO[U]) Iterator[U] {
|
||||||
|
return G.FromLazy[Iterator[U], IO.IO[U]](io)
|
||||||
|
}
|
38
iterator/stateless/io_test.go
Normal file
38
iterator/stateless/io_test.go
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
// Copyright (c) 2023 IBM Corp.
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package stateless
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/rand"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestIteratorFromLazy(t *testing.T) {
|
||||||
|
num := rand.Int
|
||||||
|
|
||||||
|
cit := FromLazy(num)
|
||||||
|
|
||||||
|
// create arrays twice
|
||||||
|
c1 := ToArray(cit)
|
||||||
|
c2 := ToArray(cit)
|
||||||
|
|
||||||
|
assert.Equal(t, 1, len(c1))
|
||||||
|
assert.Equal(t, 1, len(c2))
|
||||||
|
|
||||||
|
assert.NotEqual(t, c1, c2)
|
||||||
|
}
|
14
lambda/y.go
14
lambda/y.go
@@ -15,16 +15,12 @@
|
|||||||
|
|
||||||
package lambda
|
package lambda
|
||||||
|
|
||||||
type (
|
|
||||||
// RecFct is the function called recursively
|
|
||||||
RecFct[T, R any] func(T) R
|
|
||||||
|
|
||||||
internalCombinator[T, R any] func(internalCombinator[T, R]) RecFct[T, R]
|
|
||||||
)
|
|
||||||
|
|
||||||
// Y is the Y-combinator based on https://dreamsongs.com/Files/WhyOfY.pdf
|
// Y is the Y-combinator based on https://dreamsongs.com/Files/WhyOfY.pdf
|
||||||
func Y[TRFRM ~func(RecFct[T, R]) RecFct[T, R], T, R any](f TRFRM) RecFct[T, R] {
|
func Y[Endo ~func(RecFct) RecFct, RecFct ~func(T) R, T, R any](f Endo) RecFct {
|
||||||
g := func(h internalCombinator[T, R]) RecFct[T, R] {
|
|
||||||
|
type internal[RecFct ~func(T) R, T, R any] func(internal[RecFct, T, R]) RecFct
|
||||||
|
|
||||||
|
g := func(h internal[RecFct, T, R]) RecFct {
|
||||||
return func(t T) R {
|
return func(t T) R {
|
||||||
return f(h(h))(t)
|
return f(h(h))(t)
|
||||||
}
|
}
|
||||||
|
@@ -16,12 +16,13 @@
|
|||||||
package lambda
|
package lambda
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestFactorial(t *testing.T) {
|
func TestFactorial(t *testing.T) {
|
||||||
fct := Y(func(r RecFct[int, int]) RecFct[int, int] {
|
fct := Y(func(r func(int) int) func(int) int {
|
||||||
return func(n int) int {
|
return func(n int) int {
|
||||||
if n <= 0 {
|
if n <= 0 {
|
||||||
return 1
|
return 1
|
||||||
@@ -29,6 +30,5 @@ func TestFactorial(t *testing.T) {
|
|||||||
return n * r(n-1)
|
return n * r(n-1)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
assert.Equal(t, 3628800, fct(10))
|
||||||
fmt.Println(fct(10))
|
|
||||||
}
|
}
|
||||||
|
@@ -17,6 +17,7 @@
|
|||||||
package iso
|
package iso
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
EM "github.com/IBM/fp-go/endomorphism"
|
||||||
F "github.com/IBM/fp-go/function"
|
F "github.com/IBM/fp-go/function"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -52,7 +53,7 @@ func Reverse[S, A any](sa Iso[S, A]) Iso[A, S] {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func modify[S, A any](f func(A) A, sa Iso[S, A], s S) S {
|
func modify[FCT ~func(A) A, S, A any](f FCT, sa Iso[S, A], s S) S {
|
||||||
return F.Pipe3(
|
return F.Pipe3(
|
||||||
s,
|
s,
|
||||||
sa.Get,
|
sa.Get,
|
||||||
@@ -62,8 +63,8 @@ func modify[S, A any](f func(A) A, sa Iso[S, A], s S) S {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Modify applies a transformation
|
// Modify applies a transformation
|
||||||
func Modify[S, A any](f func(A) A) func(Iso[S, A]) func(S) S {
|
func Modify[S any, FCT ~func(A) A, A any](f FCT) func(Iso[S, A]) EM.Endomorphism[S] {
|
||||||
return F.Curry3(modify[S, A])(f)
|
return EM.Curry3(modify[FCT, S, A])(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wrap wraps the value
|
// Wrap wraps the value
|
||||||
|
@@ -16,6 +16,7 @@
|
|||||||
package lens
|
package lens
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
EM "github.com/IBM/fp-go/endomorphism"
|
||||||
F "github.com/IBM/fp-go/function"
|
F "github.com/IBM/fp-go/function"
|
||||||
I "github.com/IBM/fp-go/optics/iso"
|
I "github.com/IBM/fp-go/optics/iso"
|
||||||
L "github.com/IBM/fp-go/optics/lens"
|
L "github.com/IBM/fp-go/optics/lens"
|
||||||
@@ -23,10 +24,10 @@ import (
|
|||||||
|
|
||||||
// IsoAsLens converts an `Iso` to a `Lens`
|
// IsoAsLens converts an `Iso` to a `Lens`
|
||||||
func IsoAsLens[S, A any](sa I.Iso[S, A]) L.Lens[S, A] {
|
func IsoAsLens[S, A any](sa I.Iso[S, A]) L.Lens[S, A] {
|
||||||
return L.MakeLensCurried(sa.Get, F.Flow2(sa.ReverseGet, F.Constant1[S, S]))
|
return L.MakeLensCurried(sa.Get, F.Flow2(sa.ReverseGet, F.Flow2(F.Constant1[S, S], EM.Of[func(S) S])))
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsoAsLensRef converts an `Iso` to a `Lens`
|
// IsoAsLensRef converts an `Iso` to a `Lens`
|
||||||
func IsoAsLensRef[S, A any](sa I.Iso[*S, A]) L.Lens[*S, A] {
|
func IsoAsLensRef[S, A any](sa I.Iso[*S, A]) L.Lens[*S, A] {
|
||||||
return L.MakeLensRefCurried(sa.Get, F.Flow2(sa.ReverseGet, F.Constant1[*S, *S]))
|
return L.MakeLensRefCurried(sa.Get, F.Flow2(sa.ReverseGet, F.Flow2(F.Constant1[*S, *S], EM.Of[func(*S) *S])))
|
||||||
}
|
}
|
||||||
|
@@ -17,8 +17,8 @@
|
|||||||
package lens
|
package lens
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
EM "github.com/IBM/fp-go/endomorphism"
|
||||||
F "github.com/IBM/fp-go/function"
|
F "github.com/IBM/fp-go/function"
|
||||||
I "github.com/IBM/fp-go/identity"
|
|
||||||
O "github.com/IBM/fp-go/option"
|
O "github.com/IBM/fp-go/option"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -26,13 +26,13 @@ type (
|
|||||||
// Lens is a reference to a subpart of a data type
|
// Lens is a reference to a subpart of a data type
|
||||||
Lens[S, A any] struct {
|
Lens[S, A any] struct {
|
||||||
Get func(s S) A
|
Get func(s S) A
|
||||||
Set func(a A) func(S) S
|
Set func(a A) EM.Endomorphism[S]
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
// setCopy wraps a setter for a pointer into a setter that first creates a copy before
|
// setCopy wraps a setter for a pointer into a setter that first creates a copy before
|
||||||
// modifying that copy
|
// modifying that copy
|
||||||
func setCopy[S, A any](setter func(*S, A) *S) func(s *S, a A) *S {
|
func setCopy[SET ~func(*S, A) *S, S, A any](setter SET) func(s *S, a A) *S {
|
||||||
return func(s *S, a A) *S {
|
return func(s *S, a A) *S {
|
||||||
copy := *s
|
copy := *s
|
||||||
return setter(©, a)
|
return setter(©, a)
|
||||||
@@ -41,8 +41,8 @@ func setCopy[S, A any](setter func(*S, A) *S) func(s *S, a A) *S {
|
|||||||
|
|
||||||
// setCopyCurried wraps a setter for a pointer into a setter that first creates a copy before
|
// setCopyCurried wraps a setter for a pointer into a setter that first creates a copy before
|
||||||
// modifying that copy
|
// modifying that copy
|
||||||
func setCopyCurried[S, A any](setter func(A) func(*S) *S) func(a A) func(*S) *S {
|
func setCopyCurried[SET ~func(A) EM.Endomorphism[*S], S, A any](setter SET) func(a A) EM.Endomorphism[*S] {
|
||||||
return func(a A) func(*S) *S {
|
return func(a A) EM.Endomorphism[*S] {
|
||||||
seta := setter(a)
|
seta := setter(a)
|
||||||
return func(s *S) *S {
|
return func(s *S) *S {
|
||||||
copy := *s
|
copy := *s
|
||||||
@@ -51,53 +51,53 @@ func setCopyCurried[S, A any](setter func(A) func(*S) *S) func(a A) func(*S) *S
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MakeLens creates a lens based on a getter and a setter function. Make sure that the setter creates a (shallow) copy of the
|
// MakeLens creates a [Lens] based on a getter and a setter function. Make sure that the setter creates a (shallow) copy of the
|
||||||
// data. This happens automatically if the data is passed by value. For pointers consider to use `MakeLensRef`
|
// data. This happens automatically if the data is passed by value. For pointers consider to use `MakeLensRef`
|
||||||
// and for other kinds of data structures that are copied by reference make sure the setter creates the copy.
|
// and for other kinds of data structures that are copied by reference make sure the setter creates the copy.
|
||||||
func MakeLens[S, A any](get func(S) A, set func(S, A) S) Lens[S, A] {
|
func MakeLens[GET ~func(S) A, SET ~func(S, A) S, S, A any](get GET, set SET) Lens[S, A] {
|
||||||
return MakeLensCurried(get, F.Curry2(F.Swap(set)))
|
return MakeLensCurried(get, EM.Curry2(F.Swap(set)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// MakeLensCurried creates a lens based on a getter and a setter function. Make sure that the setter creates a (shallow) copy of the
|
// MakeLensCurried creates a [Lens] based on a getter and a setter function. Make sure that the setter creates a (shallow) copy of the
|
||||||
// data. This happens automatically if the data is passed by value. For pointers consider to use `MakeLensRef`
|
// data. This happens automatically if the data is passed by value. For pointers consider to use `MakeLensRef`
|
||||||
// and for other kinds of data structures that are copied by reference make sure the setter creates the copy.
|
// and for other kinds of data structures that are copied by reference make sure the setter creates the copy.
|
||||||
func MakeLensCurried[S, A any](get func(S) A, set func(A) func(S) S) Lens[S, A] {
|
func MakeLensCurried[GET ~func(S) A, SET ~func(A) EM.Endomorphism[S], S, A any](get GET, set SET) Lens[S, A] {
|
||||||
return Lens[S, A]{Get: get, Set: set}
|
return Lens[S, A]{Get: get, Set: set}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MakeLensRef creates a lens based on a getter and a setter function. The setter passed in does not have to create a shallow
|
// MakeLensRef creates a [Lens] based on a getter and a setter function. The setter passed in does not have to create a shallow
|
||||||
// copy, the implementation wraps the setter into one that copies the pointer before modifying it
|
// copy, the implementation wraps the setter into one that copies the pointer before modifying it
|
||||||
//
|
//
|
||||||
// Such a lens assumes that property A of S always exists
|
// Such a [Lens] assumes that property A of S always exists
|
||||||
func MakeLensRef[S, A any](get func(*S) A, set func(*S, A) *S) Lens[*S, A] {
|
func MakeLensRef[GET ~func(*S) A, SET func(*S, A) *S, S, A any](get GET, set SET) Lens[*S, A] {
|
||||||
return MakeLens(get, setCopy(set))
|
return MakeLens(get, setCopy(set))
|
||||||
}
|
}
|
||||||
|
|
||||||
// MakeLensRefCurried creates a lens based on a getter and a setter function. The setter passed in does not have to create a shallow
|
// MakeLensRefCurried creates a [Lens] based on a getter and a setter function. The setter passed in does not have to create a shallow
|
||||||
// copy, the implementation wraps the setter into one that copies the pointer before modifying it
|
// copy, the implementation wraps the setter into one that copies the pointer before modifying it
|
||||||
//
|
//
|
||||||
// Such a lens assumes that property A of S always exists
|
// Such a [Lens] assumes that property A of S always exists
|
||||||
func MakeLensRefCurried[S, A any](get func(*S) A, set func(A) func(*S) *S) Lens[*S, A] {
|
func MakeLensRefCurried[S, A any](get func(*S) A, set func(A) EM.Endomorphism[*S]) Lens[*S, A] {
|
||||||
return MakeLensCurried(get, setCopyCurried(set))
|
return MakeLensCurried(get, setCopyCurried(set))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Id returns a lens implementing the identity operation
|
// id returns a [Lens] implementing the identity operation
|
||||||
func id[S any](creator func(get func(S) S, set func(S, S) S) Lens[S, S]) Lens[S, S] {
|
func id[GET ~func(S) S, SET ~func(S, S) S, S any](creator func(get GET, set SET) Lens[S, S]) Lens[S, S] {
|
||||||
return creator(F.Identity[S], F.Second[S, S])
|
return creator(F.Identity[S], F.Second[S, S])
|
||||||
}
|
}
|
||||||
|
|
||||||
// Id returns a lens implementing the identity operation
|
// Id returns a [Lens] implementing the identity operation
|
||||||
func Id[S any]() Lens[S, S] {
|
func Id[S any]() Lens[S, S] {
|
||||||
return id(MakeLens[S, S])
|
return id(MakeLens[EM.Endomorphism[S], func(S, S) S])
|
||||||
}
|
}
|
||||||
|
|
||||||
// IdRef returns a lens implementing the identity operation
|
// IdRef returns a [Lens] implementing the identity operation
|
||||||
func IdRef[S any]() Lens[*S, *S] {
|
func IdRef[S any]() Lens[*S, *S] {
|
||||||
return id(MakeLensRef[S, *S])
|
return id(MakeLensRef[EM.Endomorphism[*S], func(*S, *S) *S])
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compose combines two lenses and allows to narrow down the focus to a sub-lens
|
// Compose combines two lenses and allows to narrow down the focus to a sub-lens
|
||||||
func compose[S, A, B any](creator func(get func(S) B, set func(S, B) S) Lens[S, B], ab Lens[A, B]) func(Lens[S, A]) Lens[S, B] {
|
func compose[GET ~func(S) B, SET ~func(S, B) S, S, A, B any](creator func(get GET, set SET) Lens[S, B], ab Lens[A, B]) func(Lens[S, A]) Lens[S, B] {
|
||||||
abget := ab.Get
|
abget := ab.Get
|
||||||
abset := ab.Set
|
abset := ab.Set
|
||||||
return func(sa Lens[S, A]) Lens[S, B] {
|
return func(sa Lens[S, A]) Lens[S, B] {
|
||||||
@@ -114,7 +114,7 @@ func compose[S, A, B any](creator func(get func(S) B, set func(S, B) S) Lens[S,
|
|||||||
|
|
||||||
// Compose combines two lenses and allows to narrow down the focus to a sub-lens
|
// Compose combines two lenses and allows to narrow down the focus to a sub-lens
|
||||||
func Compose[S, A, B any](ab Lens[A, B]) func(Lens[S, A]) Lens[S, B] {
|
func Compose[S, A, B any](ab Lens[A, B]) func(Lens[S, A]) Lens[S, B] {
|
||||||
return compose(MakeLens[S, B], ab)
|
return compose(MakeLens[func(S) B, func(S, B) S], ab)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ComposeOption combines a `Lens` that returns an optional value with a `Lens` that returns a definite value
|
// ComposeOption combines a `Lens` that returns an optional value with a `Lens` that returns a definite value
|
||||||
@@ -141,7 +141,7 @@ func ComposeOption[S, B, A any](defaultA A) func(ab Lens[A, B]) func(Lens[S, O.O
|
|||||||
func(s S, ob O.Option[B]) S {
|
func(s S, ob O.Option[B]) S {
|
||||||
return F.Pipe2(
|
return F.Pipe2(
|
||||||
ob,
|
ob,
|
||||||
O.Fold(unseta, func(b B) func(S) S {
|
O.Fold(unseta, func(b B) EM.Endomorphism[S] {
|
||||||
setbona := F.Flow2(
|
setbona := F.Flow2(
|
||||||
ab.Set(b),
|
ab.Set(b),
|
||||||
seta,
|
seta,
|
||||||
@@ -158,7 +158,7 @@ func ComposeOption[S, B, A any](defaultA A) func(ab Lens[A, B]) func(Lens[S, O.O
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
}),
|
}),
|
||||||
I.Ap[S, S](s),
|
EM.Ap(s),
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@@ -174,7 +174,7 @@ func ComposeOption[S, B, A any](defaultA A) func(ab Lens[A, B]) func(Lens[S, O.O
|
|||||||
// if the setter is called with `None[B]` and `A` does exist, 'B' is removed from 'A'
|
// if the setter is called with `None[B]` and `A` does exist, 'B' is removed from 'A'
|
||||||
func ComposeOptions[S, B, A any](defaultA A) func(ab Lens[A, O.Option[B]]) func(Lens[S, O.Option[A]]) Lens[S, O.Option[B]] {
|
func ComposeOptions[S, B, A any](defaultA A) func(ab Lens[A, O.Option[B]]) func(Lens[S, O.Option[A]]) Lens[S, O.Option[B]] {
|
||||||
defa := F.Constant(defaultA)
|
defa := F.Constant(defaultA)
|
||||||
noops := F.Constant(F.Identity[S])
|
noops := EM.Identity[S]
|
||||||
noneb := O.None[B]()
|
noneb := O.None[B]()
|
||||||
return func(ab Lens[A, O.Option[B]]) func(Lens[S, O.Option[A]]) Lens[S, O.Option[B]] {
|
return func(ab Lens[A, O.Option[B]]) func(Lens[S, O.Option[A]]) Lens[S, O.Option[B]] {
|
||||||
unsetb := ab.Set(noneb)
|
unsetb := ab.Set(noneb)
|
||||||
@@ -189,15 +189,15 @@ func ComposeOptions[S, B, A any](defaultA A) func(ab Lens[A, O.Option[B]]) func(
|
|||||||
sa.Get,
|
sa.Get,
|
||||||
O.Chain(ab.Get),
|
O.Chain(ab.Get),
|
||||||
),
|
),
|
||||||
func(b O.Option[B]) func(S) S {
|
func(b O.Option[B]) EM.Endomorphism[S] {
|
||||||
return func(s S) S {
|
return func(s S) S {
|
||||||
return O.MonadFold(b, func() func(S) S {
|
return O.MonadFold(b, func() EM.Endomorphism[S] {
|
||||||
return F.Pipe2(
|
return F.Pipe2(
|
||||||
s,
|
s,
|
||||||
sa.Get,
|
sa.Get,
|
||||||
O.Fold(noops, F.Flow2(unsetb, seta)),
|
O.Fold(noops, F.Flow2(unsetb, seta)),
|
||||||
)
|
)
|
||||||
}, func(b B) func(S) S {
|
}, func(b B) EM.Endomorphism[S] {
|
||||||
// sets a B onto an A
|
// sets a B onto an A
|
||||||
setb := F.Flow2(
|
setb := F.Flow2(
|
||||||
ab.Set(O.Some(b)),
|
ab.Set(O.Some(b)),
|
||||||
@@ -218,20 +218,20 @@ func ComposeOptions[S, B, A any](defaultA A) func(ab Lens[A, O.Option[B]]) func(
|
|||||||
|
|
||||||
// Compose combines two lenses and allows to narrow down the focus to a sub-lens
|
// Compose combines two lenses and allows to narrow down the focus to a sub-lens
|
||||||
func ComposeRef[S, A, B any](ab Lens[A, B]) func(Lens[*S, A]) Lens[*S, B] {
|
func ComposeRef[S, A, B any](ab Lens[A, B]) func(Lens[*S, A]) Lens[*S, B] {
|
||||||
return compose(MakeLensRef[S, B], ab)
|
return compose(MakeLensRef[func(*S) B, func(*S, B) *S], ab)
|
||||||
}
|
}
|
||||||
|
|
||||||
func modify[S, A any](f func(A) A, sa Lens[S, A], s S) S {
|
func modify[FCT ~func(A) A, S, A any](f FCT, sa Lens[S, A], s S) S {
|
||||||
return sa.Set(f(sa.Get(s)))(s)
|
return sa.Set(f(sa.Get(s)))(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Modify changes a property of a lens by invoking a transformation function
|
// Modify changes a property of a [Lens] by invoking a transformation function
|
||||||
// if the transformed property has not changes, the method returns the original state
|
// if the transformed property has not changes, the method returns the original state
|
||||||
func Modify[S, A any](f func(A) A) func(Lens[S, A]) func(S) S {
|
func Modify[S any, FCT ~func(A) A, A any](f FCT) func(Lens[S, A]) EM.Endomorphism[S] {
|
||||||
return F.Curry3(modify[S, A])(f)
|
return EM.Curry3(modify[FCT, S, A])(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
func IMap[E, A, B any](ab func(A) B, ba func(B) A) func(Lens[E, A]) Lens[E, B] {
|
func IMap[E any, AB ~func(A) B, BA ~func(B) A, A, B any](ab AB, ba BA) func(Lens[E, A]) Lens[E, B] {
|
||||||
return func(ea Lens[E, A]) Lens[E, B] {
|
return func(ea Lens[E, A]) Lens[E, B] {
|
||||||
return Lens[E, B]{Get: F.Flow2(ea.Get, ab), Set: F.Flow2(ba, ea.Set)}
|
return Lens[E, B]{Get: F.Flow2(ea.Get, ab), Set: F.Flow2(ba, ea.Set)}
|
||||||
}
|
}
|
||||||
@@ -239,7 +239,7 @@ func IMap[E, A, B any](ab func(A) B, ba func(B) A) func(Lens[E, A]) Lens[E, B] {
|
|||||||
|
|
||||||
// fromPredicate returns a `Lens` for a property accessibly as a getter and setter that can be optional
|
// fromPredicate returns a `Lens` for a property accessibly as a getter and setter that can be optional
|
||||||
// if the optional value is set then the nil value will be set instead
|
// if the optional value is set then the nil value will be set instead
|
||||||
func fromPredicate[S, A any](creator func(get func(S) O.Option[A], set func(S, O.Option[A]) S) Lens[S, O.Option[A]], pred func(A) bool, nilValue A) func(sa Lens[S, A]) Lens[S, O.Option[A]] {
|
func fromPredicate[GET ~func(S) O.Option[A], SET ~func(S, O.Option[A]) S, S, A any](creator func(get GET, set SET) Lens[S, O.Option[A]], pred func(A) bool, nilValue A) func(sa Lens[S, A]) Lens[S, O.Option[A]] {
|
||||||
fromPred := O.FromPredicate(pred)
|
fromPred := O.FromPredicate(pred)
|
||||||
return func(sa Lens[S, A]) Lens[S, O.Option[A]] {
|
return func(sa Lens[S, A]) Lens[S, O.Option[A]] {
|
||||||
fold := O.Fold(F.Bind1of1(sa.Set)(nilValue), sa.Set)
|
fold := O.Fold(F.Bind1of1(sa.Set)(nilValue), sa.Set)
|
||||||
@@ -247,7 +247,7 @@ func fromPredicate[S, A any](creator func(get func(S) O.Option[A], set func(S, O
|
|||||||
return F.Pipe2(
|
return F.Pipe2(
|
||||||
a,
|
a,
|
||||||
fold,
|
fold,
|
||||||
I.Ap[S, S](s),
|
EM.Ap(s),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -256,13 +256,13 @@ func fromPredicate[S, A any](creator func(get func(S) O.Option[A], set func(S, O
|
|||||||
// FromPredicate returns a `Lens` for a property accessibly as a getter and setter that can be optional
|
// FromPredicate returns a `Lens` for a property accessibly as a getter and setter that can be optional
|
||||||
// if the optional value is set then the nil value will be set instead
|
// if the optional value is set then the nil value will be set instead
|
||||||
func FromPredicate[S, A any](pred func(A) bool, nilValue A) func(sa Lens[S, A]) Lens[S, O.Option[A]] {
|
func FromPredicate[S, A any](pred func(A) bool, nilValue A) func(sa Lens[S, A]) Lens[S, O.Option[A]] {
|
||||||
return fromPredicate(MakeLens[S, O.Option[A]], pred, nilValue)
|
return fromPredicate(MakeLens[func(S) O.Option[A], func(S, O.Option[A]) S], pred, nilValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FromPredicateRef returns a `Lens` for a property accessibly as a getter and setter that can be optional
|
// FromPredicateRef returns a `Lens` for a property accessibly as a getter and setter that can be optional
|
||||||
// if the optional value is set then the nil value will be set instead
|
// if the optional value is set then the nil value will be set instead
|
||||||
func FromPredicateRef[S, A any](pred func(A) bool, nilValue A) func(sa Lens[*S, A]) Lens[*S, O.Option[A]] {
|
func FromPredicateRef[S, A any](pred func(A) bool, nilValue A) func(sa Lens[*S, A]) Lens[*S, O.Option[A]] {
|
||||||
return fromPredicate(MakeLensRef[S, O.Option[A]], pred, nilValue)
|
return fromPredicate(MakeLensRef[func(*S) O.Option[A], func(*S, O.Option[A]) *S], pred, nilValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FromPredicate returns a `Lens` for a property accessibly as a getter and setter that can be optional
|
// FromPredicate returns a `Lens` for a property accessibly as a getter and setter that can be optional
|
||||||
@@ -278,7 +278,7 @@ func FromNillableRef[S, A any](sa Lens[*S, *A]) Lens[*S, O.Option[*A]] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// fromNullableProp returns a `Lens` from a property that may be optional. The getter returns a default value for these items
|
// fromNullableProp returns a `Lens` from a property that may be optional. The getter returns a default value for these items
|
||||||
func fromNullableProp[S, A any](creator func(get func(S) A, set func(S, A) S) Lens[S, A], isNullable func(A) O.Option[A], defaultValue A) func(sa Lens[S, A]) Lens[S, A] {
|
func fromNullableProp[GET ~func(S) A, SET ~func(S, A) S, S, A any](creator func(get GET, set SET) Lens[S, A], isNullable func(A) O.Option[A], defaultValue A) func(sa Lens[S, A]) Lens[S, A] {
|
||||||
return func(sa Lens[S, A]) Lens[S, A] {
|
return func(sa Lens[S, A]) Lens[S, A] {
|
||||||
return creator(F.Flow3(
|
return creator(F.Flow3(
|
||||||
sa.Get,
|
sa.Get,
|
||||||
@@ -293,16 +293,16 @@ func fromNullableProp[S, A any](creator func(get func(S) A, set func(S, A) S) Le
|
|||||||
|
|
||||||
// FromNullableProp returns a `Lens` from a property that may be optional. The getter returns a default value for these items
|
// FromNullableProp returns a `Lens` from a property that may be optional. The getter returns a default value for these items
|
||||||
func FromNullableProp[S, A any](isNullable func(A) O.Option[A], defaultValue A) func(sa Lens[S, A]) Lens[S, A] {
|
func FromNullableProp[S, A any](isNullable func(A) O.Option[A], defaultValue A) func(sa Lens[S, A]) Lens[S, A] {
|
||||||
return fromNullableProp(MakeLens[S, A], isNullable, defaultValue)
|
return fromNullableProp(MakeLens[func(S) A, func(S, A) S], isNullable, defaultValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FromNullablePropRef returns a `Lens` from a property that may be optional. The getter returns a default value for these items
|
// FromNullablePropRef returns a `Lens` from a property that may be optional. The getter returns a default value for these items
|
||||||
func FromNullablePropRef[S, A any](isNullable func(A) O.Option[A], defaultValue A) func(sa Lens[*S, A]) Lens[*S, A] {
|
func FromNullablePropRef[S, A any](isNullable func(A) O.Option[A], defaultValue A) func(sa Lens[*S, A]) Lens[*S, A] {
|
||||||
return fromNullableProp(MakeLensRef[S, A], isNullable, defaultValue)
|
return fromNullableProp(MakeLensRef[func(*S) A, func(*S, A) *S], isNullable, defaultValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
// fromFromOption returns a `Lens` from an option property. The getter returns a default value the setter will always set the some option
|
// fromFromOption returns a `Lens` from an option property. The getter returns a default value the setter will always set the some option
|
||||||
func fromOption[S, A any](creator func(get func(S) A, set func(S, A) S) Lens[S, A], defaultValue A) func(sa Lens[S, O.Option[A]]) Lens[S, A] {
|
func fromOption[GET ~func(S) A, SET ~func(S, A) S, S, A any](creator func(get GET, set SET) Lens[S, A], defaultValue A) func(sa Lens[S, O.Option[A]]) Lens[S, A] {
|
||||||
return func(sa Lens[S, O.Option[A]]) Lens[S, A] {
|
return func(sa Lens[S, O.Option[A]]) Lens[S, A] {
|
||||||
return creator(F.Flow2(
|
return creator(F.Flow2(
|
||||||
sa.Get,
|
sa.Get,
|
||||||
@@ -316,10 +316,10 @@ func fromOption[S, A any](creator func(get func(S) A, set func(S, A) S) Lens[S,
|
|||||||
|
|
||||||
// FromFromOption returns a `Lens` from an option property. The getter returns a default value the setter will always set the some option
|
// FromFromOption returns a `Lens` from an option property. The getter returns a default value the setter will always set the some option
|
||||||
func FromOption[S, A any](defaultValue A) func(sa Lens[S, O.Option[A]]) Lens[S, A] {
|
func FromOption[S, A any](defaultValue A) func(sa Lens[S, O.Option[A]]) Lens[S, A] {
|
||||||
return fromOption(MakeLens[S, A], defaultValue)
|
return fromOption(MakeLens[func(S) A, func(S, A) S], defaultValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FromFromOptionRef returns a `Lens` from an option property. The getter returns a default value the setter will always set the some option
|
// FromFromOptionRef returns a `Lens` from an option property. The getter returns a default value the setter will always set the some option
|
||||||
func FromOptionRef[S, A any](defaultValue A) func(sa Lens[*S, O.Option[A]]) Lens[*S, A] {
|
func FromOptionRef[S, A any](defaultValue A) func(sa Lens[*S, O.Option[A]]) Lens[*S, A] {
|
||||||
return fromOption(MakeLensRef[S, A], defaultValue)
|
return fromOption(MakeLensRef[func(*S) A, func(*S, A) *S], defaultValue)
|
||||||
}
|
}
|
||||||
|
@@ -18,6 +18,7 @@
|
|||||||
package optional
|
package optional
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
EM "github.com/IBM/fp-go/endomorphism"
|
||||||
F "github.com/IBM/fp-go/function"
|
F "github.com/IBM/fp-go/function"
|
||||||
O "github.com/IBM/fp-go/option"
|
O "github.com/IBM/fp-go/option"
|
||||||
)
|
)
|
||||||
@@ -25,12 +26,12 @@ import (
|
|||||||
// Optional is an optional reference to a subpart of a data type
|
// Optional is an optional reference to a subpart of a data type
|
||||||
type Optional[S, A any] struct {
|
type Optional[S, A any] struct {
|
||||||
GetOption func(s S) O.Option[A]
|
GetOption func(s S) O.Option[A]
|
||||||
Set func(a A) func(S) S
|
Set func(a A) EM.Endomorphism[S]
|
||||||
}
|
}
|
||||||
|
|
||||||
// setCopy wraps a setter for a pointer into a setter that first creates a copy before
|
// setCopy wraps a setter for a pointer into a setter that first creates a copy before
|
||||||
// modifying that copy
|
// modifying that copy
|
||||||
func setCopy[S, A any](setter func(*S, A) *S) func(s *S, a A) *S {
|
func setCopy[SET ~func(*S, A) *S, S, A any](setter SET) func(s *S, a A) *S {
|
||||||
return func(s *S, a A) *S {
|
return func(s *S, a A) *S {
|
||||||
copy := *s
|
copy := *s
|
||||||
return setter(©, a)
|
return setter(©, a)
|
||||||
@@ -41,7 +42,7 @@ func setCopy[S, A any](setter func(*S, A) *S) func(s *S, a A) *S {
|
|||||||
// data. This happens automatically if the data is passed by value. For pointers consider to use `MakeOptionalRef`
|
// data. This happens automatically if the data is passed by value. For pointers consider to use `MakeOptionalRef`
|
||||||
// and for other kinds of data structures that are copied by reference make sure the setter creates the copy.
|
// and for other kinds of data structures that are copied by reference make sure the setter creates the copy.
|
||||||
func MakeOptional[S, A any](get func(S) O.Option[A], set func(S, A) S) Optional[S, A] {
|
func MakeOptional[S, A any](get func(S) O.Option[A], set func(S, A) S) Optional[S, A] {
|
||||||
return Optional[S, A]{GetOption: get, Set: F.Curry2(F.Swap(set))}
|
return Optional[S, A]{GetOption: get, Set: EM.Curry2(F.Swap(set))}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MakeOptionalRef creates an Optional based on a getter and a setter function. The setter passed in does not have to create a shallow
|
// MakeOptionalRef creates an Optional based on a getter and a setter function. The setter passed in does not have to create a shallow
|
||||||
@@ -168,7 +169,7 @@ func ichain[S, A, B any](sa Optional[S, A], ab func(A) O.Option[B], ba func(B) O
|
|||||||
return MakeOptional(
|
return MakeOptional(
|
||||||
F.Flow2(sa.GetOption, O.Chain(ab)),
|
F.Flow2(sa.GetOption, O.Chain(ab)),
|
||||||
func(s S, b B) S {
|
func(s S, b B) S {
|
||||||
return O.MonadFold(ba(b), F.Constant(F.Identity[S]), sa.Set)(s)
|
return O.MonadFold(ba(b), EM.Identity[S], sa.Set)(s)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@@ -17,6 +17,7 @@
|
|||||||
package prism
|
package prism
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
EM "github.com/IBM/fp-go/endomorphism"
|
||||||
F "github.com/IBM/fp-go/function"
|
F "github.com/IBM/fp-go/function"
|
||||||
O "github.com/IBM/fp-go/option"
|
O "github.com/IBM/fp-go/option"
|
||||||
)
|
)
|
||||||
@@ -86,12 +87,12 @@ func prismModify[S, A any](f func(A) A, sa Prism[S, A], s S) S {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func prismSet[S, A any](a A) func(Prism[S, A]) func(S) S {
|
func prismSet[S, A any](a A) func(Prism[S, A]) EM.Endomorphism[S] {
|
||||||
return F.Curry3(prismModify[S, A])(F.Constant1[A](a))
|
return EM.Curry3(prismModify[S, A])(F.Constant1[A](a))
|
||||||
}
|
}
|
||||||
|
|
||||||
func Set[S, A any](a A) func(Prism[S, A]) func(S) S {
|
func Set[S, A any](a A) func(Prism[S, A]) EM.Endomorphism[S] {
|
||||||
return F.Curry3(prismModify[S, A])(F.Constant1[A](a))
|
return EM.Curry3(prismModify[S, A])(F.Constant1[A](a))
|
||||||
}
|
}
|
||||||
|
|
||||||
func prismSome[A any]() Prism[O.Option[A], A] {
|
func prismSome[A any]() Prism[O.Option[A], A] {
|
||||||
@@ -103,14 +104,14 @@ func Some[S, A any](soa Prism[S, O.Option[A]]) Prism[S, A] {
|
|||||||
return Compose[S](prismSome[A]())(soa)
|
return Compose[S](prismSome[A]())(soa)
|
||||||
}
|
}
|
||||||
|
|
||||||
func imap[S, A, B any](sa Prism[S, A], ab func(A) B, ba func(B) A) Prism[S, B] {
|
func imap[S any, AB ~func(A) B, BA ~func(B) A, A, B any](sa Prism[S, A], ab AB, ba BA) Prism[S, B] {
|
||||||
return MakePrism(
|
return MakePrism(
|
||||||
F.Flow2(sa.GetOption, O.Map(ab)),
|
F.Flow2(sa.GetOption, O.Map(ab)),
|
||||||
F.Flow2(ba, sa.ReverseGet),
|
F.Flow2(ba, sa.ReverseGet),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func IMap[S, A, B any](ab func(A) B, ba func(B) A) func(Prism[S, A]) Prism[S, B] {
|
func IMap[S any, AB ~func(A) B, BA ~func(B) A, A, B any](ab AB, ba BA) func(Prism[S, A]) Prism[S, B] {
|
||||||
return func(sa Prism[S, A]) Prism[S, B] {
|
return func(sa Prism[S, A]) Prism[S, B] {
|
||||||
return imap(sa, ab, ba)
|
return imap(sa, ab, ba)
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user