1
0
mirror of https://github.com/IBM/fp-go.git synced 2025-12-09 23:11:40 +02:00

Compare commits

..

1 Commits

Author SHA1 Message Date
Dr. Carsten Leue
3bf432af49 fix: add a uniq method to arrays
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-11-30 09:02:38 +01:00
1116 changed files with 2003 additions and 129147 deletions

View File

@@ -4,7 +4,9 @@ on:
push:
branches:
- main
pull_request:
workflow_dispatch:
inputs:
dryRun:
@@ -13,109 +15,35 @@ on:
required: false
env:
# Currently no way to detect automatically
DEFAULT_BRANCH: main
LATEST_GO_VERSION: 1.25.2 # renovate: datasource=golang-version depName=golang
NODE_VERSION: 24
GO_VERSION: 1.20.6 # renovate: datasource=golang-version depName=golang
NODE_VERSION: 18
DRY_RUN: true
jobs:
build-v1:
name: Build v1 (Go ${{ matrix.go-version }})
build:
runs-on: ubuntu-latest
strategy:
matrix:
go-version: ['1.20.x', '1.21.x', '1.22.x', '1.23.x', '1.24.x', '1.25.x']
fail-fast: false # Continue with other versions if one fails
go-version: [ '1.20.x', '1.21.x' ]
steps:
# full checkout for semantic-release
- uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
with:
fetch-depth: 0
- name: Set up Go ${{ matrix.go-version }}
uses: actions/setup-go@v5
- name: Set up go ${{ matrix.go-version }}
uses: actions/setup-go@v4
with:
go-version: ${{ matrix.go-version }}
cache: true # Enable Go module caching
- name: Run tests
-
name: Tests
run: |
go mod tidy
go test -v -race -coverprofile=coverage.txt -covermode=atomic ./...
- name: Upload coverage to Coveralls
uses: coverallsapp/github-action@v2
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
file: ./coverage.txt
flag-name: v1-go-${{ matrix.go-version }}
parallel: true
# - name: Upload coverage to Codecov
# uses: codecov/codecov-action@v5
# with:
# file: ./coverage.txt
# flags: v1,go-${{ matrix.go-version }}
# name: v1-go-${{ matrix.go-version }}
# fail_ci_if_error: false
# env:
# CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
build-v2:
name: Build v2 (Go ${{ matrix.go-version }})
runs-on: ubuntu-latest
strategy:
matrix:
go-version: ['1.24.x', '1.25.x']
steps:
- uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
with:
fetch-depth: 0
- name: Set up Go ${{ matrix.go-version }}
uses: actions/setup-go@v5
with:
go-version: ${{ matrix.go-version }}
cache: true # Enable Go module caching
- name: Run tests
run: |
cd v2
go mod tidy
go test -v -race -coverprofile=coverage.txt -covermode=atomic ./...
- name: Upload coverage to Coveralls
uses: coverallsapp/github-action@v2
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
file: ./v2/coverage.txt
flag-name: v2-go-${{ matrix.go-version }}
parallel: true
# - name: Upload coverage to Codecov
# uses: codecov/codecov-action@v5
# with:
# file: ./v2/coverage.txt
# flags: v2,go-${{ matrix.go-version }}
# name: v2-go-${{ matrix.go-version }}
# fail_ci_if_error: false
# env:
# CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
coveralls-finish:
name: Finish Coveralls
needs:
- build-v1
- build-v2
runs-on: ubuntu-latest
steps:
- name: Coveralls Finished
uses: coverallsapp/github-action@v2
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
parallel-finished: true
go test -v ./...
release:
name: Release
needs:
- build-v1
- build-v2
needs: [build]
if: github.repository == 'IBM/fp-go' && github.event_name != 'pull_request'
runs-on: ubuntu-latest
timeout-minutes: 15
@@ -123,37 +51,38 @@ jobs:
contents: write
issues: write
pull-requests: write
steps:
# full checkout for semantic-release
- name: Full checkout
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
with:
fetch-depth: 0
- name: Set up Node.js ${{ env.NODE_VERSION }}
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0
with:
node-version: ${{ env.NODE_VERSION }}
- name: Set up Go
uses: actions/setup-go@v5
- name: Set up go ${{env.GO_VERSION}}
uses: actions/setup-go@v4
with:
go-version: ${{ env.LATEST_GO_VERSION }}
cache: true # Enable Go module caching
go-version: ${{env.GO_VERSION}}
- name: Determine release mode
id: release-mode
# The dry-run evaluation is only made for non PR events. Manual trigger w/dryRun true, main branch and any tagged branches will set DRY run to false
- name: Check dry run
run: |
if [[ "${{ github.event_name }}" == "workflow_dispatch" && "${{ github.event.inputs.dryRun }}" != "true" ]]; then
if [[ "${{github.event_name}}" == "workflow_dispatch" && "${{ github.event.inputs.dryRun }}" != "true" ]]; then
echo "DRY_RUN=false" >> $GITHUB_ENV
elif [[ "${{github.ref}}" == "refs/heads/${{env.DEFAULT_BRANCH}}" ]]; then
echo "DRY_RUN=false" >> $GITHUB_ENV
elif [[ "${{ github.ref }}" == "refs/heads/${{ env.DEFAULT_BRANCH }}" ]]; then
echo "DRY_RUN=false" >> $GITHUB_ENV
elif [[ "${{ github.ref }}" =~ ^refs/heads/v[0-9]+(\.[0-9]+)?$ ]]; then
elif [[ "${{github.ref}}" =~ ^refs/heads/v[0-9]+(\.[0-9]+)?$ ]]; then
echo "DRY_RUN=false" >> $GITHUB_ENV
fi
- name: Run semantic release
- name: Semantic Release
run: |
npx -p conventional-changelog-conventionalcommits -p semantic-release semantic-release --dry-run ${{ env.DRY_RUN }}
npx -p conventional-changelog-conventionalcommits -p semantic-release semantic-release --dry-run ${{env.DRY_RUN}}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

4
.gitignore vendored
View File

@@ -1,5 +1,3 @@
fp-go.exe
fp-go
main.exe
build/
.idea
build/

View File

@@ -1,3 +0,0 @@
{
"settingsInheritedFrom": "ibm-mend-config/mend-config@main"
}

347
README.md
View File

@@ -1,312 +1,207 @@
# fp-go: Functional Programming Library for Go
# Functional programming library for golang
[![Go Reference](https://pkg.go.dev/badge/github.com/IBM/fp-go.svg)](https://pkg.go.dev/github.com/IBM/fp-go)
[![Coverage Status](https://coveralls.io/repos/github/IBM/fp-go/badge.svg?branch=main)](https://coveralls.io/github/IBM/fp-go?branch=main)
**🚧 Work in progress! 🚧** Despite major version 1 (due to [semantic-release limitations](https://github.com/semantic-release/semantic-release/issues/1507)), we're working to minimize breaking changes.
**🚧 Work in progress! 🚧** Despite major version 1 because of <https://github.com/semantic-release/semantic-release/issues/1507>. Trying to not make breaking changes, but devil is in the details.
![logo](resources/images/logo.png)
A comprehensive functional programming library for Go, strongly influenced by the excellent [fp-ts](https://github.com/gcanti/fp-ts) library for TypeScript.
This library is strongly influenced by the awesome [fp-ts](https://github.com/gcanti/fp-ts).
## 📚 Table of Contents
- [Getting Started](#-getting-started)
- [Design Goals](#-design-goals)
- [Core Concepts](#-core-concepts)
- [Comparison to Idiomatic Go](#comparison-to-idiomatic-go)
- [Implementation Notes](#implementation-notes)
- [Common Operations](#common-operations)
- [Resources](#-resources)
## 🚀 Getting Started
### Installation
## Getting started
```bash
go get github.com/IBM/fp-go
```
### Quick Example
Refer to the [samples](./samples/).
```go
import (
"errors"
"github.com/IBM/fp-go/either"
"github.com/IBM/fp-go/function"
)
Find API documentation [here](https://pkg.go.dev/github.com/IBM/fp-go)
// Pure function that can fail
func divide(a, b int) either.Either[error, int] {
if b == 0 {
return either.Left[int](errors.New("division by zero"))
}
return either.Right[error](a / b)
}
## Design Goal
// Compose operations safely
result := function.Pipe2(
divide(10, 2),
either.Map(func(x int) int { return x * 2 }),
either.GetOrElse(func() int { return 0 }),
)
// result = 10
```
This library aims to provide a set of data types and functions that make it easy and fun to write maintainable and testable code in golang. It encourages the following patterns:
### Resources
- write many small, testable and pure functions, i.e. functions that produce output only depending on their input and that do not execute side effects
- offer helpers to isolate side effects into lazily executed functions (IO)
- expose a consistent set of composition to create new functions from existing ones
- for each data type there exists a small set of composition functions
- these functions are called the same across all data types, so you only have to learn a small number of function names
- the semantic of functions of the same name is consistent across all data types
- 📖 [API Documentation](https://pkg.go.dev/github.com/IBM/fp-go)
- 💡 [Code Samples](./samples/)
- 🆕 [V2 Documentation](./v2/README.md) (requires Go 1.24+)
### How does this play with the [🧘🏽 Zen Of Go](https://the-zen-of-go.netlify.app/)?
## 🎯 Design Goals
#### 🧘🏽 Each package fulfils a single purpose
This library aims to provide a set of data types and functions that make it easy and fun to write maintainable and testable code in Go. It encourages the following patterns:
✔️ Each of the top level packages (e.g. Option, Either, ReaderIOEither, ...) fulfils the purpose of defining the respective data type and implementing the set of common operations for this data type.
### Core Principles
#### 🧘🏽 Handle errors explicitly
- **Pure Functions**: Write many small, testable, and pure functions that produce output only depending on their input and execute no side effects
- **Side Effect Isolation**: Isolate side effects into lazily executed functions using the `IO` monad
- **Consistent Composition**: Expose a consistent set of composition functions across all data types
- Each data type has a small set of composition functions
- Functions are named consistently across all data types
- Semantics of same-named functions are consistent across data types
✔️ The library makes a clear distinction between that operations that cannot fail by design and operations that can fail. Failure is represented via the `Either` type and errors are handled explicitly by using `Either`'s monadic set of operations.
### 🧘🏽 Alignment with the Zen of Go
#### 🧘🏽 Return early rather than nesting deeply
This library respects and aligns with [The Zen of Go](https://the-zen-of-go.netlify.app/):
✔️ We recommend to implement simple, small functions that implement one feature and that would typically not invoke other functions. Interaction with other functions is done by function composition and the composition makes sure to run one function after the other. In the error case the `Either` monad makes sure to skip the error path.
| Principle | Alignment | Explanation |
|-----------|-----------|-------------|
| 🧘🏽 Each package fulfills a single purpose | ✔️ | Each top-level package (Option, Either, ReaderIOEither, etc.) defines one data type and its operations |
| 🧘🏽 Handle errors explicitly | ✔️ | Clear distinction between operations that can/cannot fail; failures represented via `Either` type |
| 🧘🏽 Return early rather than nesting deeply | ✔️ | Small, focused functions composed together; `Either` monad handles error paths automatically |
| 🧘🏽 Leave concurrency to the caller | ✔️ | Pure functions are synchronous; I/O operations are asynchronous by default |
| 🧘🏽 Before you launch a goroutine, know when it will stop | 🤷🏽 | Library doesn't start goroutines; Task monad supports cancellation via context |
| 🧘🏽 Avoid package level state | ✔️ | No package-level state anywhere |
| 🧘🏽 Simplicity matters | ✔️ | Small, consistent interface across data types; focus on business logic |
| 🧘🏽 Write tests to lock in behaviour | 🟡 | Programming pattern encourages testing; library has growing test coverage |
| 🧘🏽 If you think it's slow, first prove it with a benchmark | ✔️ | Performance claims should be backed by benchmarks |
| 🧘🏽 Moderation is a virtue | ✔️ | No custom goroutines or expensive synchronization; atomic counters for coordination |
| 🧘🏽 Maintainability counts | ✔️ | Small, concise operations; pure functions with clear type signatures |
#### 🧘🏽 Leave concurrency to the caller
## 💡 Core Concepts
✔️ All pure are synchronous by default. The I/O operations are asynchronous per default.
### Data Types
#### 🧘🏽 Before you launch a goroutine, know when it will stop
The library provides several key functional data types:
🤷🏽 This is left to the user of the library since the library itself will not start goroutines on its own. The Task monad offers support for cancellation via the golang context, though.
- **`Option[A]`**: Represents an optional value (Some or None)
- **`Either[E, A]`**: Represents a value that can be one of two types (Left for errors, Right for success)
- **`IO[A]`**: Represents a lazy computation that produces a value
- **`IOEither[E, A]`**: Represents a lazy computation that can fail
- **`Reader[R, A]`**: Represents a computation that depends on an environment
- **`ReaderIOEither[R, E, A]`**: Combines Reader, IO, and Either for effectful computations with dependencies
- **`Task[A]`**: Represents an asynchronous computation
- **`State[S, A]`**: Represents a stateful computation
#### 🧘🏽 Avoid package level state
### Monadic Operations
✔️ No package level state anywhere, this would be a significant anti-pattern
All data types support common monadic operations:
#### 🧘🏽 Simplicity matters
- **`Map`**: Transform the value inside a context
- **`Chain`** (FlatMap): Transform and flatten nested contexts
- **`Ap`**: Apply a function in a context to a value in a context
- **`Of`**: Wrap a value in a context
- **`Fold`**: Extract a value from a context
✔️ The library is simple in the sense that it offers a small, consistent interface to a variety of data types. Users can concentrate on implementing business logic rather than dealing with low level data structures.
#### 🧘🏽 Write tests to lock in the behaviour of your package’s API
🟡 The programming pattern suggested by this library encourages writing test cases. The library itself also has a growing number of tests, but not enough, yet. TBD
#### 🧘🏽 If you think it’s slow, first prove it with a benchmark
✔️ Absolutely. If you think the function composition offered by this library is too slow, please provide a benchmark.
#### 🧘🏽 Moderation is a virtue
✔️ The library does not implement its own goroutines and also does not require any expensive synchronization primitives. Coordination of IO operations is implemented via atomic counters without additional primitives.
#### 🧘🏽 Maintainability counts
✔️ Code that consumes this library is easy to maintain because of the small and concise set of operations exposed. Also the suggested programming paradigm to decompose an application into small functions increases maintainability, because these functions are easy to understand and if they are pure, it's often sufficient to look at the type signature to understand the purpose.
The library itself also comprises many small functions, but it's admittedly harder to maintain than code that uses it. However this asymmetry is intended because it offloads complexity from users into a central component.
## Comparison to Idiomatic Go
This section explains how functional APIs differ from idiomatic Go and how to convert between them.
In this section we discuss how the functional APIs differ from idiomatic go function signatures and how to convert back and forth.
### Pure Functions
### Pure functions
Pure functions take input parameters and compute output without changing global state or mutating inputs. They always return the same output for the same input.
Pure functions are functions that take input parameters and that compute an output without changing any global state and without mutating the input parameters. They will always return the same output for the same input.
#### Without Errors
If your pure function doesn't return an error, the idiomatic signature works as-is:
```go
func add(a, b int) int {
return a + b
}
```
If your pure function does not return an error, the idiomatic signature is just fine and no changes are required.
#### With Errors
**Idiomatic Go:**
```go
func divide(a, b int) (int, error) {
if b == 0 {
return 0, errors.New("division by zero")
}
return a / b, nil
}
```
If your pure function can return an error, then it will have a `(T, error)` return value in idiomatic go. In functional style the return value is [Either[error, T]](https://pkg.go.dev/github.com/IBM/fp-go/either) because function composition is easier with such a return type. Use the `EitherizeXXX` methods in ["github.com/IBM/fp-go/either"](https://pkg.go.dev/github.com/IBM/fp-go/either) to convert from idiomatic to functional style and `UneitherizeXXX` to convert from functional to idiomatic style.
**Functional Style:**
```go
func divide(a, b int) either.Either[error, int] {
if b == 0 {
return either.Left[int](errors.New("division by zero"))
}
return either.Right[error](a / b)
}
```
### Effectful functions
**Conversion:**
- Use `either.EitherizeXXX` to convert from idiomatic to functional style
- Use `either.UneitherizeXXX` to convert from functional to idiomatic style
### Effectful Functions
An effectful function changes data outside its scope or doesn't always produce the same output for the same input.
An effectful function (or function with a side effect) is one that changes data outside the scope of the function or that does not always produce the same output for the same input (because it depends on some external, mutable state). There is no special way in idiomatic go to identify such a function other than documentation. In functional style we represent them as functions that do not take an input but that produce an output. The base type for these functions is [IO[T]](https://pkg.go.dev/github.com/IBM/fp-go/io) because in many cases such functions represent `I/O` operations.
#### Without Errors
**Functional signature:** `IO[T]`
```go
func getCurrentTime() io.IO[time.Time] {
return func() time.Time {
return time.Now()
}
}
```
If your effectful function does not return an error, the functional signature is [IO[T]](https://pkg.go.dev/github.com/IBM/fp-go/io)
#### With Errors
**Functional signature:** `IOEither[error, T]`
```go
func readFile(path string) ioeither.IOEither[error, []byte] {
return func() either.Either[error, []byte] {
data, err := os.ReadFile(path)
if err != nil {
return either.Left[[]byte](err)
}
return either.Right[error](data)
}
}
```
**Conversion:**
- Use `ioeither.EitherizeXXX` to convert idiomatic Go functions to functional style
If your effectful function can return an error, the functional signature is [IOEither[error, T]](https://pkg.go.dev/github.com/IBM/fp-go/ioeither). Use `EitherizeXXX` from ["github.com/IBM/fp-go/ioeither"](https://pkg.go.dev/github.com/IBM/fp-go/ioeither) to convert an idiomatic go function to functional style.
### Go Context
Functions that take a `context.Context` are effectful because they depend on mutable context.
Functions that take a [context](https://pkg.go.dev/context) are per definition effectful because they depend on the context parameter that is designed to be mutable (it can e.g. be used to cancel a running operation). Furthermore in idiomatic go the parameter is typically passed as the first parameter to a function.
**Idiomatic Go:**
```go
func fetchData(ctx context.Context, url string) ([]byte, error) {
// implementation
}
```
**Functional Style:**
```go
func fetchData(url string) readerioeither.ReaderIOEither[context.Context, error, []byte] {
return func(ctx context.Context) ioeither.IOEither[error, []byte] {
return func() either.Either[error, []byte] {
// implementation
}
}
}
```
**Conversion:**
- Use `readerioeither.EitherizeXXX` to convert idiomatic Go functions with context to functional style
In functional style we isolate the [context](https://pkg.go.dev/context) and represent the nature of the effectful function as an [IOEither[error, T]](https://pkg.go.dev/github.com/IBM/fp-go/ioeither). The resulting type is [ReaderIOEither[T]](https://pkg.go.dev/github.com/IBM/fp-go/context/readerioeither), a function taking a [context](https://pkg.go.dev/context) that returns a function without parameters returning an [Either[error, T]](https://pkg.go.dev/github.com/IBM/fp-go/either). Use the `EitherizeXXX` methods from ["github.com/IBM/fp-go/context/readerioeither"](https://pkg.go.dev/github.com/IBM/fp-go/context/readerioeither) to convert an idiomatic go function with a [context](https://pkg.go.dev/context) to functional style.
## Implementation Notes
### Generics
All monadic operations use Go generics for type safety:
All monadic operations are implemented via generics, i.e. they offer a type safe way to compose operations. This allows for convenient IDE support and also gives confidence about the correctness of the composition at compile time.
-**Pros**: Type-safe composition, IDE support, compile-time correctness
- ⚠️ **Cons**: May result in larger binaries (different versions per type)
- 💡 **Tip**: For binary size concerns, use type erasure with `any` type
Downside is that this will result in different versions of each operation per type, these versions are generated by the golang compiler at build time (unlike type erasure in languages such as Java of TypeScript). This might lead to large binaries for codebases with many different types. If this is a concern, you can always implement type erasure on top, i.e. use the monadic operations with the `any` type as if generics were not supported. You loose type safety, but this might result in smaller binaries.
### Ordering of Generic Type Parameters
Go requires all type parameters on the global function definition. Parameters that cannot be auto-detected come first:
In go we need to specify all type parameters of a function on the global function definition, even if the function returns a higher order function and some of the type parameters are only applicable to the higher order function. So the following is not possible:
```go
// Map: B cannot be auto-detected, so it comes first
func Map[R, E, A, B any](f func(A) B) func(ReaderIOEither[R, E, A]) ReaderIOEither[R, E, B]
// Ap: B cannot be auto-detected from the argument
func Ap[B, R, E, A any](fa ReaderIOEither[R, E, A]) func(ReaderIOEither[R, E, func(A) B]) ReaderIOEither[R, E, B]
func Map[A, B any](f func(A) B) [R, E any]func(fa ReaderIOEither[R, E, A]) ReaderIOEither[R, E, B]
```
This ordering maximizes type inference where possible.
Note that the parameters `R` and `E` are not needed by the first level of `Map` but only by the resulting higher order function. Instead we need to specify the following:
### Use of the ~ Operator
```go
func Map[R, E, A, B any](f func(A) B) func(fa ReaderIOEither[R, E, A]) ReaderIOEither[R, E, B]
```
Go doesn't support generic type aliases (until Go 1.24), only type definitions. The `~` operator allows generic implementations to work with compatible types:
which overspecifies `Map` on the global scope. As a result the go compiler will not be able to auto-detect these parameters, it can only auto detect `A` and `B` since they appear in the argument of `Map`. We need to explicitly pass values for these type parameters when `Map` is being used.
Because of this limitation the order of parameters on a function matters. We want to make sure that we define those parameters that cannot be auto-detected, first, and the parameters that can be auto-detected, last. This can lead to inconsistencies in parameter ordering, but we believe that the gain in convenience is worth it. The parameter order of `Ap` is e.g. different from that of `Map`:
```go
func Ap[B, R, E, A any](fa ReaderIOEither[R, E, A]) func(fab ReaderIOEither[R, E, func(A) B]) ReaderIOEither[R, E, B]
```
because `R`, `E` and `A` can be determined from the argument to `Ap` but `B` cannot.
### Use of the [~ Operator](https://go.googlesource.com/proposal/+/master/design/47781-parameterized-go-ast.md)
The FP library attempts to be easy to consume and one aspect of this is the definition of higher level type definitions instead of having to use their low level equivalent. It is e.g. more convenient and readable to use
```go
ReaderIOEither[R, E, A]
```
than
```go
func(R) func() Either.Either[E, A]
```
although both are logically equivalent. At the time of this writing the go type system does not support generic type aliases, only generic type definition, i.e. it is not possible to write:
```go
type ReaderIOEither[R, E, A any] = RD.Reader[R, IOE.IOEither[E, A]]
```
only
```go
type ReaderIOEither[R, E, A any] RD.Reader[R, IOE.IOEither[E, A]]
```
**Generic Subpackages:**
- Each higher-level type has a `generic` subpackage with fully generic implementations
- These are for library extensions, not end-users
- Main packages specialize generic implementations for convenience
This makes a big difference, because in the second case the type `ReaderIOEither[R, E, A any]` is considered a completely new type, not compatible to its right hand side, so it's not just a shortcut but a fully new type.
### Higher Kinded Types (HKT)
From the implementation perspective however there is no reason to restrict the implementation to the new type, it can be generic for all compatible types. The way to express this in go is the [~](https://go.googlesource.com/proposal/+/master/design/47781-parameterized-go-ast.md) operator. This comes with some quite complicated type declarations in some cases, which undermines the goal of the library to be easy to use.
Go doesn't support HKT natively. This library addresses this by:
For that reason there exist sub-packages called `Generic` for all higher level types. These packages contain the fully generic implementation of the operations, preferring abstraction over usability. These packages are not meant to be used by end-users but are meant to be used by library extensions. The implementation for the convenient higher level types specializes the generic implementation for the particular higher level type, i.e. this layer does not contain any business logic but only *type magic*.
- Introducing HKTs as individual types (e.g., `HKTA` for `HKT[A]`)
- Implementing generic algorithms in the `internal` package
- Keeping complexity hidden from end-users
### Higher Kinded Types
## Common Operations
Go does not support higher kinded types (HKT). Such types occur if a generic type itself is parametrized by another generic type. Example:
### Map/Chain/Ap/Flap
| Operator | Parameter | Monad | Result | Use Case |
| -------- | ---------------- | --------------- | -------- | -------- |
| Map | `func(A) B` | `HKT[A]` | `HKT[B]` | Transform value in context |
| Chain | `func(A) HKT[B]` | `HKT[A]` | `HKT[B]` | Transform and flatten |
| Ap | `HKT[A]` | `HKT[func(A)B]` | `HKT[B]` | Apply function in context |
| Flap | `A` | `HKT[func(A)B]` | `HKT[B]` | Apply value to function in context |
### Example: Chaining Operations
The `Map` operation for `ReaderIOEither` is defined as:
```go
import (
"github.com/IBM/fp-go/either"
"github.com/IBM/fp-go/function"
)
result := function.Pipe3(
either.Right[error](10),
either.Map(func(x int) int { return x * 2 }),
either.Chain(func(x int) either.Either[error, int] {
if x > 15 {
return either.Right[error](x)
}
return either.Left[int](errors.New("too small"))
}),
either.GetOrElse(func() int { return 0 }),
)
func Map[R, E, A, B any](f func(A) B) func(fa ReaderIOEither[R, E, A]) ReaderIOEither[R, E, B]
```
## 📚 Resources
and in fact the equivalent operations for all other monads follow the same pattern, we could try to introduce a new type for `ReaderIOEither` (without a parameter) as a HKT, e.g. like so (made-up syntax, does not work in go):
- [API Documentation](https://pkg.go.dev/github.com/IBM/fp-go)
- [Code Samples](./samples/)
- [V2 Documentation](./v2/README.md) - New features in Go 1.24+
- [fp-ts](https://github.com/gcanti/fp-ts) - Original TypeScript inspiration
```go
func Map[HKT, R, E, A, B any](f func(A) B) func(HKT[R, E, A]) HKT[R, E, B]
```
## 🤝 Contributing
this would be the completely generic method signature for all possible monads. In particular in many cases it is possible to compose functions independent of the concrete knowledge of the actual `HKT`. From the perspective of a library this is the ideal situation because then a particular algorithm only has to be implemented and tested once.
Contributions are welcome! Please feel free to submit issues or pull requests.
This FP library addresses this by introducing the HKTs as individual types, e.g. `HKT[A]` would be represented as a new generic type `HKTA`. This loses the correlation to the type `A` but allows to implement generic algorithms, at the price of readability.
## 📄 License
For that reason these implementations are kept in the `internal` package. These are meant to be used by the library itself or by extensions, not by end users.
This project is licensed under the Apache License 2.0 - see the LICENSE file for details.
## Map/Ap/Flap
The following table lists the relationship between some selected operators
| Opertator | Parameter | Monad | Result |
| -------- | ---------------- | --------------- | -------- |
| Map | `func(A) B` | `HKT[A]` | `HKT[B]` |
| Chain | `func(A) HKT[B]` | `HKT[A]` | `HKT[B]` |
| Ap | `HKT[A]` | `HKT[func(A)B]` | `HKT[B]` |
| Flap | `A` | `HKT[func(A)B]` | `HKT[B]` |

View File

@@ -17,7 +17,6 @@ package array
import (
G "github.com/IBM/fp-go/array/generic"
EM "github.com/IBM/fp-go/endomorphism"
F "github.com/IBM/fp-go/function"
"github.com/IBM/fp-go/internal/array"
M "github.com/IBM/fp-go/monoid"
@@ -58,7 +57,7 @@ func MapWithIndex[A, B any](f func(int, A) B) func([]A) []B {
}
func Map[A, B any](f func(a A) B) func([]A) []B {
return G.Map[[]A, []B, A, B](f)
return F.Bind2nd(MonadMap[A, B], f)
}
func MapRef[A, B any](f func(a *A) B) func([]A) []B {
@@ -90,16 +89,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
func Filter[A any](pred func(A) bool) EM.Endomorphism[[]A] {
func Filter[A any](pred func(A) bool) func([]A) []A {
return G.Filter[[]A](pred)
}
// 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) EM.Endomorphism[[]A] {
func FilterWithIndex[A any](pred func(int, A) bool) func([]A) []A {
return G.FilterWithIndex[[]A](pred)
}
func FilterRef[A any](pred func(*A) bool) EM.Endomorphism[[]A] {
func FilterRef[A any](pred func(*A) bool) func([]A) []A {
return F.Bind2nd(filterRef[A], pred)
}
@@ -141,10 +140,6 @@ func reduceRef[A, B any](fa []A, f func(B, *A) B, initial B) B {
return current
}
func MonadReduce[A, B any](fa []A, f func(B, A) B, initial B) B {
return G.MonadReduce(fa, f, initial)
}
func Reduce[A, B any](f func(B, A) B, initial B) func([]A) B {
return G.Reduce[[]A](f, initial)
}
@@ -232,7 +227,7 @@ func Last[A any](as []A) O.Option[A] {
return G.Last(as)
}
func PrependAll[A any](middle A) EM.Endomorphism[[]A] {
func PrependAll[A any](middle A) func([]A) []A {
return func(as []A) []A {
count := len(as)
dst := count * 2
@@ -247,7 +242,7 @@ func PrependAll[A any](middle A) EM.Endomorphism[[]A] {
}
}
func Intersperse[A any](middle A) EM.Endomorphism[[]A] {
func Intersperse[A any](middle A) func([]A) []A {
prepend := PrependAll(middle)
return func(as []A) []A {
if IsEmpty(as) {
@@ -276,7 +271,7 @@ func Lookup[A any](idx int) func([]A) O.Option[A] {
return G.Lookup[[]A](idx)
}
func UpsertAt[A any](a A) EM.Endomorphism[[]A] {
func UpsertAt[A any](a A) func([]A) []A {
return G.UpsertAt[[]A](a)
}
@@ -309,20 +304,14 @@ func ConstNil[A any]() []A {
return array.ConstNil[[]A]()
}
func SliceRight[A any](start int) EM.Endomorphism[[]A] {
func SliceRight[A any](start int) func([]A) []A {
return G.SliceRight[[]A](start)
}
// Copy creates a shallow copy of the array
func Copy[A any](b []A) []A {
return G.Copy(b)
}
// Clone creates a deep copy of the array using the provided endomorphism to clone the values
func Clone[A any](f func(A) A) func(as []A) []A {
return G.Clone[[]A](f)
}
// FoldMap maps and folds an array. Map the Array passing each value to the iterating function. Then fold the results using the provided Monoid.
func FoldMap[A, B any](m M.Monoid[B]) func(func(A) B) func([]A) B {
return G.FoldMap[[]A](m)
@@ -338,8 +327,8 @@ func Fold[A any](m M.Monoid[A]) func([]A) A {
return G.Fold[[]A](m)
}
func Push[A any](a A) EM.Endomorphism[[]A] {
return G.Push[EM.Endomorphism[[]A]](a)
func Push[A any](a A) func([]A) []A {
return G.Push[[]A](a)
}
func MonadFlap[B, A any](fab []func(A) B, a A) []B {
@@ -349,7 +338,3 @@ func MonadFlap[B, A any](fab []func(A) B, a A) []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)
}
func Prepend[A any](head A) EM.Endomorphism[[]A] {
return G.Prepend[EM.Endomorphism[[]A]](head)
}

View File

@@ -1,66 +0,0 @@
// 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
import (
G "github.com/IBM/fp-go/array/generic"
)
// Bind creates an empty context of type [S] to be used with the [Bind] operation
func Do[S any](
empty S,
) []S {
return G.Do[[]S, S](empty)
}
// Bind attaches the result of a computation to a context [S1] to produce a context [S2]
func Bind[S1, S2, T any](
setter func(T) func(S1) S2,
f func(S1) []T,
) func([]S1) []S2 {
return G.Bind[[]S1, []S2, []T, S1, S2, T](setter, f)
}
// Let attaches the result of a computation to a context [S1] to produce a context [S2]
func Let[S1, S2, T any](
setter func(T) func(S1) S2,
f func(S1) T,
) func([]S1) []S2 {
return G.Let[[]S1, []S2, S1, S2, T](setter, f)
}
// LetTo attaches the a value to a context [S1] to produce a context [S2]
func LetTo[S1, S2, T any](
setter func(T) func(S1) S2,
b T,
) func([]S1) []S2 {
return G.LetTo[[]S1, []S2, S1, S2, T](setter, b)
}
// BindTo initializes a new state [S1] from a value [T]
func BindTo[S1, T any](
setter func(T) S1,
) func([]T) []S1 {
return G.BindTo[[]S1, []T, S1, T](setter)
}
// ApS attaches a value to a context [S1] to produce a context [S2] by considering the context and the value concurrently
func ApS[S1, S2, T any](
setter func(T) func(S1) S2,
fa []T,
) func([]S1) []S2 {
return G.ApS[[]S1, []S2, []T, S1, S2, T](setter, fa)
}

View File

@@ -1,56 +0,0 @@
// 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
import (
"testing"
F "github.com/IBM/fp-go/function"
"github.com/IBM/fp-go/internal/utils"
"github.com/stretchr/testify/assert"
)
func getLastName(s utils.Initial) []string {
return Of("Doe")
}
func getGivenName(s utils.WithLastName) []string {
return Of("John")
}
func TestBind(t *testing.T) {
res := F.Pipe3(
Do(utils.Empty),
Bind(utils.SetLastName, getLastName),
Bind(utils.SetGivenName, getGivenName),
Map(utils.GetFullName),
)
assert.Equal(t, res, Of("John Doe"))
}
func TestApS(t *testing.T) {
res := F.Pipe3(
Do(utils.Empty),
ApS(utils.SetLastName, Of("Doe")),
ApS(utils.SetGivenName, Of("John")),
Map(utils.GetFullName),
)
assert.Equal(t, res, Of("John Doe"))
}

View File

@@ -147,7 +147,7 @@ func MonadMap[GA ~[]A, GB ~[]B, A, B any](as GA, f func(a A) B) GB {
}
func Map[GA ~[]A, GB ~[]B, A, B any](f func(a A) B) func(GA) GB {
return array.Map[GA, GB](f)
return F.Bind2nd(MonadMap[GA, GB, A, B], f)
}
func MonadMapWithIndex[GA ~[]A, GB ~[]B, A, B any](as GA, f func(int, A) B) GB {
@@ -304,11 +304,6 @@ func Copy[AS ~[]A, A any](b AS) AS {
return buf
}
func Clone[AS ~[]A, A any](f func(A) A) func(as AS) AS {
// implementation assumes that map does not optimize for the empty array
return Map[AS, AS](f)
}
func FoldMap[AS ~[]A, A, B any](m M.Monoid[B]) func(func(A) B) func(AS) B {
return func(f func(A) B) func(AS) B {
return func(as AS) B {
@@ -335,7 +330,7 @@ func Fold[AS ~[]A, A any](m M.Monoid[A]) func(AS) A {
}
}
func Push[ENDO ~func(GA) GA, GA ~[]A, A any](a A) ENDO {
func Push[GA ~[]A, A any](a A) func(GA) GA {
return F.Bind2nd(array.Push[GA, A], a)
}
@@ -344,9 +339,5 @@ 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 {
return FC.Flap(Map[GFAB, GB], a)
}
func Prepend[ENDO ~func(AS) AS, AS []A, A any](head A) ENDO {
return array.Prepend[ENDO](head)
return F.Bind2nd(MonadFlap[FAB, GFAB, GB, A, B], a)
}

View File

@@ -1,89 +0,0 @@
// 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 (
A "github.com/IBM/fp-go/internal/apply"
C "github.com/IBM/fp-go/internal/chain"
F "github.com/IBM/fp-go/internal/functor"
)
// Bind creates an empty context of type [S] to be used with the [Bind] operation
func Do[GS ~[]S, S any](
empty S,
) GS {
return Of[GS](empty)
}
// Bind attaches the result of a computation to a context [S1] to produce a context [S2]
func Bind[GS1 ~[]S1, GS2 ~[]S2, GT ~[]T, S1, S2, T any](
setter func(T) func(S1) S2,
f func(S1) GT,
) func(GS1) GS2 {
return C.Bind(
Chain[GS1, GS2, S1, S2],
Map[GT, GS2, T, S2],
setter,
f,
)
}
// Let attaches the result of a computation to a context [S1] to produce a context [S2]
func Let[GS1 ~[]S1, GS2 ~[]S2, S1, S2, T any](
key func(T) func(S1) S2,
f func(S1) T,
) func(GS1) GS2 {
return F.Let(
Map[GS1, GS2, S1, S2],
key,
f,
)
}
// LetTo attaches the a value to a context [S1] to produce a context [S2]
func LetTo[GS1 ~[]S1, GS2 ~[]S2, S1, S2, B any](
key func(B) func(S1) S2,
b B,
) func(GS1) GS2 {
return F.LetTo(
Map[GS1, GS2, S1, S2],
key,
b,
)
}
// BindTo initializes a new state [S1] from a value [T]
func BindTo[GS1 ~[]S1, GT ~[]T, S1, T any](
setter func(T) S1,
) func(GT) GS1 {
return C.BindTo(
Map[GT, GS1, T, S1],
setter,
)
}
// ApS attaches a value to a context [S1] to produce a context [S2] by considering the context and the value concurrently
func ApS[GS1 ~[]S1, GS2 ~[]S2, GT ~[]T, S1, S2, T any](
setter func(T) func(S1) S2,
fa GT,
) func(GS1) GS2 {
return A.ApS(
Ap[GS2, []func(T) S2, GT, S2, T],
Map[GS1, []func(T) S2, S1, func(T) S2],
setter,
fa,
)
}

View File

@@ -1,43 +0,0 @@
// Copyright (c) 2024 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 (
"github.com/IBM/fp-go/internal/monad"
)
type arrayMonad[A, B any, GA ~[]A, GB ~[]B, GAB ~[]func(A) B] struct{}
func (o *arrayMonad[A, B, GA, GB, GAB]) Of(a A) GA {
return Of[GA, A](a)
}
func (o *arrayMonad[A, B, GA, GB, GAB]) Map(f func(A) B) func(GA) GB {
return Map[GA, GB, A, B](f)
}
func (o *arrayMonad[A, B, GA, GB, GAB]) Chain(f func(A) GB) func(GA) GB {
return Chain[GA, GB, A, B](f)
}
func (o *arrayMonad[A, B, GA, GB, GAB]) Ap(fa GA) func(GAB) GB {
return Ap[GB, GAB, GA, B, A](fa)
}
// Monad implements the monadic operations for an array
func Monad[A, B any, GA ~[]A, GB ~[]B, GAB ~[]func(A) B]() monad.Monad[A, B, GA, GB, GAB] {
return &arrayMonad[A, B, GA, GB, GAB]{}
}

View File

@@ -1,26 +0,0 @@
// Copyright (c) 2024 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
import (
G "github.com/IBM/fp-go/array/generic"
"github.com/IBM/fp-go/internal/monad"
)
// Monad returns the monadic operations for an array
func Monad[A, B any]() monad.Monad[A, B, []A, []B, []func(A) B] {
return G.Monad[A, B, []A, []B, []func(A) B]()
}

View File

@@ -24,10 +24,10 @@ import (
func concat[T any](left, right []T) []T {
// some performance checks
ll := len(left)
lr := len(right)
if ll == 0 {
return right
}
lr := len(right)
if lr == 0 {
return left
}

View File

@@ -17,7 +17,6 @@ package nonempty
import (
G "github.com/IBM/fp-go/array/generic"
EM "github.com/IBM/fp-go/endomorphism"
F "github.com/IBM/fp-go/function"
"github.com/IBM/fp-go/internal/array"
S "github.com/IBM/fp-go/semigroup"
@@ -44,11 +43,11 @@ func From[A any](first A, data ...A) NonEmptyArray[A] {
return buffer
}
func IsEmpty[A any](_ NonEmptyArray[A]) bool {
func IsEmpty[A any](as NonEmptyArray[A]) bool {
return false
}
func IsNonEmpty[A any](_ NonEmptyArray[A]) bool {
func IsNonEmpty[A any](as NonEmptyArray[A]) bool {
return true
}
@@ -66,12 +65,6 @@ 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 {
return as[1:]
}
@@ -129,8 +122,3 @@ func Fold[A any](s S.Semigroup[A]) func(NonEmptyArray[A]) A {
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)
}

View File

@@ -1,74 +0,0 @@
// 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 testing
import (
"testing"
RA "github.com/IBM/fp-go/array"
EQ "github.com/IBM/fp-go/eq"
L "github.com/IBM/fp-go/internal/monad/testing"
)
// AssertLaws asserts the apply monad laws for the array monad
func AssertLaws[A, B, C any](t *testing.T,
eqa EQ.Eq[A],
eqb EQ.Eq[B],
eqc EQ.Eq[C],
ab func(A) B,
bc func(B) C,
) func(a A) bool {
return L.AssertLaws(t,
RA.Eq(eqa),
RA.Eq(eqb),
RA.Eq(eqc),
RA.Of[A],
RA.Of[B],
RA.Of[C],
RA.Of[func(A) A],
RA.Of[func(A) B],
RA.Of[func(B) C],
RA.Of[func(func(A) B) B],
RA.MonadMap[A, A],
RA.MonadMap[A, B],
RA.MonadMap[A, C],
RA.MonadMap[B, C],
RA.MonadMap[func(B) C, func(func(A) B) func(A) C],
RA.MonadChain[A, A],
RA.MonadChain[A, B],
RA.MonadChain[A, C],
RA.MonadChain[B, C],
RA.MonadAp[A, A],
RA.MonadAp[B, A],
RA.MonadAp[C, B],
RA.MonadAp[C, A],
RA.MonadAp[B, func(A) B],
RA.MonadAp[func(A) C, func(A) B],
ab,
bc,
)
}

View File

@@ -1,47 +0,0 @@
// 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 testing
import (
"fmt"
"testing"
EQ "github.com/IBM/fp-go/eq"
"github.com/stretchr/testify/assert"
)
func TestMonadLaws(t *testing.T) {
// some comparison
eqa := EQ.FromStrictEquals[bool]()
eqb := EQ.FromStrictEquals[int]()
eqc := EQ.FromStrictEquals[string]()
ab := func(a bool) int {
if a {
return 1
}
return 0
}
bc := func(b int) string {
return fmt.Sprintf("value %d", b)
}
laws := AssertLaws(t, eqa, eqb, eqc, ab, bc)
assert.True(t, laws(true))
assert.True(t, laws(false))
}

View File

@@ -32,20 +32,20 @@ type bounded[T any] struct {
b T
}
func (b bounded[T]) Equals(x, y T) bool {
return b.e(x, y)
func (self bounded[T]) Equals(x, y T) bool {
return self.e(x, y)
}
func (b bounded[T]) Compare(x, y T) int {
return b.c(x, y)
func (self bounded[T]) Compare(x, y T) int {
return self.c(x, y)
}
func (b bounded[T]) Top() T {
return b.t
func (self bounded[T]) Top() T {
return self.t
}
func (b bounded[T]) Bottom() T {
return b.b
func (self bounded[T]) Bottom() T {
return self.b
}
// MakeBounded creates an instance of a bounded type

View File

@@ -15,10 +15,6 @@
package bytes
func Empty() []byte {
return Monoid.Empty()
}
func ToString(a []byte) string {
return string(a)
}

View File

@@ -34,6 +34,5 @@ func Commands() []*C.Command {
IOEitherCommand(),
IOCommand(),
IOOptionCommand(),
DICommand(),
}
}

View File

@@ -365,70 +365,6 @@ func generateContextReaderIOEitherEitherize(f, fg *os.File, i int) {
fmt.Fprintln(fg, "}")
}
func generateContextReaderIOEitherUneitherize(f, fg *os.File, i int) {
// non generic version
fmt.Fprintf(f, "\n// Uneitherize%d converts a function with %d parameters returning a [ReaderIOEither[R]] into a function with %d parameters returning a tuple.\n// The first parameter is considered to be the [context.Context].\n", i, i+1, i)
fmt.Fprintf(f, "func Uneitherize%d[F ~func(", i)
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T%d", j)
}
fmt.Fprintf(f, ") ReaderIOEither[R]")
for j := 0; j < i; j++ {
fmt.Fprintf(f, ", T%d", j)
}
fmt.Fprintf(f, ", R any](f F) func(context.Context")
for j := 0; j < i; j++ {
fmt.Fprintf(f, ", T%d", j)
}
fmt.Fprintf(f, ") (R, error) {\n")
fmt.Fprintf(f, " return G.Uneitherize%d[ReaderIOEither[R]", i)
fmt.Fprintf(f, ", func(context.Context")
for j := 0; j < i; j++ {
fmt.Fprintf(f, ", T%d", j)
}
fmt.Fprintf(f, ")(R, error)](f)\n")
fmt.Fprintln(f, "}")
// generic version
fmt.Fprintf(fg, "\n// Uneitherize%d converts a function with %d parameters returning a [GRA] into a function with %d parameters returning a tuple.\n// The first parameter is considered to be the [context.Context].\n", i, i, i)
fmt.Fprintf(fg, "func Uneitherize%d[GRA ~func(context.Context) GIOA, F ~func(context.Context", i)
for j := 0; j < i; j++ {
fmt.Fprintf(fg, ", T%d", j)
}
fmt.Fprintf(fg, ") (R, error), GIOA ~func() E.Either[error, R]")
for j := 0; j < i; j++ {
fmt.Fprintf(fg, ", T%d", j)
}
fmt.Fprintf(fg, ", R any](f func(")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(fg, ", ")
}
fmt.Fprintf(fg, "T%d", j)
}
fmt.Fprintf(fg, ") GRA) F {\n")
fmt.Fprintf(fg, " return func(c context.Context")
for j := 0; j < i; j++ {
fmt.Fprintf(fg, ", t%d T%d", j, j)
}
fmt.Fprintf(fg, ") (R, error) {\n")
fmt.Fprintf(fg, " return E.UnwrapError(f(")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(fg, ", ")
}
fmt.Fprintf(fg, "t%d", j)
}
fmt.Fprintf(fg, ")(c)())\n")
fmt.Fprintf(fg, " }\n")
fmt.Fprintf(fg, "}\n")
}
func generateContextReaderIOEitherHelpers(filename string, count int) error {
dir, err := os.Getwd()
if err != nil {
@@ -484,12 +420,10 @@ import (
`)
generateContextReaderIOEitherEitherize(f, fg, 0)
generateContextReaderIOEitherUneitherize(f, fg, 0)
for i := 1; i <= count; i++ {
// eitherize
generateContextReaderIOEitherEitherize(f, fg, i)
generateContextReaderIOEitherUneitherize(f, fg, i)
// sequenceT
generateContextReaderIOEitherSequenceT("")(f, fg, i)
generateContextReaderIOEitherSequenceT("Seq")(f, fg, i)

231
cli/di.go
View File

@@ -1,231 +0,0 @@
// 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),
)
},
}
}

View File

@@ -265,15 +265,10 @@ func generatePipe(f *os.File, i int) {
fmt.Fprintf(f, ", f%d F%d", j, j)
}
fmt.Fprintf(f, ") T%d {\n", i)
fmt.Fprintf(f, " return ")
for j := i; j >= 1; j-- {
fmt.Fprintf(f, "f%d(", j)
}
fmt.Fprintf(f, "t0")
for j := 1; j <= i; j++ {
fmt.Fprintf(f, ")")
fmt.Fprintf(f, " t%d := f%d(t%d)\n", j, j, j-1)
}
fmt.Fprintf(f, "\n")
fmt.Fprintf(f, " return t%d\n", i)
fmt.Fprintln(f, "}")
}
@@ -300,16 +295,15 @@ func recurseCurry(f *os.File, indent string, total, count int) {
func generateCurry(f *os.File, i int) {
// 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, "func Curry%d[FCT ~func(T0", i)
for j := 1; j < i; j++ {
fmt.Fprintf(f, "func Curry%d[T0", i)
for j := 1; j <= i; j++ {
fmt.Fprintf(f, ", T%d", j)
}
fmt.Fprintf(f, ") T%d", i)
// type arguments
for j := 0; j <= i; j++ {
fmt.Fprintf(f, ", T%d", j)
fmt.Fprintf(f, " any](f func(T0")
for j := 2; j <= i; j++ {
fmt.Fprintf(f, ", T%d", j-1)
}
fmt.Fprintf(f, " any](f FCT) func(T0)")
fmt.Fprintf(f, ") T%d) func(T0)", i)
for j := 2; j <= i; j++ {
fmt.Fprintf(f, " func(T%d)", j-1)
}
@@ -321,16 +315,15 @@ func generateCurry(f *os.File, i int) {
func generateUncurry(f *os.File, i int) {
// 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, "func Uncurry%d[FCT ~func(T0)", i)
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, "func Uncurry%d[T0", i)
for j := 1; j <= i; j++ {
fmt.Fprintf(f, ", T%d", j)
}
fmt.Fprintf(f, " any](f FCT) func(")
fmt.Fprintf(f, " any](f")
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++ {
if j > 1 {
fmt.Fprintf(f, ", ")

View File

@@ -136,70 +136,6 @@ func generateReaderIOEitherEitherize(f, fg *os.File, i int) {
fmt.Fprintf(fg, "}\n")
}
func generateReaderIOEitherUneitherize(f, fg *os.File, i int) {
// non generic version
fmt.Fprintf(f, "\n// Uneitherize%d converts a function with %d parameters returning a [ReaderIOEither[C, error, R]] into a function with %d parameters returning a tuple.\n// The first parameter is considered to be the context [C].\n", i, i+1, i)
fmt.Fprintf(f, "func Uneitherize%d[F ~func(", i)
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T%d", j)
}
fmt.Fprintf(f, ") ReaderIOEither[C, error, R]")
for j := 0; j < i; j++ {
fmt.Fprintf(f, ", T%d", j)
}
fmt.Fprintf(f, ", C, R any](f F) func(C")
for j := 0; j < i; j++ {
fmt.Fprintf(f, ", T%d", j)
}
fmt.Fprintf(f, ") (R, error) {\n")
fmt.Fprintf(f, " return G.Uneitherize%d[ReaderIOEither[C, error, R]", i)
fmt.Fprintf(f, ", func(C")
for j := 0; j < i; j++ {
fmt.Fprintf(f, ", T%d", j)
}
fmt.Fprintf(f, ")(R, error)](f)\n")
fmt.Fprintln(f, "}")
// generic version
fmt.Fprintf(fg, "\n// Uneitherize%d converts a function with %d parameters returning a [GRA] into a function with %d parameters returning a tuple.\n// The first parameter is considered to be the context [C].\n", i, i, i)
fmt.Fprintf(fg, "func Uneitherize%d[GRA ~func(C) GIOA, F ~func(C", i)
for j := 0; j < i; j++ {
fmt.Fprintf(fg, ", T%d", j)
}
fmt.Fprintf(fg, ") (R, error), GIOA ~func() E.Either[error, R]")
for j := 0; j < i; j++ {
fmt.Fprintf(fg, ", T%d", j)
}
fmt.Fprintf(fg, ", C, R any](f func(")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(fg, ", ")
}
fmt.Fprintf(fg, "T%d", j)
}
fmt.Fprintf(fg, ") GRA) F {\n")
fmt.Fprintf(fg, " return func(c C")
for j := 0; j < i; j++ {
fmt.Fprintf(fg, ", t%d T%d", j, j)
}
fmt.Fprintf(fg, ") (R, error) {\n")
fmt.Fprintf(fg, " return E.UnwrapError(f(")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(fg, ", ")
}
fmt.Fprintf(fg, "t%d", j)
}
fmt.Fprintf(fg, ")(c)())\n")
fmt.Fprintf(fg, " }\n")
fmt.Fprintf(fg, "}\n")
}
func generateReaderIOEitherHelpers(filename string, count int) error {
dir, err := os.Getwd()
if err != nil {
@@ -261,16 +197,12 @@ import (
generateReaderIOEitherFrom(f, fg, 0)
// eitherize
generateReaderIOEitherEitherize(f, fg, 0)
// uneitherize
generateReaderIOEitherUneitherize(f, fg, 0)
for i := 1; i <= count; i++ {
// from
generateReaderIOEitherFrom(f, fg, i)
// eitherize
generateReaderIOEitherEitherize(f, fg, i)
// uneitherize
generateReaderIOEitherUneitherize(f, fg, i)
}
return nil

View File

@@ -1,15 +0,0 @@
package templates
import (
"text/template"
E "github.com/IBM/fp-go/either"
)
var (
templateFunctions = template.FuncMap{}
)
func Parse(name, tmpl string) E.Either[error, *template.Template] {
return E.TryCatchError(template.New(name).Funcs(templateFunctions).Parse(tmpl))
}

View File

@@ -405,6 +405,8 @@ func generateTupleHelpers(filename string, count int) error {
fmt.Fprintf(f, `
import (
"fmt"
"encoding/json"
M "github.com/IBM/fp-go/monoid"
O "github.com/IBM/fp-go/ord"
)
@@ -455,7 +457,7 @@ func generateTupleMarshal(f *os.File, i int) {
fmt.Fprintf(f, "func (t ")
writeTupleType(f, "T", i)
fmt.Fprintf(f, ") MarshalJSON() ([]byte, error) {\n")
fmt.Fprintf(f, " return tupleMarshalJSON(")
fmt.Fprintf(f, " return json.Marshal([]any{")
// function prototypes
for j := 1; j <= i; j++ {
if j > 1 {
@@ -463,7 +465,7 @@ func generateTupleMarshal(f *os.File, i int) {
}
fmt.Fprintf(f, "t.F%d", j)
}
fmt.Fprintf(f, ")\n")
fmt.Fprintf(f, "})\n")
fmt.Fprintf(f, "}\n")
}
@@ -473,12 +475,19 @@ func generateTupleUnmarshal(f *os.File, i int) {
fmt.Fprintf(f, "func (t *")
writeTupleType(f, "T", i)
fmt.Fprintf(f, ") UnmarshalJSON(data []byte) error {\n")
fmt.Fprintf(f, " return tupleUnmarshalJSON(data")
// function prototypes
fmt.Fprintf(f, " var tmp []json.RawMessage\n")
fmt.Fprintf(f, " if err := json.Unmarshal(data, &tmp); err != nil {return err}\n")
fmt.Fprintf(f, " l := len(tmp)\n")
// unmarshal fields
for j := 1; j <= i; j++ {
fmt.Fprintf(f, ", &t.F%d", j)
fmt.Fprintf(f, " if l > %d {\n", j-1)
fmt.Fprintf(f, " if err := json.Unmarshal(tmp[%d], &t.F%d); err != nil {return err}\n", j-1, j)
}
fmt.Fprintf(f, ")\n")
fmt.Fprintf(f, " ")
for j := 1; j <= i; j++ {
fmt.Fprintf(f, "}")
}
fmt.Fprintf(f, "\n return nil\n")
fmt.Fprintf(f, "}\n")
}
@@ -561,13 +570,30 @@ func generateTupleString(f *os.File, i int) {
writeTupleType(f, "T", i)
fmt.Fprintf(f, ") String() string {\n")
// convert to string
fmt.Fprint(f, " return tupleString(")
fmt.Fprintf(f, " return fmt.Sprintf(\"Tuple%d[", i)
for j := 1; j <= i; j++ {
if j > 1 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "%s", "%T")
}
fmt.Fprintf(f, "](")
for j := 1; j <= i; j++ {
if j > 1 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "%s", "%v")
}
fmt.Fprintf(f, ")\", ")
for j := 1; j <= i; j++ {
if j > 1 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "t.F%d", j)
}
for j := 1; j <= i; j++ {
fmt.Fprintf(f, ", t.F%d", j)
}
fmt.Fprintf(f, ")\n")
fmt.Fprintf(f, "}\n")
}

View File

@@ -37,7 +37,7 @@ func Of[E, A any](m M.Monoid[E]) func(A) Const[E, A] {
return F.Constant1[A](Make[E, A](m.Empty()))
}
func MonadMap[E, A, B any](fa Const[E, A], _ func(A) B) Const[E, B] {
func MonadMap[E, A, B any](fa Const[E, A], f func(A) B) Const[E, B] {
return Make[E, B](fa.value)
}

View File

@@ -1,68 +0,0 @@
// 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 readereither
import (
"context"
G "github.com/IBM/fp-go/readereither/generic"
)
// Bind creates an empty context of type [S] to be used with the [Bind] operation
func Do[S any](
empty S,
) ReaderEither[S] {
return G.Do[ReaderEither[S], context.Context, error, S](empty)
}
// Bind attaches the result of a computation to a context [S1] to produce a context [S2]
func Bind[S1, S2, T any](
setter func(T) func(S1) S2,
f func(S1) ReaderEither[T],
) func(ReaderEither[S1]) ReaderEither[S2] {
return G.Bind[ReaderEither[S1], ReaderEither[S2], ReaderEither[T], context.Context, error, S1, S2, T](setter, f)
}
// Let attaches the result of a computation to a context [S1] to produce a context [S2]
func Let[S1, S2, T any](
setter func(T) func(S1) S2,
f func(S1) T,
) func(ReaderEither[S1]) ReaderEither[S2] {
return G.Let[ReaderEither[S1], ReaderEither[S2], context.Context, error, S1, S2, T](setter, f)
}
// LetTo attaches the a value to a context [S1] to produce a context [S2]
func LetTo[S1, S2, T any](
setter func(T) func(S1) S2,
b T,
) func(ReaderEither[S1]) ReaderEither[S2] {
return G.LetTo[ReaderEither[S1], ReaderEither[S2], context.Context, error, S1, S2, T](setter, b)
}
// BindTo initializes a new state [S1] from a value [T]
func BindTo[S1, T any](
setter func(T) S1,
) func(ReaderEither[T]) ReaderEither[S1] {
return G.BindTo[ReaderEither[S1], ReaderEither[T], context.Context, error, S1, T](setter)
}
// ApS attaches a value to a context [S1] to produce a context [S2] by considering the context and the value concurrently
func ApS[S1, S2, T any](
setter func(T) func(S1) S2,
fa ReaderEither[T],
) func(ReaderEither[S1]) ReaderEither[S2] {
return G.ApS[ReaderEither[S1], ReaderEither[S2], ReaderEither[T], context.Context, error, S1, S2, T](setter, fa)
}

View File

@@ -1,58 +0,0 @@
// 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 readereither
import (
"context"
"testing"
E "github.com/IBM/fp-go/either"
F "github.com/IBM/fp-go/function"
"github.com/IBM/fp-go/internal/utils"
"github.com/stretchr/testify/assert"
)
func getLastName(s utils.Initial) ReaderEither[string] {
return Of("Doe")
}
func getGivenName(s utils.WithLastName) ReaderEither[string] {
return Of("John")
}
func TestBind(t *testing.T) {
res := F.Pipe3(
Do(utils.Empty),
Bind(utils.SetLastName, getLastName),
Bind(utils.SetGivenName, getGivenName),
Map(utils.GetFullName),
)
assert.Equal(t, res(context.Background()), E.Of[error]("John Doe"))
}
func TestApS(t *testing.T) {
res := F.Pipe3(
Do(utils.Empty),
ApS(utils.SetLastName, Of("Doe")),
ApS(utils.SetGivenName, Of("John")),
Map(utils.GetFullName),
)
assert.Equal(t, res(context.Background()), E.Of[error]("John Doe"))
}

View File

@@ -1,67 +0,0 @@
// 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 readerioeither
import (
G "github.com/IBM/fp-go/context/readerioeither/generic"
IOE "github.com/IBM/fp-go/ioeither"
)
// Bind creates an empty context of type [S] to be used with the [Bind] operation
func Do[S any](
empty S,
) ReaderIOEither[S] {
return G.Do[ReaderIOEither[S], IOE.IOEither[error, S], S](empty)
}
// Bind attaches the result of a computation to a context [S1] to produce a context [S2]
func Bind[S1, S2, T any](
setter func(T) func(S1) S2,
f func(S1) ReaderIOEither[T],
) func(ReaderIOEither[S1]) ReaderIOEither[S2] {
return G.Bind[ReaderIOEither[S1], ReaderIOEither[S2], ReaderIOEither[T], IOE.IOEither[error, S1], IOE.IOEither[error, S2], IOE.IOEither[error, T], S1, S2, T](setter, f)
}
// Let attaches the result of a computation to a context [S1] to produce a context [S2]
func Let[S1, S2, T any](
setter func(T) func(S1) S2,
f func(S1) T,
) func(ReaderIOEither[S1]) ReaderIOEither[S2] {
return G.Let[ReaderIOEither[S1], ReaderIOEither[S2], IOE.IOEither[error, S1], IOE.IOEither[error, S2], S1, S2, T](setter, f)
}
// LetTo attaches the a value to a context [S1] to produce a context [S2]
func LetTo[S1, S2, T any](
setter func(T) func(S1) S2,
b T,
) func(ReaderIOEither[S1]) ReaderIOEither[S2] {
return G.LetTo[ReaderIOEither[S1], ReaderIOEither[S2], IOE.IOEither[error, S1], IOE.IOEither[error, S2], S1, S2, T](setter, b)
}
// BindTo initializes a new state [S1] from a value [T]
func BindTo[S1, T any](
setter func(T) S1,
) func(ReaderIOEither[T]) ReaderIOEither[S1] {
return G.BindTo[ReaderIOEither[S1], ReaderIOEither[T], IOE.IOEither[error, S1], IOE.IOEither[error, T], S1, T](setter)
}
// ApS attaches a value to a context [S1] to produce a context [S2] by considering the context and the value concurrently
func ApS[S1, S2, T any](
setter func(T) func(S1) S2,
fa ReaderIOEither[T],
) func(ReaderIOEither[S1]) ReaderIOEither[S2] {
return G.ApS[ReaderIOEither[func(T) S2], ReaderIOEither[S1], ReaderIOEither[S2], ReaderIOEither[T], IOE.IOEither[error, func(T) S2], IOE.IOEither[error, S1], IOE.IOEither[error, S2], IOE.IOEither[error, T], S1, S2, T](setter, fa)
}

View File

@@ -1,58 +0,0 @@
// 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 readerioeither
import (
"context"
"testing"
E "github.com/IBM/fp-go/either"
F "github.com/IBM/fp-go/function"
"github.com/IBM/fp-go/internal/utils"
"github.com/stretchr/testify/assert"
)
func getLastName(s utils.Initial) ReaderIOEither[string] {
return Of("Doe")
}
func getGivenName(s utils.WithLastName) ReaderIOEither[string] {
return Of("John")
}
func TestBind(t *testing.T) {
res := F.Pipe3(
Do(utils.Empty),
Bind(utils.SetLastName, getLastName),
Bind(utils.SetGivenName, getGivenName),
Map(utils.GetFullName),
)
assert.Equal(t, res(context.Background())(), E.Of[error]("John Doe"))
}
func TestApS(t *testing.T) {
res := F.Pipe3(
Do(utils.Empty),
ApS(utils.SetLastName, Of("Doe")),
ApS(utils.SetGivenName, Of("John")),
Map(utils.GetFullName),
)
assert.Equal(t, res(context.Background())(), E.Of[error]("John Doe"))
}

View File

@@ -47,5 +47,5 @@ func ExampleReadFile() {
fmt.Println(result())
// Output:
// Right[string](Carsten)
// Right[<nil>, string](Carsten)
}

View File

@@ -26,7 +26,7 @@ import (
func onWriteAll[W io.Writer](data []byte) func(w W) RIOE.ReaderIOEither[[]byte] {
return func(w W) RIOE.ReaderIOEither[[]byte] {
return F.Pipe1(
RIOE.TryCatch(func(_ context.Context) func() ([]byte, error) {
RIOE.TryCatch(func(ctx context.Context) func() ([]byte, error) {
return func() ([]byte, error) {
_, err := w.Write(data)
return data, err

View File

@@ -2,7 +2,7 @@ package readerioeither
// Code generated by go generate; DO NOT EDIT.
// This file was generated by robots at
// 2024-05-24 22:24:01.4250895 +0200 CEST m=+0.014515801
// 2023-10-23 08:30:39.012572 +0200 CEST m=+0.008846101
import (
"context"
@@ -17,24 +17,12 @@ func Eitherize0[F ~func(context.Context) (R, error), R any](f F) func() ReaderIO
return G.Eitherize0[ReaderIOEither[R]](f)
}
// Uneitherize0 converts a function with 1 parameters returning a [ReaderIOEither[R]] into a function with 0 parameters returning a tuple.
// The first parameter is considered to be the [context.Context].
func Uneitherize0[F ~func() ReaderIOEither[R], R any](f F) func(context.Context) (R, error) {
return G.Uneitherize0[ReaderIOEither[R], func(context.Context) (R, error)](f)
}
// Eitherize1 converts a function with 1 parameters returning a tuple into a function with 1 parameters returning a [ReaderIOEither[R]]
// The inverse function is [Uneitherize1]
func Eitherize1[F ~func(context.Context, T0) (R, error), T0, R any](f F) func(T0) ReaderIOEither[R] {
return G.Eitherize1[ReaderIOEither[R]](f)
}
// Uneitherize1 converts a function with 2 parameters returning a [ReaderIOEither[R]] into a function with 1 parameters returning a tuple.
// The first parameter is considered to be the [context.Context].
func Uneitherize1[F ~func(T0) ReaderIOEither[R], T0, R any](f F) func(context.Context, T0) (R, error) {
return G.Uneitherize1[ReaderIOEither[R], func(context.Context, T0) (R, error)](f)
}
// SequenceT1 converts 1 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple1].
func SequenceT1[T1 any](t1 ReaderIOEither[T1]) ReaderIOEither[T.Tuple1[T1]] {
return G.SequenceT1[ReaderIOEither[T.Tuple1[T1]]](t1)
@@ -86,12 +74,6 @@ func Eitherize2[F ~func(context.Context, T0, T1) (R, error), T0, T1, R any](f F)
return G.Eitherize2[ReaderIOEither[R]](f)
}
// Uneitherize2 converts a function with 3 parameters returning a [ReaderIOEither[R]] into a function with 2 parameters returning a tuple.
// The first parameter is considered to be the [context.Context].
func Uneitherize2[F ~func(T0, T1) ReaderIOEither[R], T0, T1, R any](f F) func(context.Context, T0, T1) (R, error) {
return G.Uneitherize2[ReaderIOEither[R], func(context.Context, T0, T1) (R, error)](f)
}
// SequenceT2 converts 2 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple2].
func SequenceT2[T1, T2 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2]) ReaderIOEither[T.Tuple2[T1, T2]] {
return G.SequenceT2[ReaderIOEither[T.Tuple2[T1, T2]]](t1, t2)
@@ -143,12 +125,6 @@ func Eitherize3[F ~func(context.Context, T0, T1, T2) (R, error), T0, T1, T2, R a
return G.Eitherize3[ReaderIOEither[R]](f)
}
// Uneitherize3 converts a function with 4 parameters returning a [ReaderIOEither[R]] into a function with 3 parameters returning a tuple.
// The first parameter is considered to be the [context.Context].
func Uneitherize3[F ~func(T0, T1, T2) ReaderIOEither[R], T0, T1, T2, R any](f F) func(context.Context, T0, T1, T2) (R, error) {
return G.Uneitherize3[ReaderIOEither[R], func(context.Context, T0, T1, T2) (R, error)](f)
}
// SequenceT3 converts 3 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple3].
func SequenceT3[T1, T2, T3 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2], t3 ReaderIOEither[T3]) ReaderIOEither[T.Tuple3[T1, T2, T3]] {
return G.SequenceT3[ReaderIOEither[T.Tuple3[T1, T2, T3]]](t1, t2, t3)
@@ -200,12 +176,6 @@ func Eitherize4[F ~func(context.Context, T0, T1, T2, T3) (R, error), T0, T1, T2,
return G.Eitherize4[ReaderIOEither[R]](f)
}
// Uneitherize4 converts a function with 5 parameters returning a [ReaderIOEither[R]] into a function with 4 parameters returning a tuple.
// The first parameter is considered to be the [context.Context].
func Uneitherize4[F ~func(T0, T1, T2, T3) ReaderIOEither[R], T0, T1, T2, T3, R any](f F) func(context.Context, T0, T1, T2, T3) (R, error) {
return G.Uneitherize4[ReaderIOEither[R], func(context.Context, T0, T1, T2, T3) (R, error)](f)
}
// SequenceT4 converts 4 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple4].
func SequenceT4[T1, T2, T3, T4 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2], t3 ReaderIOEither[T3], t4 ReaderIOEither[T4]) ReaderIOEither[T.Tuple4[T1, T2, T3, T4]] {
return G.SequenceT4[ReaderIOEither[T.Tuple4[T1, T2, T3, T4]]](t1, t2, t3, t4)
@@ -257,12 +227,6 @@ func Eitherize5[F ~func(context.Context, T0, T1, T2, T3, T4) (R, error), T0, T1,
return G.Eitherize5[ReaderIOEither[R]](f)
}
// Uneitherize5 converts a function with 6 parameters returning a [ReaderIOEither[R]] into a function with 5 parameters returning a tuple.
// The first parameter is considered to be the [context.Context].
func Uneitherize5[F ~func(T0, T1, T2, T3, T4) ReaderIOEither[R], T0, T1, T2, T3, T4, R any](f F) func(context.Context, T0, T1, T2, T3, T4) (R, error) {
return G.Uneitherize5[ReaderIOEither[R], func(context.Context, T0, T1, T2, T3, T4) (R, error)](f)
}
// SequenceT5 converts 5 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple5].
func SequenceT5[T1, T2, T3, T4, T5 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2], t3 ReaderIOEither[T3], t4 ReaderIOEither[T4], t5 ReaderIOEither[T5]) ReaderIOEither[T.Tuple5[T1, T2, T3, T4, T5]] {
return G.SequenceT5[ReaderIOEither[T.Tuple5[T1, T2, T3, T4, T5]]](t1, t2, t3, t4, t5)
@@ -314,12 +278,6 @@ func Eitherize6[F ~func(context.Context, T0, T1, T2, T3, T4, T5) (R, error), T0,
return G.Eitherize6[ReaderIOEither[R]](f)
}
// Uneitherize6 converts a function with 7 parameters returning a [ReaderIOEither[R]] into a function with 6 parameters returning a tuple.
// The first parameter is considered to be the [context.Context].
func Uneitherize6[F ~func(T0, T1, T2, T3, T4, T5) ReaderIOEither[R], T0, T1, T2, T3, T4, T5, R any](f F) func(context.Context, T0, T1, T2, T3, T4, T5) (R, error) {
return G.Uneitherize6[ReaderIOEither[R], func(context.Context, T0, T1, T2, T3, T4, T5) (R, error)](f)
}
// SequenceT6 converts 6 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple6].
func SequenceT6[T1, T2, T3, T4, T5, T6 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2], t3 ReaderIOEither[T3], t4 ReaderIOEither[T4], t5 ReaderIOEither[T5], t6 ReaderIOEither[T6]) ReaderIOEither[T.Tuple6[T1, T2, T3, T4, T5, T6]] {
return G.SequenceT6[ReaderIOEither[T.Tuple6[T1, T2, T3, T4, T5, T6]]](t1, t2, t3, t4, t5, t6)
@@ -371,12 +329,6 @@ func Eitherize7[F ~func(context.Context, T0, T1, T2, T3, T4, T5, T6) (R, error),
return G.Eitherize7[ReaderIOEither[R]](f)
}
// Uneitherize7 converts a function with 8 parameters returning a [ReaderIOEither[R]] into a function with 7 parameters returning a tuple.
// The first parameter is considered to be the [context.Context].
func Uneitherize7[F ~func(T0, T1, T2, T3, T4, T5, T6) ReaderIOEither[R], T0, T1, T2, T3, T4, T5, T6, R any](f F) func(context.Context, T0, T1, T2, T3, T4, T5, T6) (R, error) {
return G.Uneitherize7[ReaderIOEither[R], func(context.Context, T0, T1, T2, T3, T4, T5, T6) (R, error)](f)
}
// SequenceT7 converts 7 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple7].
func SequenceT7[T1, T2, T3, T4, T5, T6, T7 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2], t3 ReaderIOEither[T3], t4 ReaderIOEither[T4], t5 ReaderIOEither[T5], t6 ReaderIOEither[T6], t7 ReaderIOEither[T7]) ReaderIOEither[T.Tuple7[T1, T2, T3, T4, T5, T6, T7]] {
return G.SequenceT7[ReaderIOEither[T.Tuple7[T1, T2, T3, T4, T5, T6, T7]]](t1, t2, t3, t4, t5, t6, t7)
@@ -428,12 +380,6 @@ func Eitherize8[F ~func(context.Context, T0, T1, T2, T3, T4, T5, T6, T7) (R, err
return G.Eitherize8[ReaderIOEither[R]](f)
}
// Uneitherize8 converts a function with 9 parameters returning a [ReaderIOEither[R]] into a function with 8 parameters returning a tuple.
// The first parameter is considered to be the [context.Context].
func Uneitherize8[F ~func(T0, T1, T2, T3, T4, T5, T6, T7) ReaderIOEither[R], T0, T1, T2, T3, T4, T5, T6, T7, R any](f F) func(context.Context, T0, T1, T2, T3, T4, T5, T6, T7) (R, error) {
return G.Uneitherize8[ReaderIOEither[R], func(context.Context, T0, T1, T2, T3, T4, T5, T6, T7) (R, error)](f)
}
// SequenceT8 converts 8 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple8].
func SequenceT8[T1, T2, T3, T4, T5, T6, T7, T8 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2], t3 ReaderIOEither[T3], t4 ReaderIOEither[T4], t5 ReaderIOEither[T5], t6 ReaderIOEither[T6], t7 ReaderIOEither[T7], t8 ReaderIOEither[T8]) ReaderIOEither[T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]] {
return G.SequenceT8[ReaderIOEither[T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]](t1, t2, t3, t4, t5, t6, t7, t8)
@@ -485,12 +431,6 @@ func Eitherize9[F ~func(context.Context, T0, T1, T2, T3, T4, T5, T6, T7, T8) (R,
return G.Eitherize9[ReaderIOEither[R]](f)
}
// Uneitherize9 converts a function with 10 parameters returning a [ReaderIOEither[R]] into a function with 9 parameters returning a tuple.
// The first parameter is considered to be the [context.Context].
func Uneitherize9[F ~func(T0, T1, T2, T3, T4, T5, T6, T7, T8) ReaderIOEither[R], T0, T1, T2, T3, T4, T5, T6, T7, T8, R any](f F) func(context.Context, T0, T1, T2, T3, T4, T5, T6, T7, T8) (R, error) {
return G.Uneitherize9[ReaderIOEither[R], func(context.Context, T0, T1, T2, T3, T4, T5, T6, T7, T8) (R, error)](f)
}
// SequenceT9 converts 9 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple9].
func SequenceT9[T1, T2, T3, T4, T5, T6, T7, T8, T9 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2], t3 ReaderIOEither[T3], t4 ReaderIOEither[T4], t5 ReaderIOEither[T5], t6 ReaderIOEither[T6], t7 ReaderIOEither[T7], t8 ReaderIOEither[T8], t9 ReaderIOEither[T9]) ReaderIOEither[T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]] {
return G.SequenceT9[ReaderIOEither[T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]](t1, t2, t3, t4, t5, t6, t7, t8, t9)
@@ -542,12 +482,6 @@ func Eitherize10[F ~func(context.Context, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9
return G.Eitherize10[ReaderIOEither[R]](f)
}
// Uneitherize10 converts a function with 11 parameters returning a [ReaderIOEither[R]] into a function with 10 parameters returning a tuple.
// The first parameter is considered to be the [context.Context].
func Uneitherize10[F ~func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9) ReaderIOEither[R], T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, R any](f F) func(context.Context, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9) (R, error) {
return G.Uneitherize10[ReaderIOEither[R], func(context.Context, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9) (R, error)](f)
}
// SequenceT10 converts 10 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple10].
func SequenceT10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2], t3 ReaderIOEither[T3], t4 ReaderIOEither[T4], t5 ReaderIOEither[T5], t6 ReaderIOEither[T6], t7 ReaderIOEither[T7], t8 ReaderIOEither[T8], t9 ReaderIOEither[T9], t10 ReaderIOEither[T10]) ReaderIOEither[T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]] {
return G.SequenceT10[ReaderIOEither[T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]](t1, t2, t3, t4, t5, t6, t7, t8, t9, t10)

View File

@@ -1,92 +0,0 @@
// 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 (
"context"
ET "github.com/IBM/fp-go/either"
A "github.com/IBM/fp-go/internal/apply"
C "github.com/IBM/fp-go/internal/chain"
F "github.com/IBM/fp-go/internal/functor"
)
// Bind creates an empty context of type [S] to be used with the [Bind] operation
func Do[GRS ~func(context.Context) GS, GS ~func() ET.Either[error, S], S any](
empty S,
) GRS {
return Of[GRS, GS, S](empty)
}
// Bind attaches the result of a computation to a context [S1] to produce a context [S2]
func Bind[GRS1 ~func(context.Context) GS1, GRS2 ~func(context.Context) GS2, GRT ~func(context.Context) GT, GS1 ~func() ET.Either[error, S1], GS2 ~func() ET.Either[error, S2], GT ~func() ET.Either[error, T], S1, S2, T any](
setter func(T) func(S1) S2,
f func(S1) GRT,
) func(GRS1) GRS2 {
return C.Bind(
Chain[GRS1, GRS2, GS1, GS2, S1, S2],
Map[GRT, GRS2, GT, GS2, T, S2],
setter,
f,
)
}
// Let attaches the result of a computation to a context [S1] to produce a context [S2]
func Let[GRS1 ~func(context.Context) GS1, GRS2 ~func(context.Context) GS2, GS1 ~func() ET.Either[error, S1], GS2 ~func() ET.Either[error, S2], S1, S2, T any](
key func(T) func(S1) S2,
f func(S1) T,
) func(GRS1) GRS2 {
return F.Let(
Map[GRS1, GRS2, GS1, GS2, S1, S2],
key,
f,
)
}
// LetTo attaches the a value to a context [S1] to produce a context [S2]
func LetTo[GRS1 ~func(context.Context) GS1, GRS2 ~func(context.Context) GS2, GS1 ~func() ET.Either[error, S1], GS2 ~func() ET.Either[error, S2], S1, S2, B any](
key func(B) func(S1) S2,
b B,
) func(GRS1) GRS2 {
return F.LetTo(
Map[GRS1, GRS2, GS1, GS2, S1, S2],
key,
b,
)
}
// BindTo initializes a new state [S1] from a value [T]
func BindTo[GRS1 ~func(context.Context) GS1, GRT ~func(context.Context) GT, GS1 ~func() ET.Either[error, S1], GT ~func() ET.Either[error, T], S1, T any](
setter func(T) S1,
) func(GRT) GRS1 {
return C.BindTo(
Map[GRT, GRS1, GT, GS1, T, S1],
setter,
)
}
// ApS attaches a value to a context [S1] to produce a context [S2] by considering the context and the value concurrently
func ApS[GRTS1 ~func(context.Context) GTS1, GRS1 ~func(context.Context) GS1, GRS2 ~func(context.Context) GS2, GRT ~func(context.Context) GT, GTS1 ~func() ET.Either[error, func(T) S2], GS1 ~func() ET.Either[error, S1], GS2 ~func() ET.Either[error, S2], GT ~func() ET.Either[error, T], S1, S2, T any](
setter func(T) func(S1) S2,
fa GRT,
) func(GRS1) GRS2 {
return A.ApS(
Ap[GRS2, GRTS1, GRT, GS2, GTS1, GT],
Map[GRS1, GRTS1, GS1, GTS1, S1, func(T) S2],
setter,
fa,
)
}

View File

@@ -2,7 +2,7 @@ package generic
// Code generated by go generate; DO NOT EDIT.
// This file was generated by robots at
// 2024-05-24 22:24:01.4250895 +0200 CEST m=+0.014515801
// 2023-10-23 08:30:39.012572 +0200 CEST m=+0.008846101
import (
"context"
@@ -19,28 +19,12 @@ func Eitherize0[GRA ~func(context.Context) GIOA, F ~func(context.Context) (R, er
return RE.Eitherize0[GRA](f)
}
// Uneitherize0 converts a function with 0 parameters returning a [GRA] into a function with 0 parameters returning a tuple.
// The first parameter is considered to be the [context.Context].
func Uneitherize0[GRA ~func(context.Context) GIOA, F ~func(context.Context) (R, error), GIOA ~func() E.Either[error, R], R any](f func() GRA) F {
return func(c context.Context) (R, error) {
return E.UnwrapError(f()(c)())
}
}
// Eitherize1 converts a function with 1 parameters returning a tuple into a function with 1 parameters returning a [GRA]
// The inverse function is [Uneitherize1]
func Eitherize1[GRA ~func(context.Context) GIOA, F ~func(context.Context, T0) (R, error), GIOA ~func() E.Either[error, R], T0, R any](f F) func(T0) GRA {
return RE.Eitherize1[GRA](f)
}
// Uneitherize1 converts a function with 1 parameters returning a [GRA] into a function with 1 parameters returning a tuple.
// The first parameter is considered to be the [context.Context].
func Uneitherize1[GRA ~func(context.Context) GIOA, F ~func(context.Context, T0) (R, error), GIOA ~func() E.Either[error, R], T0, R any](f func(T0) GRA) F {
return func(c context.Context, t0 T0) (R, error) {
return E.UnwrapError(f(t0)(c)())
}
}
// SequenceT1 converts 1 readers into a reader of a [T.Tuple1].
func SequenceT1[
GR_TUPLE1 ~func(context.Context) GIO_TUPLE1,
@@ -185,14 +169,6 @@ func Eitherize2[GRA ~func(context.Context) GIOA, F ~func(context.Context, T0, T1
return RE.Eitherize2[GRA](f)
}
// Uneitherize2 converts a function with 2 parameters returning a [GRA] into a function with 2 parameters returning a tuple.
// The first parameter is considered to be the [context.Context].
func Uneitherize2[GRA ~func(context.Context) GIOA, F ~func(context.Context, T0, T1) (R, error), GIOA ~func() E.Either[error, R], T0, T1, R any](f func(T0, T1) GRA) F {
return func(c context.Context, t0 T0, t1 T1) (R, error) {
return E.UnwrapError(f(t0, t1)(c)())
}
}
// SequenceT2 converts 2 readers into a reader of a [T.Tuple2].
func SequenceT2[
GR_TUPLE2 ~func(context.Context) GIO_TUPLE2,
@@ -388,14 +364,6 @@ func Eitherize3[GRA ~func(context.Context) GIOA, F ~func(context.Context, T0, T1
return RE.Eitherize3[GRA](f)
}
// Uneitherize3 converts a function with 3 parameters returning a [GRA] into a function with 3 parameters returning a tuple.
// The first parameter is considered to be the [context.Context].
func Uneitherize3[GRA ~func(context.Context) GIOA, F ~func(context.Context, T0, T1, T2) (R, error), GIOA ~func() E.Either[error, R], T0, T1, T2, R any](f func(T0, T1, T2) GRA) F {
return func(c context.Context, t0 T0, t1 T1, t2 T2) (R, error) {
return E.UnwrapError(f(t0, t1, t2)(c)())
}
}
// SequenceT3 converts 3 readers into a reader of a [T.Tuple3].
func SequenceT3[
GR_TUPLE3 ~func(context.Context) GIO_TUPLE3,
@@ -642,14 +610,6 @@ func Eitherize4[GRA ~func(context.Context) GIOA, F ~func(context.Context, T0, T1
return RE.Eitherize4[GRA](f)
}
// Uneitherize4 converts a function with 4 parameters returning a [GRA] into a function with 4 parameters returning a tuple.
// The first parameter is considered to be the [context.Context].
func Uneitherize4[GRA ~func(context.Context) GIOA, F ~func(context.Context, T0, T1, T2, T3) (R, error), GIOA ~func() E.Either[error, R], T0, T1, T2, T3, R any](f func(T0, T1, T2, T3) GRA) F {
return func(c context.Context, t0 T0, t1 T1, t2 T2, t3 T3) (R, error) {
return E.UnwrapError(f(t0, t1, t2, t3)(c)())
}
}
// SequenceT4 converts 4 readers into a reader of a [T.Tuple4].
func SequenceT4[
GR_TUPLE4 ~func(context.Context) GIO_TUPLE4,
@@ -947,14 +907,6 @@ func Eitherize5[GRA ~func(context.Context) GIOA, F ~func(context.Context, T0, T1
return RE.Eitherize5[GRA](f)
}
// Uneitherize5 converts a function with 5 parameters returning a [GRA] into a function with 5 parameters returning a tuple.
// The first parameter is considered to be the [context.Context].
func Uneitherize5[GRA ~func(context.Context) GIOA, F ~func(context.Context, T0, T1, T2, T3, T4) (R, error), GIOA ~func() E.Either[error, R], T0, T1, T2, T3, T4, R any](f func(T0, T1, T2, T3, T4) GRA) F {
return func(c context.Context, t0 T0, t1 T1, t2 T2, t3 T3, t4 T4) (R, error) {
return E.UnwrapError(f(t0, t1, t2, t3, t4)(c)())
}
}
// SequenceT5 converts 5 readers into a reader of a [T.Tuple5].
func SequenceT5[
GR_TUPLE5 ~func(context.Context) GIO_TUPLE5,
@@ -1303,14 +1255,6 @@ func Eitherize6[GRA ~func(context.Context) GIOA, F ~func(context.Context, T0, T1
return RE.Eitherize6[GRA](f)
}
// Uneitherize6 converts a function with 6 parameters returning a [GRA] into a function with 6 parameters returning a tuple.
// The first parameter is considered to be the [context.Context].
func Uneitherize6[GRA ~func(context.Context) GIOA, F ~func(context.Context, T0, T1, T2, T3, T4, T5) (R, error), GIOA ~func() E.Either[error, R], T0, T1, T2, T3, T4, T5, R any](f func(T0, T1, T2, T3, T4, T5) GRA) F {
return func(c context.Context, t0 T0, t1 T1, t2 T2, t3 T3, t4 T4, t5 T5) (R, error) {
return E.UnwrapError(f(t0, t1, t2, t3, t4, t5)(c)())
}
}
// SequenceT6 converts 6 readers into a reader of a [T.Tuple6].
func SequenceT6[
GR_TUPLE6 ~func(context.Context) GIO_TUPLE6,
@@ -1710,14 +1654,6 @@ func Eitherize7[GRA ~func(context.Context) GIOA, F ~func(context.Context, T0, T1
return RE.Eitherize7[GRA](f)
}
// Uneitherize7 converts a function with 7 parameters returning a [GRA] into a function with 7 parameters returning a tuple.
// The first parameter is considered to be the [context.Context].
func Uneitherize7[GRA ~func(context.Context) GIOA, F ~func(context.Context, T0, T1, T2, T3, T4, T5, T6) (R, error), GIOA ~func() E.Either[error, R], T0, T1, T2, T3, T4, T5, T6, R any](f func(T0, T1, T2, T3, T4, T5, T6) GRA) F {
return func(c context.Context, t0 T0, t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6) (R, error) {
return E.UnwrapError(f(t0, t1, t2, t3, t4, t5, t6)(c)())
}
}
// SequenceT7 converts 7 readers into a reader of a [T.Tuple7].
func SequenceT7[
GR_TUPLE7 ~func(context.Context) GIO_TUPLE7,
@@ -2168,14 +2104,6 @@ func Eitherize8[GRA ~func(context.Context) GIOA, F ~func(context.Context, T0, T1
return RE.Eitherize8[GRA](f)
}
// Uneitherize8 converts a function with 8 parameters returning a [GRA] into a function with 8 parameters returning a tuple.
// The first parameter is considered to be the [context.Context].
func Uneitherize8[GRA ~func(context.Context) GIOA, F ~func(context.Context, T0, T1, T2, T3, T4, T5, T6, T7) (R, error), GIOA ~func() E.Either[error, R], T0, T1, T2, T3, T4, T5, T6, T7, R any](f func(T0, T1, T2, T3, T4, T5, T6, T7) GRA) F {
return func(c context.Context, t0 T0, t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6, t7 T7) (R, error) {
return E.UnwrapError(f(t0, t1, t2, t3, t4, t5, t6, t7)(c)())
}
}
// SequenceT8 converts 8 readers into a reader of a [T.Tuple8].
func SequenceT8[
GR_TUPLE8 ~func(context.Context) GIO_TUPLE8,
@@ -2677,14 +2605,6 @@ func Eitherize9[GRA ~func(context.Context) GIOA, F ~func(context.Context, T0, T1
return RE.Eitherize9[GRA](f)
}
// Uneitherize9 converts a function with 9 parameters returning a [GRA] into a function with 9 parameters returning a tuple.
// The first parameter is considered to be the [context.Context].
func Uneitherize9[GRA ~func(context.Context) GIOA, F ~func(context.Context, T0, T1, T2, T3, T4, T5, T6, T7, T8) (R, error), GIOA ~func() E.Either[error, R], T0, T1, T2, T3, T4, T5, T6, T7, T8, R any](f func(T0, T1, T2, T3, T4, T5, T6, T7, T8) GRA) F {
return func(c context.Context, t0 T0, t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6, t7 T7, t8 T8) (R, error) {
return E.UnwrapError(f(t0, t1, t2, t3, t4, t5, t6, t7, t8)(c)())
}
}
// SequenceT9 converts 9 readers into a reader of a [T.Tuple9].
func SequenceT9[
GR_TUPLE9 ~func(context.Context) GIO_TUPLE9,
@@ -3237,14 +3157,6 @@ func Eitherize10[GRA ~func(context.Context) GIOA, F ~func(context.Context, T0, T
return RE.Eitherize10[GRA](f)
}
// Uneitherize10 converts a function with 10 parameters returning a [GRA] into a function with 10 parameters returning a tuple.
// The first parameter is considered to be the [context.Context].
func Uneitherize10[GRA ~func(context.Context) GIOA, F ~func(context.Context, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9) (R, error), GIOA ~func() E.Either[error, R], T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, R any](f func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9) GRA) F {
return func(c context.Context, t0 T0, t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6, t7 T7, t8 T8, t9 T9) (R, error) {
return E.UnwrapError(f(t0, t1, t2, t3, t4, t5, t6, t7, t8, t9)(c)())
}
}
// SequenceT10 converts 10 readers into a reader of a [T.Tuple10].
func SequenceT10[
GR_TUPLE10 ~func(context.Context) GIO_TUPLE10,

View File

@@ -182,7 +182,10 @@ func withCancelCauseFunc[
ma,
IOE.Swap[GIOA, func() E.Either[A, error]],
IOE.ChainFirstIOK[func() E.Either[A, error], func() any](func(err error) func() any {
return IO.FromImpure[func() any](func() { cancel(err) })
return IO.MakeIO[func() any](func() any {
cancel(err)
return nil
})
}),
IOE.Swap[func() E.Either[A, error], GIOA],
)

View File

@@ -1,72 +0,0 @@
// 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
}),
)
}

View File

@@ -1,59 +0,0 @@
// 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())()))
}

View File

@@ -26,7 +26,7 @@ import (
IOE "github.com/IBM/fp-go/ioeither"
IOEF "github.com/IBM/fp-go/ioeither/file"
J "github.com/IBM/fp-go/json"
P "github.com/IBM/fp-go/pair"
T "github.com/IBM/fp-go/tuple"
)
type (
@@ -79,7 +79,7 @@ func ReadFullResponse(client Client) func(Requester) RIOE.ReaderIOEither[H.FullR
IOE.Of[error, io.ReadCloser],
IOEF.ReadAll[io.ReadCloser],
),
IOE.Map[error](F.Bind1st(P.MakePair[*http.Response, []byte], resp)),
IOE.Map[error](F.Bind1st(T.MakeTuple2[*http.Response, []byte], resp)),
)
}),
)
@@ -103,27 +103,16 @@ func ReadText(client Client) func(Requester) RIOE.ReaderIOEither[string] {
}
// ReadJson sends a request, reads the response and parses the response as JSON
//
// Deprecated: use [ReadJSON] instead
func ReadJson[A any](client Client) func(Requester) RIOE.ReaderIOEither[A] {
return ReadJSON[A](client)
}
func readJSON(client Client) func(Requester) RIOE.ReaderIOEither[[]byte] {
return F.Flow3(
ReadFullResponse(client),
RIOE.ChainFirstEitherK(F.Flow2(
H.Response,
H.ValidateJSONResponse,
H.ValidateJsonResponse,
)),
RIOE.ChainEitherK(F.Flow2(
H.Body,
J.Unmarshal[A],
)),
RIOE.Map(H.Body),
)
}
// ReadJSON sends a request, reads the response and parses the response as JSON
func ReadJSON[A any](client Client) func(Requester) RIOE.ReaderIOEither[A] {
return F.Flow2(
readJSON(client),
RIOE.ChainEitherK(J.Unmarshal[A]),
)
}

View File

@@ -31,7 +31,7 @@ import (
)
type PostItem struct {
UserID uint `json:"userId"`
UserId uint `json:"userId"`
Id uint `json:"id"`
Title string `json:"title"`
Body string `json:"body"`
@@ -84,7 +84,7 @@ func TestSendSingleRequest(t *testing.T) {
req1 := MakeGetRequest("https://jsonplaceholder.typicode.com/posts/1")
readItem := ReadJSON[PostItem](client)
readItem := ReadJson[PostItem](client)
resp1 := readItem(req1)
@@ -112,7 +112,7 @@ func TestSendSingleRequestWithHeaderUnsafe(t *testing.T) {
R.Map(setHeaderUnsafe("Content-Type", "text/html")),
)
readItem := ReadJSON[PostItem](client)
readItem := ReadJson[PostItem](client)
resp1 := F.Pipe2(
req1,
@@ -140,7 +140,7 @@ func TestSendSingleRequestWithHeaderSafe(t *testing.T) {
WithHeader("Content-Type", "text/html").
Build()
readItem := ReadJSON[PostItem](client)
readItem := ReadJson[PostItem](client)
response := F.Pipe2(
request,

View File

@@ -25,7 +25,6 @@ import (
IOE "github.com/IBM/fp-go/ioeither"
L "github.com/IBM/fp-go/lazy"
O "github.com/IBM/fp-go/option"
RIO "github.com/IBM/fp-go/readerio"
)
func FromEither[A any](e ET.Either[error, A]) ReaderIOEither[A] {
@@ -193,7 +192,8 @@ func Memoize[A any](rdr ReaderIOEither[A]) ReaderIOEither[A] {
}
// Flatten converts a nested [ReaderIOEither] into a [ReaderIOEither]
func Flatten[A any](rdr ReaderIOEither[ReaderIOEither[A]]) ReaderIOEither[A] {
func Flatten[
A any](rdr ReaderIOEither[ReaderIOEither[A]]) ReaderIOEither[A] {
return G.Flatten[ReaderIOEither[ReaderIOEither[A]]](rdr)
}
@@ -204,15 +204,3 @@ func MonadFlap[B, A any](fab ReaderIOEither[func(A) B], a A) ReaderIOEither[B] {
func Flap[B, A any](a A) func(ReaderIOEither[func(A) B]) ReaderIOEither[B] {
return G.Flap[ReaderIOEither[func(A) B], ReaderIOEither[B]](a)
}
func Fold[A, B any](onLeft func(error) ReaderIOEither[B], onRight func(A) ReaderIOEither[B]) func(ReaderIOEither[A]) ReaderIOEither[B] {
return G.Fold[ReaderIOEither[B], ReaderIOEither[A]](onLeft, onRight)
}
func GetOrElse[A any](onLeft func(error) RIO.ReaderIO[context.Context, A]) func(ReaderIOEither[A]) RIO.ReaderIO[context.Context, A] {
return G.GetOrElse[RIO.ReaderIO[context.Context, A], ReaderIOEither[A]](onLeft)
}
func OrLeft[A any](onLeft func(error) RIO.ReaderIO[context.Context, error]) func(ReaderIOEither[A]) ReaderIOEither[A] {
return G.OrLeft[ReaderIOEither[A]](onLeft)
}

View File

@@ -1,3 +1,2 @@
@echo off
go tool cover -html=build/cover.out -o build/cover.html
cov-report -ex ".*/cli/.*.go|.*/gen.go|.*/binds.go" build\cover.out
go tool cover -html=build/cover.out -o build/cover.html

View File

@@ -1,38 +0,0 @@
// 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))),
)

View File

@@ -1,43 +0,0 @@
// 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 15 --filename gen.go

View File

@@ -7,6 +7,7 @@
//
// 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.
@@ -114,9 +115,6 @@ func itemProviderFactory(fcts []ProviderFactory) ProviderFactory {
}
// 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 {
type Result = IOE.IOEither[error, any]
@@ -127,7 +125,7 @@ func MakeInjector(providers []Provider) InjectableFactory {
var resolved sync.Map
// provide a mapping for all providers
factoryByID := assembleProviders(providers)
factoryById := assembleProviders(providers)
// the actual factory, we need lazy initialization
var injFct InjectableFactory
@@ -149,7 +147,7 @@ func MakeInjector(providers []Provider) InjectableFactory {
T.Map2(F.Flow3(
Dependency.Id,
R.Lookup[ProviderFactory, string],
I.Ap[O.Option[ProviderFactory]](factoryByID),
I.Ap[O.Option[ProviderFactory]](factoryById),
), handleMissingProvider),
T.Tupled2(O.MonadGetOrElse[ProviderFactory]),
IG.Ap[ProviderFactory](injFct),

View File

@@ -31,29 +31,25 @@ import (
R "github.com/IBM/fp-go/record"
)
type (
// 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 InjectableFactory = func(Dependency) IOE.IOEither[error, any]
type ProviderFactory = func(InjectableFactory) IOE.IOEither[error, any]
paramIndex = map[int]int
paramValue = map[int]any
handler = func(paramIndex) func([]IOE.IOEither[error, any]) IOE.IOEither[error, paramValue]
mapping = map[int]paramIndex
type paramIndex = map[int]int
type paramValue = map[int]any
type handler = func(paramIndex) func([]IOE.IOEither[error, any]) IOE.IOEither[error, paramValue]
Provider interface {
fmt.Stringer
// Provides returns the [Dependency] implemented by this provider
Provides() Dependency
// Factory returns s function that can create an instance of the dependency based on an [InjectableFactory]
Factory() ProviderFactory
}
type Provider interface {
fmt.Stringer
// Provides returns the [Dependency] implemented by this provider
Provides() Dependency
// Factory returns s function that can create an instance of the dependency based on an [InjectableFactory]
Factory() ProviderFactory
}
provider struct {
provides Dependency
factory ProviderFactory
}
)
type provider struct {
provides Dependency
factory ProviderFactory
}
func (p *provider) Provides() Dependency {
return p.provides
@@ -76,16 +72,11 @@ func mapFromToken(idx int, token Dependency) map[int]paramIndex {
}
var (
// Empty is the empty array of providers
Empty = A.Empty[Provider]()
mergeTokenMaps = R.UnionMonoid[int](R.UnionLastSemigroup[int, int]())
foldDeps = A.FoldMapWithIndex[Dependency](mergeTokenMaps)(mapFromToken)
mergeMaps = R.UnionLastMonoid[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{
Identity: func(mp paramIndex) func([]IOE.IOEither[error, any]) IOE.IOEither[error, paramValue] {
return func(res []IOE.IOEither[error, any]) IOE.IOEither[error, paramValue] {
@@ -136,13 +127,15 @@ var (
}
)
type Mapping = map[int]paramIndex
func getAt[T any](ar []T) func(idx int) T {
return func(idx int) T {
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(
mp,
R.Collect(func(idx int, p paramIndex) func([]IOE.IOEither[error, any]) IOE.IOEither[error, paramValue] {
@@ -174,7 +167,7 @@ func MakeProviderFactory(
fct func(param ...any) IOE.IOEither[error, any]) ProviderFactory {
return F.Flow3(
mapDeps(deps),
F.Curry2(A.MonadMap[Dependency, IOE.IOEither[error, any]])(deps),
handleMapping(foldDeps(deps)),
IOE.Chain(F.Unvariadic0(fct)),
)

1888
di/gen.go

File diff suppressed because it is too large Load Diff

View File

@@ -7,6 +7,7 @@
//
// 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.

View File

@@ -12,7 +12,6 @@
// 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 (
@@ -22,6 +21,7 @@ import (
"github.com/IBM/fp-go/errors"
F "github.com/IBM/fp-go/function"
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] {
@@ -32,25 +32,49 @@ func lookupAt[T any](idx int, token Dependency[T]) func(params []any) E.Either[e
)
}
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 func() IOE.IOEither[error, R]) func(params ...any) IOE.IOEither[error, any] {
return func(params ...any) IOE.IOEither[error, any] {
return F.Pipe1(
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(_ ...any) IOE.IOEither[error, any] {
return F.Pipe1(
f,
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 MakeProviderFactory0[R any](
fct IOE.IOEither[error, R],
fct func() IOE.IOEither[error, R],
) DIE.ProviderFactory {
return DIE.MakeProviderFactory(
A.Empty[DIE.Dependency](),
@@ -58,14 +82,14 @@ func MakeProviderFactory0[R any](
)
}
// MakeTokenWithDefault0 creates a unique [InjectionToken] for a specific type with an attached default [DIE.Provider]
func MakeTokenWithDefault0[R any](name string, fct IOE.IOEither[error, R]) InjectionToken[R] {
// MakeTokenWithDefault0 create a unique `InjectionToken` for a specific type with an attached default provider
func MakeTokenWithDefault0[R any](name string, fct func() IOE.IOEither[error, R]) InjectionToken[R] {
return MakeTokenWithDefault[R](name, MakeProviderFactory0(fct))
}
func MakeProvider0[R any](
token InjectionToken[R],
fct IOE.IOEither[error, R],
fct func() IOE.IOEither[error, R],
) DIE.Provider {
return DIE.MakeProvider(
token,
@@ -73,7 +97,70 @@ 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),
)
}
// ConstProvider simple implementation for a provider with a constant value
func ConstProvider[R any](token InjectionToken[R], value R) DIE.Provider {
return MakeProvider0[R](token, IOE.Of[error](value))
return MakeProvider0[R](token, F.Constant(IOE.Of[error](value)))
}

View File

@@ -12,7 +12,6 @@
// 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 (
@@ -39,10 +38,12 @@ func TestSimpleProvider(t *testing.T) {
var staticCount int
staticValue := func(value string) IOE.IOEither[error, string] {
return func() E.Either[error, string] {
staticCount++
return E.Of[error](fmt.Sprintf("Static based on [%s], at [%s]", value, time.Now()))
staticValue := func(value string) func() IOE.IOEither[error, string] {
return func() IOE.IOEither[error, string] {
return func() E.Either[error, string] {
staticCount++
return E.Of[error](fmt.Sprintf("Static based on [%s], at [%s]", value, time.Now()))
}
}
}
@@ -81,10 +82,12 @@ func TestOptionalProvider(t *testing.T) {
var staticCount int
staticValue := func(value string) IOE.IOEither[error, string] {
return func() E.Either[error, string] {
staticCount++
return E.Of[error](fmt.Sprintf("Static based on [%s], at [%s]", value, time.Now()))
staticValue := func(value string) func() IOE.IOEither[error, string] {
return func() IOE.IOEither[error, string] {
return func() E.Either[error, string] {
staticCount++
return E.Of[error](fmt.Sprintf("Static based on [%s], at [%s]", value, time.Now()))
}
}
}
@@ -179,10 +182,12 @@ func TestEagerAndLazyProvider(t *testing.T) {
var staticCount int
staticValue := func(value string) IOE.IOEither[error, string] {
return func() E.Either[error, string] {
staticCount++
return E.Of[error](fmt.Sprintf("Static based on [%s], at [%s]", value, time.Now()))
staticValue := func(value string) func() IOE.IOEither[error, string] {
return func() IOE.IOEither[error, string] {
return func() E.Either[error, string] {
staticCount++
return E.Of[error](fmt.Sprintf("Static based on [%s], at [%s]", value, time.Now()))
}
}
}
@@ -302,7 +307,7 @@ func TestTokenWithDefaultProvider(t *testing.T) {
// token without a default
injToken1 := MakeToken[string]("Token1")
// token with a default
injToken2 := MakeTokenWithDefault0("Token2", IOE.Of[error]("Carsten"))
injToken2 := MakeTokenWithDefault0("Token2", F.Constant(IOE.Of[error]("Carsten")))
// dependency
injToken3 := MakeToken[string]("Token3")
@@ -325,7 +330,7 @@ func TestTokenWithDefaultProvider(t *testing.T) {
func TestTokenWithDefaultProviderAndOverride(t *testing.T) {
// token with a default
injToken2 := MakeTokenWithDefault0("Token2", IOE.Of[error]("Carsten"))
injToken2 := MakeTokenWithDefault0("Token2", F.Constant(IOE.Of[error]("Carsten")))
// dependency
injToken3 := MakeToken[string]("Token3")

View File

@@ -42,21 +42,20 @@ type InjectionToken[T any] interface {
// 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
Identity() Dependency[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]]
// 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]`
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.
// If the dependency cannot be resolved, the resolution process fails
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.
// If the dependency cannot be resolved, the resolution process continues and the dependency is represented as the none value.
IOOption() Dependency[IOO.IOOption[T]]
}
// 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.
// MultiInjectionToken uniquely identifies a dependency by giving it an Id, Type and name.
type MultiInjectionToken[T any] interface {
// Container returns the injection token used to request an array of all provided items
Container() InjectionToken[[]T]
@@ -65,38 +64,34 @@ type MultiInjectionToken[T any] interface {
}
// makeID creates a generator of unique string IDs
func makeID() IO.IO[string] {
func makeId() IO.IO[string] {
var count atomic.Int64
return IO.MakeIO(func() string {
return strconv.FormatInt(count.Add(1), 16)
})
}
// genID is the common generator of unique string IDs
var genID = makeID()
// genId is the common generator of unique string IDs
var genId = makeId()
type tokenBase struct {
type token[T any] struct {
name string
id string
flag int
toType func(val any) E.Either[error, T]
providerFactory O.Option[DIE.ProviderFactory]
}
type token[T any] struct {
base *tokenBase
toType func(val any) E.Either[error, T]
}
func (t *token[T]) Id() string {
return t.base.id
return t.id
}
func (t *token[T]) Flag() int {
return t.base.flag
return t.flag
}
func (t *token[T]) String() string {
return t.base.name
return t.name
}
func (t *token[T]) Unerase(val any) E.Either[error, T] {
@@ -104,14 +99,11 @@ func (t *token[T]) Unerase(val any) E.Either[error, T] {
}
func (t *token[T]) ProviderFactory() O.Option[DIE.ProviderFactory] {
return t.base.providerFactory
}
func makeTokenBase(name string, id string, typ int, providerFactory O.Option[DIE.ProviderFactory]) *tokenBase {
return &tokenBase{name, id, typ, providerFactory}
return t.providerFactory
}
func makeToken[T any](name string, id string, typ int, unerase func(val any) E.Either[error, T], providerFactory O.Option[DIE.ProviderFactory]) Dependency[T] {
return &token[T]{makeTokenBase(name, id, typ, providerFactory), unerase}
return &token[T]{name, id, typ, unerase, providerFactory}
}
type injectionToken[T any] struct {
@@ -143,7 +135,7 @@ func (i *injectionToken[T]) IOOption() Dependency[IOO.IOOption[T]] {
}
func (i *injectionToken[T]) ProviderFactory() O.Option[DIE.ProviderFactory] {
return i.base.providerFactory
return i.providerFactory
}
func (m *multiInjectionToken[T]) Container() InjectionToken[[]T] {
@@ -154,31 +146,31 @@ func (m *multiInjectionToken[T]) Item() InjectionToken[T] {
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] {
id := genID()
id := genId()
toIdentity := toType[T]()
return &injectionToken[T]{
token[T]{makeTokenBase(name, id, DIE.Identity, providerFactory), toIdentity},
token[T]{name, id, DIE.Identity, toIdentity, providerFactory},
makeToken[O.Option[T]](fmt.Sprintf("Option[%s]", name), id, DIE.Option, toOptionType(toIdentity), providerFactory),
makeToken[IOE.IOEither[error, T]](fmt.Sprintf("IOEither[%s]", name), id, DIE.IOEither, toIOEitherType(toIdentity), providerFactory),
makeToken[IOO.IOOption[T]](fmt.Sprintf("IOOption[%s]", name), id, DIE.IOOption, toIOOptionType(toIdentity), providerFactory),
}
}
// 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] {
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] {
return makeInjectionToken[T](name, O.Of(providerFactory))
}
// MakeMultiToken creates a [MultiInjectionToken]
func MakeMultiToken[T any](name string) MultiInjectionToken[T] {
id := genID()
id := genId()
toItem := toType[T]()
toContainer := toArrayType(toItem)
containerName := fmt.Sprintf("Container[%s]", name)
@@ -187,14 +179,14 @@ func MakeMultiToken[T any](name string) MultiInjectionToken[T] {
providerFactory := O.None[DIE.ProviderFactory]()
// container
container := &injectionToken[[]T]{
token[[]T]{makeTokenBase(containerName, id, DIE.Multi|DIE.Identity, providerFactory), toContainer},
token[[]T]{containerName, id, DIE.Multi | DIE.Identity, toContainer, providerFactory},
makeToken[O.Option[[]T]](fmt.Sprintf("Option[%s]", containerName), id, DIE.Multi|DIE.Option, toOptionType(toContainer), providerFactory),
makeToken[IOE.IOEither[error, []T]](fmt.Sprintf("IOEither[%s]", containerName), id, DIE.Multi|DIE.IOEither, toIOEitherType(toContainer), providerFactory),
makeToken[IOO.IOOption[[]T]](fmt.Sprintf("IOOption[%s]", containerName), id, DIE.Multi|DIE.IOOption, toIOOptionType(toContainer), providerFactory),
}
// item
item := &injectionToken[T]{
token[T]{makeTokenBase(itemName, id, DIE.Item|DIE.Identity, providerFactory), toItem},
token[T]{itemName, id, DIE.Item | DIE.Identity, toItem, providerFactory},
makeToken[O.Option[T]](fmt.Sprintf("Option[%s]", itemName), id, DIE.Item|DIE.Option, toOptionType(toItem), providerFactory),
makeToken[IOE.IOEither[error, T]](fmt.Sprintf("IOEither[%s]", itemName), id, DIE.Item|DIE.IOEither, toIOEitherType(toItem), providerFactory),
makeToken[IOO.IOOption[T]](fmt.Sprintf("IOOption[%s]", itemName), id, DIE.Item|DIE.IOOption, toIOOptionType(toItem), providerFactory),

View File

@@ -12,7 +12,6 @@
// 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 (
@@ -25,13 +24,6 @@ import (
O "github.com/IBM/fp-go/option"
)
var (
toOptionAny = toType[O.Option[any]]()
toIOEitherAny = toType[IOE.IOEither[error, any]]()
toIOOptionAny = toType[IOO.IOOption[any]]()
toArrayAny = toType[[]any]()
)
// asDependency converts a generic type to a [DIE.Dependency]
func asDependency[T DIE.Dependency](t T) DIE.Dependency {
return t
@@ -45,7 +37,7 @@ func toType[T any]() func(t any) E.Either[error, T] {
// toOptionType converts an any to an Option[any] and then to an Option[T]
func toOptionType[T any](item func(any) E.Either[error, T]) func(t any) E.Either[error, O.Option[T]] {
return F.Flow2(
toOptionAny,
toType[O.Option[any]](),
E.Chain(O.Fold(
F.Nullary2(O.None[T], E.Of[error, O.Option[T]]),
F.Flow2(
@@ -59,7 +51,7 @@ func toOptionType[T any](item func(any) E.Either[error, T]) func(t any) E.Either
// toIOEitherType converts an any to an IOEither[error, any] and then to an IOEither[error, T]
func toIOEitherType[T any](item func(any) E.Either[error, T]) func(t any) E.Either[error, IOE.IOEither[error, T]] {
return F.Flow2(
toIOEitherAny,
toType[IOE.IOEither[error, any]](),
E.Map[error](IOE.ChainEitherK(item)),
)
}
@@ -67,7 +59,7 @@ func toIOEitherType[T any](item func(any) E.Either[error, T]) func(t any) E.Eith
// toIOOptionType converts an any to an IOOption[any] and then to an IOOption[T]
func toIOOptionType[T any](item func(any) E.Either[error, T]) func(t any) E.Either[error, IOO.IOOption[T]] {
return F.Flow2(
toIOOptionAny,
toType[IOO.IOOption[any]](),
E.Map[error](IOO.ChainOptionK(F.Flow2(
item,
E.ToOption[error, T],
@@ -78,7 +70,7 @@ func toIOOptionType[T any](item func(any) E.Either[error, T]) func(t any) E.Eith
// toArrayType converts an any to a []T
func toArrayType[T any](item func(any) E.Either[error, T]) func(t any) E.Either[error, []T] {
return F.Flow2(
toArrayAny,
toType[[]any](),
E.Chain(E.TraverseArray(item)),
)
}

View File

@@ -12,7 +12,6 @@
// 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 (

View File

@@ -1,10 +1,8 @@
package either
import (
"fmt"
"testing"
TST "github.com/IBM/fp-go/internal/testing"
"github.com/stretchr/testify/assert"
)
@@ -18,33 +16,3 @@ func TestCompactArray(t *testing.T) {
res := CompactArray(ar)
assert.Equal(t, 2, len(res))
}
func TestSequenceArray(t *testing.T) {
s := TST.SequenceArrayTest(
FromStrictEquals[error, bool](),
Pointed[error, string](),
Pointed[error, bool](),
Functor[error, []string, bool](),
SequenceArray[error, string],
)
for i := 0; i < 10; i++ {
t.Run(fmt.Sprintf("TestSequenceArray %d", i), s(i))
}
}
func TestSequenceArrayError(t *testing.T) {
s := TST.SequenceArrayErrorTest(
FromStrictEquals[error, bool](),
Left[string, error],
Left[bool, error],
Pointed[error, string](),
Pointed[error, bool](),
Functor[error, []string, bool](),
SequenceArray[error, string],
)
// run across four bits
s(4)(t)
}

View File

@@ -1,89 +0,0 @@
// 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 either
import (
A "github.com/IBM/fp-go/internal/apply"
C "github.com/IBM/fp-go/internal/chain"
F "github.com/IBM/fp-go/internal/functor"
)
// Bind creates an empty context of type [S] to be used with the [Bind] operation
func Do[E, S any](
empty S,
) Either[E, S] {
return Of[E](empty)
}
// Bind attaches the result of a computation to a context [S1] to produce a context [S2]
func Bind[E, S1, S2, T any](
setter func(T) func(S1) S2,
f func(S1) Either[E, T],
) func(Either[E, S1]) Either[E, S2] {
return C.Bind(
Chain[E, S1, S2],
Map[E, T, S2],
setter,
f,
)
}
// Let attaches the result of a computation to a context [S1] to produce a context [S2]
func Let[E, S1, S2, T any](
key func(T) func(S1) S2,
f func(S1) T,
) func(Either[E, S1]) Either[E, S2] {
return F.Let(
Map[E, S1, S2],
key,
f,
)
}
// LetTo attaches the a value to a context [S1] to produce a context [S2]
func LetTo[E, S1, S2, T any](
key func(T) func(S1) S2,
b T,
) func(Either[E, S1]) Either[E, S2] {
return F.LetTo(
Map[E, S1, S2],
key,
b,
)
}
// BindTo initializes a new state [S1] from a value [T]
func BindTo[E, S1, T any](
setter func(T) S1,
) func(Either[E, T]) Either[E, S1] {
return C.BindTo(
Map[E, T, S1],
setter,
)
}
// ApS attaches a value to a context [S1] to produce a context [S2] by considering the context and the value concurrently
func ApS[E, S1, S2, T any](
setter func(T) func(S1) S2,
fa Either[E, T],
) func(Either[E, S1]) Either[E, S2] {
return A.ApS(
Ap[S2, E, T],
Map[E, S1, func(T) S2],
setter,
fa,
)
}

View File

@@ -1,56 +0,0 @@
// 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 either
import (
"testing"
F "github.com/IBM/fp-go/function"
"github.com/IBM/fp-go/internal/utils"
"github.com/stretchr/testify/assert"
)
func getLastName(s utils.Initial) Either[error, string] {
return Of[error]("Doe")
}
func getGivenName(s utils.WithLastName) Either[error, string] {
return Of[error]("John")
}
func TestBind(t *testing.T) {
res := F.Pipe3(
Do[error](utils.Empty),
Bind(utils.SetLastName, getLastName),
Bind(utils.SetGivenName, getGivenName),
Map[error](utils.GetFullName),
)
assert.Equal(t, res, Of[error]("John Doe"))
}
func TestApS(t *testing.T) {
res := F.Pipe3(
Do[error](utils.Empty),
ApS(utils.SetLastName, Of[error]("Doe")),
ApS(utils.SetGivenName, Of[error]("John")),
Map[error](utils.GetFullName),
)
assert.Equal(t, res, Of[error]("John Doe"))
}

View File

@@ -20,45 +20,30 @@ import (
)
type (
either struct {
isLeft bool
value any
}
// Either defines a data structure that logically holds either an E or an A. The flag discriminates the cases
Either[E, A any] either
Either[E, A any] struct {
isLeft bool
left E
right A
}
)
// String prints some debug info for the object
//
//go:noinline
func eitherString(s *either) string {
if s.isLeft {
return fmt.Sprintf("Left[%T](%v)", s.value, s.value)
}
return fmt.Sprintf("Right[%T](%v)", s.value, s.value)
}
// Format prints some debug info for the object
//
//go:noinline
func eitherFormat(e *either, f fmt.State, c rune) {
switch c {
case 's':
fmt.Fprint(f, eitherString(e))
default:
fmt.Fprint(f, eitherString(e))
}
}
// String prints some debug info for the object
func (s Either[E, A]) String() string {
return eitherString((*either)(&s))
if s.isLeft {
return fmt.Sprintf("Left[%T, %T](%v)", s.left, s.right, s.left)
}
return fmt.Sprintf("Right[%T, %T](%v)", s.left, s.right, s.right)
}
// Format prints some debug info for the object
func (s Either[E, A]) Format(f fmt.State, c rune) {
eitherFormat((*either)(&s), f, c)
switch c {
case 's':
fmt.Fprint(f, s.String())
default:
fmt.Fprint(f, s.String())
}
}
// IsLeft tests if the [Either] is a left value. Rather use [Fold] if you need to access the values. Inverse is [IsRight].
@@ -73,29 +58,23 @@ func IsRight[E, A any](val Either[E, A]) bool {
// Left creates a new instance of an [Either] representing the left value.
func Left[A, E any](value E) Either[E, A] {
return Either[E, A]{true, value}
return Either[E, A]{isLeft: true, left: value}
}
// Right creates a new instance of an [Either] representing the right value.
func Right[E, A any](value A) Either[E, A] {
return Either[E, A]{false, value}
return Either[E, A]{isLeft: false, right: value}
}
// MonadFold extracts the values from an [Either] by invoking the [onLeft] callback or the [onRight] callback depending on the case
func MonadFold[E, A, B any](ma Either[E, A], onLeft func(e E) B, onRight func(a A) B) B {
if ma.isLeft {
return onLeft(ma.value.(E))
return onLeft(ma.left)
}
return onRight(ma.value.(A))
return onRight(ma.right)
}
// Unwrap converts an [Either] into the idiomatic tuple
func Unwrap[E, A any](ma Either[E, A]) (A, E) {
if ma.isLeft {
var a A
return a, ma.value.(E)
} else {
var e E
return ma.value.(A), e
}
return ma.right, ma.left
}

View File

@@ -16,4 +16,4 @@
// Package option defines the [Either] datastructure and its monadic operations
package either
//go:generate go run .. either --count 15 --filename gen.go
//go:generate go run .. either --count 10 --filename gen.go

View File

@@ -22,7 +22,6 @@ package either
import (
E "github.com/IBM/fp-go/errors"
F "github.com/IBM/fp-go/function"
C "github.com/IBM/fp-go/internal/chain"
FC "github.com/IBM/fp-go/internal/functor"
L "github.com/IBM/fp-go/lazy"
O "github.com/IBM/fp-go/option"
@@ -33,7 +32,7 @@ func Of[E, A any](value A) Either[E, A] {
return F.Pipe1(value, Right[E, A])
}
func FromIO[E any, IO ~func() A, A any](f IO) Either[E, A] {
func FromIO[E, IO ~func() A, A any](f IO) Either[E, A] {
return F.Pipe1(f(), Right[E, A])
}
@@ -65,20 +64,19 @@ func MonadMapTo[E, A, B any](fa Either[E, A], b B) Either[E, B] {
}
func MapTo[E, A, B any](b B) func(Either[E, A]) Either[E, B] {
return Map[E](F.Constant1[A](b))
return F.Bind2nd(MonadMapTo[E, A, B], b)
}
func MonadMapLeft[E1, A, E2 any](fa Either[E1, A], f func(E1) E2) Either[E2, A] {
return MonadFold(fa, F.Flow2(f, Left[A, E2]), Right[E2, A])
func MonadMapLeft[E, A, B any](fa Either[E, A], f func(E) B) Either[B, A] {
return MonadFold(fa, F.Flow2(f, Left[A, B]), Right[B, A])
}
func Map[E, A, B any](f func(a A) B) func(fa Either[E, A]) Either[E, B] {
return Chain(F.Flow2(f, Right[E, B]))
}
// MapLeft applies a mapping function to the error channel
func MapLeft[A, E1, E2 any](f func(E1) E2) func(fa Either[E1, A]) Either[E2, A] {
return Fold(F.Flow2(f, Left[A, E2]), Right[E2, A])
func MapLeft[E, A, B any](f func(E) B) func(fa Either[E, A]) Either[B, A] {
return F.Bind2nd(MonadMapLeft[E, A, B], f)
}
func MonadChain[E, A, B any](fa Either[E, A], f func(a A) Either[E, B]) Either[E, B] {
@@ -86,15 +84,12 @@ func MonadChain[E, A, B any](fa Either[E, A], f func(a A) Either[E, B]) Either[E
}
func MonadChainFirst[E, A, B any](ma Either[E, A], f func(a A) Either[E, B]) Either[E, A] {
return C.MonadChainFirst(
MonadChain[E, A, A],
MonadMap[E, B, A],
ma,
f,
)
return MonadChain(ma, func(a A) Either[E, A] {
return MonadMap(f(a), F.Constant1[B](a))
})
}
func MonadChainTo[A, E, B any](_ Either[E, A], mb Either[E, B]) Either[E, B] {
func MonadChainTo[A, E, B any](ma Either[E, A], mb Either[E, B]) Either[E, B] {
return mb
}
@@ -110,19 +105,15 @@ func ChainOptionK[A, B, E any](onNone func() E) func(func(A) O.Option[B]) func(E
}
func ChainTo[A, E, B any](mb Either[E, B]) func(Either[E, A]) Either[E, B] {
return F.Constant1[Either[E, A]](mb)
return F.Bind2nd(MonadChainTo[A, E, B], mb)
}
func Chain[E, A, B any](f func(a A) Either[E, B]) func(Either[E, A]) Either[E, B] {
return Fold(Left[B, E], f)
return F.Bind2nd(MonadChain[E, A, B], f)
}
func ChainFirst[E, A, B any](f func(a A) Either[E, B]) func(Either[E, A]) Either[E, A] {
return C.ChainFirst(
Chain[E, A, A],
Map[E, B, A],
f,
)
return F.Bind2nd(MonadChainFirst[E, A, B], f)
}
func Flatten[E, A any](mma Either[E, Either[E, A]]) Either[E, A] {
@@ -259,7 +250,7 @@ func MonadFlap[E, B, A any](fab Either[E, func(A) B], a A) Either[E, B] {
}
func Flap[E, B, A any](a A) func(Either[E, func(A) B]) Either[E, B] {
return FC.Flap(Map[E, func(A) B, B], a)
return F.Bind2nd(MonadFlap[E, B, A], a)
}
func MonadAlt[E, A any](fa Either[E, A], that L.Lazy[Either[E, A]]) Either[E, A] {

View File

@@ -17,17 +17,21 @@ package either
import (
"errors"
"fmt"
"testing"
F "github.com/IBM/fp-go/function"
"github.com/IBM/fp-go/internal/utils"
IO "github.com/IBM/fp-go/io"
O "github.com/IBM/fp-go/option"
S "github.com/IBM/fp-go/string"
"github.com/stretchr/testify/assert"
)
func TestDefault(t *testing.T) {
var e Either[error, string]
assert.Equal(t, Of[error](""), e)
}
func TestIsLeft(t *testing.T) {
err := errors.New("Some error")
withError := Left[string](err)
@@ -72,6 +76,7 @@ func TestReduce(t *testing.T) {
assert.Equal(t, "foo", F.Pipe1(Left[string, string]("bar"), Reduce[string](s.Concat, "foo")))
}
func TestAp(t *testing.T) {
f := S.Size
@@ -110,20 +115,3 @@ func TestFromOption(t *testing.T) {
assert.Equal(t, Left[int]("none"), FromOption[int](F.Constant("none"))(O.None[int]()))
assert.Equal(t, Right[string](1), FromOption[int](F.Constant("none"))(O.Some(1)))
}
func TestStringer(t *testing.T) {
e := Of[error]("foo")
exp := "Right[string](foo)"
assert.Equal(t, exp, e.String())
var s fmt.Stringer = e
assert.Equal(t, exp, s.String())
}
func TestFromIO(t *testing.T) {
f := IO.Of("abc")
e := FromIO[error](f)
assert.Equal(t, Right[error]("abc"), e)
}

View File

@@ -34,7 +34,7 @@ func Eq[E, A any](e EQ.Eq[E], a EQ.Eq[A]) EQ.Eq[Either[E, A]] {
return EQ.FromEquals(F.Uncurry2(fld))
}
// FromStrictEquals constructs an [EQ.Eq] from the canonical comparison function
// FromStrictEquals constructs an `Eq` from the canonical comparison function
func FromStrictEquals[E, A comparable]() EQ.Eq[Either[E, A]] {
return Eq(EQ.FromStrictEquals[E](), EQ.FromStrictEquals[A]())
}

View File

@@ -48,11 +48,11 @@ func ExampleEither_creation() {
fmt.Println(rightFromPred)
// Output:
// Left[*errors.errorString](some error)
// Right[string](value)
// Left[*errors.errorString](value was nil)
// Left[*errors.errorString, string](some error)
// Right[<nil>, string](value)
// Left[*errors.errorString, *string](value was nil)
// true
// Left[*errors.errorString](3 is an odd number)
// Right[int](4)
// Left[*errors.errorString, int](3 is an odd number)
// Right[<nil>, int](4)
}

View File

@@ -53,8 +53,8 @@ func ExampleEither_extraction() {
fmt.Println(doubleFromRightBis)
// Output:
// Left[*errors.errorString](Division by Zero!)
// Right[int](10)
// Left[*errors.errorString, int](Division by Zero!)
// Right[<nil>, int](10)
// 0
// 10
// 0

View File

@@ -1,31 +0,0 @@
// Copyright (c) 2024 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 either
import (
"github.com/IBM/fp-go/internal/functor"
)
type eitherFunctor[E, A, B any] struct{}
func (o *eitherFunctor[E, A, B]) Map(f func(A) B) func(Either[E, A]) Either[E, B] {
return Map[E, A, B](f)
}
// Functor implements the functoric operations for [Either]
func Functor[E, A, B any]() functor.Functor[A, B, Either[E, A], Either[E, B]] {
return &eitherFunctor[E, A, B]{}
}

View File

@@ -1,6 +1,6 @@
// Code generated by go generate; DO NOT EDIT.
// This file was generated by robots at
// 2024-02-29 16:18:50.8721435 +0100 CET m=+0.070394501
// 2023-10-23 08:30:40.410373 +0200 CEST m=+0.010337601
package either
@@ -679,518 +679,3 @@ func TraverseTuple10[F1 ~func(A1) Either[E, T1], F2 ~func(A2) Either[E, T2], F3
)
}
}
// Eitherize11 converts a function with 11 parameters returning a tuple into a function with 11 parameters returning an Either
// The inverse function is [Uneitherize11]
func Eitherize11[F ~func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10) (R, error), T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, R any](f F) func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10) Either[error, R] {
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6, t7 T7, t8 T8, t9 T9, t10 T10) Either[error, R] {
return TryCatchError(f(t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10))
}
}
// Uneitherize11 converts a function with 11 parameters returning an Either into a function with 11 parameters returning a tuple
// The inverse function is [Eitherize11]
func Uneitherize11[F ~func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10) Either[error, R], T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, R any](f F) func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10) (R, error) {
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6, t7 T7, t8 T8, t9 T9, t10 T10) (R, error) {
return UnwrapError(f(t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10))
}
}
// SequenceT11 converts 11 parameters of [Either[E, T]] into a [Either[E, Tuple11]].
func SequenceT11[E, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11 any](t1 Either[E, T1], t2 Either[E, T2], t3 Either[E, T3], t4 Either[E, T4], t5 Either[E, T5], t6 Either[E, T6], t7 Either[E, T7], t8 Either[E, T8], t9 Either[E, T9], t10 Either[E, T10], t11 Either[E, T11]) Either[E, T.Tuple11[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11]] {
return A.SequenceT11(
Map[E, T1, func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) T.Tuple11[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11]],
Ap[func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) T.Tuple11[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11], E, T2],
Ap[func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) T.Tuple11[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11], E, T3],
Ap[func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) T.Tuple11[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11], E, T4],
Ap[func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) T.Tuple11[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11], E, T5],
Ap[func(T7) func(T8) func(T9) func(T10) func(T11) T.Tuple11[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11], E, T6],
Ap[func(T8) func(T9) func(T10) func(T11) T.Tuple11[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11], E, T7],
Ap[func(T9) func(T10) func(T11) T.Tuple11[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11], E, T8],
Ap[func(T10) func(T11) T.Tuple11[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11], E, T9],
Ap[func(T11) T.Tuple11[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11], E, T10],
Ap[T.Tuple11[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11], E, T11],
t1,
t2,
t3,
t4,
t5,
t6,
t7,
t8,
t9,
t10,
t11,
)
}
// SequenceTuple11 converts a [Tuple11] of [Either[E, T]] into an [Either[E, Tuple11]].
func SequenceTuple11[E, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11 any](t T.Tuple11[Either[E, T1], Either[E, T2], Either[E, T3], Either[E, T4], Either[E, T5], Either[E, T6], Either[E, T7], Either[E, T8], Either[E, T9], Either[E, T10], Either[E, T11]]) Either[E, T.Tuple11[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11]] {
return A.SequenceTuple11(
Map[E, T1, func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) T.Tuple11[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11]],
Ap[func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) T.Tuple11[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11], E, T2],
Ap[func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) T.Tuple11[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11], E, T3],
Ap[func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) T.Tuple11[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11], E, T4],
Ap[func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) T.Tuple11[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11], E, T5],
Ap[func(T7) func(T8) func(T9) func(T10) func(T11) T.Tuple11[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11], E, T6],
Ap[func(T8) func(T9) func(T10) func(T11) T.Tuple11[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11], E, T7],
Ap[func(T9) func(T10) func(T11) T.Tuple11[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11], E, T8],
Ap[func(T10) func(T11) T.Tuple11[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11], E, T9],
Ap[func(T11) T.Tuple11[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11], E, T10],
Ap[T.Tuple11[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11], E, T11],
t,
)
}
// TraverseTuple11 converts a [Tuple11] of [A] via transformation functions transforming [A] to [Either[E, A]] into a [Either[E, Tuple11]].
func TraverseTuple11[F1 ~func(A1) Either[E, T1], F2 ~func(A2) Either[E, T2], F3 ~func(A3) Either[E, T3], F4 ~func(A4) Either[E, T4], F5 ~func(A5) Either[E, T5], F6 ~func(A6) Either[E, T6], F7 ~func(A7) Either[E, T7], F8 ~func(A8) Either[E, T8], F9 ~func(A9) Either[E, T9], F10 ~func(A10) Either[E, T10], F11 ~func(A11) Either[E, T11], E, A1, T1, A2, T2, A3, T3, A4, T4, A5, T5, A6, T6, A7, T7, A8, T8, A9, T9, A10, T10, A11, T11 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10, f11 F11) func(T.Tuple11[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11]) Either[E, T.Tuple11[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11]] {
return func(t T.Tuple11[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11]) Either[E, T.Tuple11[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11]] {
return A.TraverseTuple11(
Map[E, T1, func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) T.Tuple11[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11]],
Ap[func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) T.Tuple11[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11], E, T2],
Ap[func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) T.Tuple11[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11], E, T3],
Ap[func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) T.Tuple11[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11], E, T4],
Ap[func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) T.Tuple11[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11], E, T5],
Ap[func(T7) func(T8) func(T9) func(T10) func(T11) T.Tuple11[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11], E, T6],
Ap[func(T8) func(T9) func(T10) func(T11) T.Tuple11[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11], E, T7],
Ap[func(T9) func(T10) func(T11) T.Tuple11[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11], E, T8],
Ap[func(T10) func(T11) T.Tuple11[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11], E, T9],
Ap[func(T11) T.Tuple11[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11], E, T10],
Ap[T.Tuple11[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11], E, T11],
f1,
f2,
f3,
f4,
f5,
f6,
f7,
f8,
f9,
f10,
f11,
t,
)
}
}
// Eitherize12 converts a function with 12 parameters returning a tuple into a function with 12 parameters returning an Either
// The inverse function is [Uneitherize12]
func Eitherize12[F ~func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11) (R, error), T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, R any](f F) func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11) Either[error, R] {
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) Either[error, R] {
return TryCatchError(f(t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11))
}
}
// Uneitherize12 converts a function with 12 parameters returning an Either into a function with 12 parameters returning a tuple
// The inverse function is [Eitherize12]
func Uneitherize12[F ~func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11) Either[error, R], T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, R any](f F) func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11) (R, error) {
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) (R, error) {
return UnwrapError(f(t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11))
}
}
// SequenceT12 converts 12 parameters of [Either[E, T]] into a [Either[E, Tuple12]].
func SequenceT12[E, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12 any](t1 Either[E, T1], t2 Either[E, T2], t3 Either[E, T3], t4 Either[E, T4], t5 Either[E, T5], t6 Either[E, T6], t7 Either[E, T7], t8 Either[E, T8], t9 Either[E, T9], t10 Either[E, T10], t11 Either[E, T11], t12 Either[E, T12]) Either[E, T.Tuple12[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12]] {
return A.SequenceT12(
Map[E, T1, func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) T.Tuple12[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12]],
Ap[func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) T.Tuple12[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12], E, T2],
Ap[func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) T.Tuple12[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12], E, T3],
Ap[func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) T.Tuple12[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12], E, T4],
Ap[func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) T.Tuple12[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12], E, T5],
Ap[func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) T.Tuple12[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12], E, T6],
Ap[func(T8) func(T9) func(T10) func(T11) func(T12) T.Tuple12[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12], E, T7],
Ap[func(T9) func(T10) func(T11) func(T12) T.Tuple12[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12], E, T8],
Ap[func(T10) func(T11) func(T12) T.Tuple12[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12], E, T9],
Ap[func(T11) func(T12) T.Tuple12[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12], E, T10],
Ap[func(T12) T.Tuple12[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12], E, T11],
Ap[T.Tuple12[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12], E, T12],
t1,
t2,
t3,
t4,
t5,
t6,
t7,
t8,
t9,
t10,
t11,
t12,
)
}
// SequenceTuple12 converts a [Tuple12] of [Either[E, T]] into an [Either[E, Tuple12]].
func SequenceTuple12[E, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12 any](t T.Tuple12[Either[E, T1], Either[E, T2], Either[E, T3], Either[E, T4], Either[E, T5], Either[E, T6], Either[E, T7], Either[E, T8], Either[E, T9], Either[E, T10], Either[E, T11], Either[E, T12]]) Either[E, T.Tuple12[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12]] {
return A.SequenceTuple12(
Map[E, T1, func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) T.Tuple12[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12]],
Ap[func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) T.Tuple12[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12], E, T2],
Ap[func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) T.Tuple12[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12], E, T3],
Ap[func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) T.Tuple12[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12], E, T4],
Ap[func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) T.Tuple12[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12], E, T5],
Ap[func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) T.Tuple12[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12], E, T6],
Ap[func(T8) func(T9) func(T10) func(T11) func(T12) T.Tuple12[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12], E, T7],
Ap[func(T9) func(T10) func(T11) func(T12) T.Tuple12[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12], E, T8],
Ap[func(T10) func(T11) func(T12) T.Tuple12[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12], E, T9],
Ap[func(T11) func(T12) T.Tuple12[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12], E, T10],
Ap[func(T12) T.Tuple12[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12], E, T11],
Ap[T.Tuple12[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12], E, T12],
t,
)
}
// TraverseTuple12 converts a [Tuple12] of [A] via transformation functions transforming [A] to [Either[E, A]] into a [Either[E, Tuple12]].
func TraverseTuple12[F1 ~func(A1) Either[E, T1], F2 ~func(A2) Either[E, T2], F3 ~func(A3) Either[E, T3], F4 ~func(A4) Either[E, T4], F5 ~func(A5) Either[E, T5], F6 ~func(A6) Either[E, T6], F7 ~func(A7) Either[E, T7], F8 ~func(A8) Either[E, T8], F9 ~func(A9) Either[E, T9], F10 ~func(A10) Either[E, T10], F11 ~func(A11) Either[E, T11], F12 ~func(A12) Either[E, T12], E, A1, T1, A2, T2, A3, T3, A4, T4, A5, T5, A6, T6, A7, T7, A8, T8, A9, T9, A10, T10, A11, T11, A12, T12 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10, f11 F11, f12 F12) func(T.Tuple12[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12]) Either[E, T.Tuple12[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12]] {
return func(t T.Tuple12[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12]) Either[E, T.Tuple12[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12]] {
return A.TraverseTuple12(
Map[E, T1, func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) T.Tuple12[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12]],
Ap[func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) T.Tuple12[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12], E, T2],
Ap[func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) T.Tuple12[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12], E, T3],
Ap[func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) T.Tuple12[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12], E, T4],
Ap[func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) T.Tuple12[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12], E, T5],
Ap[func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) T.Tuple12[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12], E, T6],
Ap[func(T8) func(T9) func(T10) func(T11) func(T12) T.Tuple12[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12], E, T7],
Ap[func(T9) func(T10) func(T11) func(T12) T.Tuple12[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12], E, T8],
Ap[func(T10) func(T11) func(T12) T.Tuple12[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12], E, T9],
Ap[func(T11) func(T12) T.Tuple12[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12], E, T10],
Ap[func(T12) T.Tuple12[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12], E, T11],
Ap[T.Tuple12[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12], E, T12],
f1,
f2,
f3,
f4,
f5,
f6,
f7,
f8,
f9,
f10,
f11,
f12,
t,
)
}
}
// Eitherize13 converts a function with 13 parameters returning a tuple into a function with 13 parameters returning an Either
// The inverse function is [Uneitherize13]
func Eitherize13[F ~func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12) (R, error), T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, R any](f F) func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12) Either[error, R] {
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) Either[error, R] {
return TryCatchError(f(t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12))
}
}
// Uneitherize13 converts a function with 13 parameters returning an Either into a function with 13 parameters returning a tuple
// The inverse function is [Eitherize13]
func Uneitherize13[F ~func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12) Either[error, R], T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, R any](f F) func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12) (R, error) {
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) (R, error) {
return UnwrapError(f(t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12))
}
}
// SequenceT13 converts 13 parameters of [Either[E, T]] into a [Either[E, Tuple13]].
func SequenceT13[E, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13 any](t1 Either[E, T1], t2 Either[E, T2], t3 Either[E, T3], t4 Either[E, T4], t5 Either[E, T5], t6 Either[E, T6], t7 Either[E, T7], t8 Either[E, T8], t9 Either[E, T9], t10 Either[E, T10], t11 Either[E, T11], t12 Either[E, T12], t13 Either[E, T13]) Either[E, T.Tuple13[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13]] {
return A.SequenceT13(
Map[E, 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) T.Tuple13[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13]],
Ap[func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) func(T13) T.Tuple13[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13], E, T2],
Ap[func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) func(T13) T.Tuple13[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13], E, T3],
Ap[func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) func(T13) T.Tuple13[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13], E, T4],
Ap[func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) func(T13) T.Tuple13[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13], E, T5],
Ap[func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) func(T13) T.Tuple13[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13], E, T6],
Ap[func(T8) func(T9) func(T10) func(T11) func(T12) func(T13) T.Tuple13[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13], E, T7],
Ap[func(T9) func(T10) func(T11) func(T12) func(T13) T.Tuple13[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13], E, T8],
Ap[func(T10) func(T11) func(T12) func(T13) T.Tuple13[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13], E, T9],
Ap[func(T11) func(T12) func(T13) T.Tuple13[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13], E, T10],
Ap[func(T12) func(T13) T.Tuple13[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13], E, T11],
Ap[func(T13) T.Tuple13[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13], E, T12],
Ap[T.Tuple13[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13], E, T13],
t1,
t2,
t3,
t4,
t5,
t6,
t7,
t8,
t9,
t10,
t11,
t12,
t13,
)
}
// SequenceTuple13 converts a [Tuple13] of [Either[E, T]] into an [Either[E, Tuple13]].
func SequenceTuple13[E, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13 any](t T.Tuple13[Either[E, T1], Either[E, T2], Either[E, T3], Either[E, T4], Either[E, T5], Either[E, T6], Either[E, T7], Either[E, T8], Either[E, T9], Either[E, T10], Either[E, T11], Either[E, T12], Either[E, T13]]) Either[E, T.Tuple13[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13]] {
return A.SequenceTuple13(
Map[E, 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) T.Tuple13[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13]],
Ap[func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) func(T13) T.Tuple13[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13], E, T2],
Ap[func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) func(T13) T.Tuple13[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13], E, T3],
Ap[func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) func(T13) T.Tuple13[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13], E, T4],
Ap[func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) func(T13) T.Tuple13[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13], E, T5],
Ap[func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) func(T13) T.Tuple13[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13], E, T6],
Ap[func(T8) func(T9) func(T10) func(T11) func(T12) func(T13) T.Tuple13[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13], E, T7],
Ap[func(T9) func(T10) func(T11) func(T12) func(T13) T.Tuple13[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13], E, T8],
Ap[func(T10) func(T11) func(T12) func(T13) T.Tuple13[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13], E, T9],
Ap[func(T11) func(T12) func(T13) T.Tuple13[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13], E, T10],
Ap[func(T12) func(T13) T.Tuple13[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13], E, T11],
Ap[func(T13) T.Tuple13[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13], E, T12],
Ap[T.Tuple13[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13], E, T13],
t,
)
}
// TraverseTuple13 converts a [Tuple13] of [A] via transformation functions transforming [A] to [Either[E, A]] into a [Either[E, Tuple13]].
func TraverseTuple13[F1 ~func(A1) Either[E, T1], F2 ~func(A2) Either[E, T2], F3 ~func(A3) Either[E, T3], F4 ~func(A4) Either[E, T4], F5 ~func(A5) Either[E, T5], F6 ~func(A6) Either[E, T6], F7 ~func(A7) Either[E, T7], F8 ~func(A8) Either[E, T8], F9 ~func(A9) Either[E, T9], F10 ~func(A10) Either[E, T10], F11 ~func(A11) Either[E, T11], F12 ~func(A12) Either[E, T12], F13 ~func(A13) Either[E, T13], E, A1, T1, A2, T2, A3, T3, A4, T4, A5, T5, A6, T6, A7, T7, A8, T8, A9, T9, A10, T10, A11, T11, A12, T12, A13, T13 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10, f11 F11, f12 F12, f13 F13) func(T.Tuple13[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13]) Either[E, T.Tuple13[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13]] {
return func(t T.Tuple13[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13]) Either[E, T.Tuple13[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13]] {
return A.TraverseTuple13(
Map[E, 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) T.Tuple13[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13]],
Ap[func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) func(T13) T.Tuple13[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13], E, T2],
Ap[func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) func(T13) T.Tuple13[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13], E, T3],
Ap[func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) func(T13) T.Tuple13[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13], E, T4],
Ap[func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) func(T13) T.Tuple13[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13], E, T5],
Ap[func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) func(T13) T.Tuple13[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13], E, T6],
Ap[func(T8) func(T9) func(T10) func(T11) func(T12) func(T13) T.Tuple13[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13], E, T7],
Ap[func(T9) func(T10) func(T11) func(T12) func(T13) T.Tuple13[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13], E, T8],
Ap[func(T10) func(T11) func(T12) func(T13) T.Tuple13[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13], E, T9],
Ap[func(T11) func(T12) func(T13) T.Tuple13[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13], E, T10],
Ap[func(T12) func(T13) T.Tuple13[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13], E, T11],
Ap[func(T13) T.Tuple13[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13], E, T12],
Ap[T.Tuple13[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13], E, T13],
f1,
f2,
f3,
f4,
f5,
f6,
f7,
f8,
f9,
f10,
f11,
f12,
f13,
t,
)
}
}
// Eitherize14 converts a function with 14 parameters returning a tuple into a function with 14 parameters returning an Either
// The inverse function is [Uneitherize14]
func Eitherize14[F ~func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13) (R, error), T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, R any](f F) func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13) Either[error, R] {
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) Either[error, R] {
return TryCatchError(f(t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13))
}
}
// Uneitherize14 converts a function with 14 parameters returning an Either into a function with 14 parameters returning a tuple
// The inverse function is [Eitherize14]
func Uneitherize14[F ~func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13) Either[error, R], T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, R any](f F) func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13) (R, error) {
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) (R, error) {
return UnwrapError(f(t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13))
}
}
// SequenceT14 converts 14 parameters of [Either[E, T]] into a [Either[E, Tuple14]].
func SequenceT14[E, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14 any](t1 Either[E, T1], t2 Either[E, T2], t3 Either[E, T3], t4 Either[E, T4], t5 Either[E, T5], t6 Either[E, T6], t7 Either[E, T7], t8 Either[E, T8], t9 Either[E, T9], t10 Either[E, T10], t11 Either[E, T11], t12 Either[E, T12], t13 Either[E, T13], t14 Either[E, T14]) Either[E, T.Tuple14[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14]] {
return A.SequenceT14(
Map[E, 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) T.Tuple14[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14]],
Ap[func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) func(T13) func(T14) T.Tuple14[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14], E, T2],
Ap[func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) func(T13) func(T14) T.Tuple14[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14], E, T3],
Ap[func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) func(T13) func(T14) T.Tuple14[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14], E, T4],
Ap[func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) func(T13) func(T14) T.Tuple14[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14], E, T5],
Ap[func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) func(T13) func(T14) T.Tuple14[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14], E, T6],
Ap[func(T8) func(T9) func(T10) func(T11) func(T12) func(T13) func(T14) T.Tuple14[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14], E, T7],
Ap[func(T9) func(T10) func(T11) func(T12) func(T13) func(T14) T.Tuple14[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14], E, T8],
Ap[func(T10) func(T11) func(T12) func(T13) func(T14) T.Tuple14[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14], E, T9],
Ap[func(T11) func(T12) func(T13) func(T14) T.Tuple14[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14], E, T10],
Ap[func(T12) func(T13) func(T14) T.Tuple14[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14], E, T11],
Ap[func(T13) func(T14) T.Tuple14[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14], E, T12],
Ap[func(T14) T.Tuple14[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14], E, T13],
Ap[T.Tuple14[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14], E, T14],
t1,
t2,
t3,
t4,
t5,
t6,
t7,
t8,
t9,
t10,
t11,
t12,
t13,
t14,
)
}
// SequenceTuple14 converts a [Tuple14] of [Either[E, T]] into an [Either[E, Tuple14]].
func SequenceTuple14[E, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14 any](t T.Tuple14[Either[E, T1], Either[E, T2], Either[E, T3], Either[E, T4], Either[E, T5], Either[E, T6], Either[E, T7], Either[E, T8], Either[E, T9], Either[E, T10], Either[E, T11], Either[E, T12], Either[E, T13], Either[E, T14]]) Either[E, T.Tuple14[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14]] {
return A.SequenceTuple14(
Map[E, 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) T.Tuple14[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14]],
Ap[func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) func(T13) func(T14) T.Tuple14[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14], E, T2],
Ap[func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) func(T13) func(T14) T.Tuple14[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14], E, T3],
Ap[func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) func(T13) func(T14) T.Tuple14[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14], E, T4],
Ap[func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) func(T13) func(T14) T.Tuple14[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14], E, T5],
Ap[func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) func(T13) func(T14) T.Tuple14[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14], E, T6],
Ap[func(T8) func(T9) func(T10) func(T11) func(T12) func(T13) func(T14) T.Tuple14[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14], E, T7],
Ap[func(T9) func(T10) func(T11) func(T12) func(T13) func(T14) T.Tuple14[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14], E, T8],
Ap[func(T10) func(T11) func(T12) func(T13) func(T14) T.Tuple14[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14], E, T9],
Ap[func(T11) func(T12) func(T13) func(T14) T.Tuple14[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14], E, T10],
Ap[func(T12) func(T13) func(T14) T.Tuple14[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14], E, T11],
Ap[func(T13) func(T14) T.Tuple14[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14], E, T12],
Ap[func(T14) T.Tuple14[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14], E, T13],
Ap[T.Tuple14[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14], E, T14],
t,
)
}
// TraverseTuple14 converts a [Tuple14] of [A] via transformation functions transforming [A] to [Either[E, A]] into a [Either[E, Tuple14]].
func TraverseTuple14[F1 ~func(A1) Either[E, T1], F2 ~func(A2) Either[E, T2], F3 ~func(A3) Either[E, T3], F4 ~func(A4) Either[E, T4], F5 ~func(A5) Either[E, T5], F6 ~func(A6) Either[E, T6], F7 ~func(A7) Either[E, T7], F8 ~func(A8) Either[E, T8], F9 ~func(A9) Either[E, T9], F10 ~func(A10) Either[E, T10], F11 ~func(A11) Either[E, T11], F12 ~func(A12) Either[E, T12], F13 ~func(A13) Either[E, T13], F14 ~func(A14) Either[E, T14], E, A1, T1, A2, T2, A3, T3, A4, T4, A5, T5, A6, T6, A7, T7, A8, T8, A9, T9, A10, T10, A11, T11, A12, T12, A13, T13, A14, T14 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10, f11 F11, f12 F12, f13 F13, f14 F14) func(T.Tuple14[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14]) Either[E, T.Tuple14[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14]] {
return func(t T.Tuple14[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14]) Either[E, T.Tuple14[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14]] {
return A.TraverseTuple14(
Map[E, 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) T.Tuple14[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14]],
Ap[func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) func(T13) func(T14) T.Tuple14[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14], E, T2],
Ap[func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) func(T13) func(T14) T.Tuple14[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14], E, T3],
Ap[func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) func(T13) func(T14) T.Tuple14[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14], E, T4],
Ap[func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) func(T13) func(T14) T.Tuple14[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14], E, T5],
Ap[func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) func(T13) func(T14) T.Tuple14[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14], E, T6],
Ap[func(T8) func(T9) func(T10) func(T11) func(T12) func(T13) func(T14) T.Tuple14[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14], E, T7],
Ap[func(T9) func(T10) func(T11) func(T12) func(T13) func(T14) T.Tuple14[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14], E, T8],
Ap[func(T10) func(T11) func(T12) func(T13) func(T14) T.Tuple14[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14], E, T9],
Ap[func(T11) func(T12) func(T13) func(T14) T.Tuple14[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14], E, T10],
Ap[func(T12) func(T13) func(T14) T.Tuple14[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14], E, T11],
Ap[func(T13) func(T14) T.Tuple14[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14], E, T12],
Ap[func(T14) T.Tuple14[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14], E, T13],
Ap[T.Tuple14[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14], E, T14],
f1,
f2,
f3,
f4,
f5,
f6,
f7,
f8,
f9,
f10,
f11,
f12,
f13,
f14,
t,
)
}
}
// Eitherize15 converts a function with 15 parameters returning a tuple into a function with 15 parameters returning an Either
// The inverse function is [Uneitherize15]
func Eitherize15[F ~func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14) (R, error), T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, R any](f F) func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14) Either[error, R] {
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) Either[error, R] {
return TryCatchError(f(t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14))
}
}
// Uneitherize15 converts a function with 15 parameters returning an Either into a function with 15 parameters returning a tuple
// The inverse function is [Eitherize15]
func Uneitherize15[F ~func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14) Either[error, R], T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, R any](f F) func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14) (R, error) {
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) (R, error) {
return UnwrapError(f(t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14))
}
}
// SequenceT15 converts 15 parameters of [Either[E, T]] into a [Either[E, Tuple15]].
func SequenceT15[E, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15 any](t1 Either[E, T1], t2 Either[E, T2], t3 Either[E, T3], t4 Either[E, T4], t5 Either[E, T5], t6 Either[E, T6], t7 Either[E, T7], t8 Either[E, T8], t9 Either[E, T9], t10 Either[E, T10], t11 Either[E, T11], t12 Either[E, T12], t13 Either[E, T13], t14 Either[E, T14], t15 Either[E, T15]) Either[E, T.Tuple15[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15]] {
return A.SequenceT15(
Map[E, 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) T.Tuple15[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15]],
Ap[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) T.Tuple15[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15], E, T2],
Ap[func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) func(T13) func(T14) func(T15) T.Tuple15[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15], E, T3],
Ap[func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) func(T13) func(T14) func(T15) T.Tuple15[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15], E, T4],
Ap[func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) func(T13) func(T14) func(T15) T.Tuple15[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15], E, T5],
Ap[func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) func(T13) func(T14) func(T15) T.Tuple15[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15], E, T6],
Ap[func(T8) func(T9) func(T10) func(T11) func(T12) func(T13) func(T14) func(T15) T.Tuple15[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15], E, T7],
Ap[func(T9) func(T10) func(T11) func(T12) func(T13) func(T14) func(T15) T.Tuple15[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15], E, T8],
Ap[func(T10) func(T11) func(T12) func(T13) func(T14) func(T15) T.Tuple15[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15], E, T9],
Ap[func(T11) func(T12) func(T13) func(T14) func(T15) T.Tuple15[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15], E, T10],
Ap[func(T12) func(T13) func(T14) func(T15) T.Tuple15[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15], E, T11],
Ap[func(T13) func(T14) func(T15) T.Tuple15[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15], E, T12],
Ap[func(T14) func(T15) T.Tuple15[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15], E, T13],
Ap[func(T15) T.Tuple15[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15], E, T14],
Ap[T.Tuple15[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15], E, T15],
t1,
t2,
t3,
t4,
t5,
t6,
t7,
t8,
t9,
t10,
t11,
t12,
t13,
t14,
t15,
)
}
// SequenceTuple15 converts a [Tuple15] of [Either[E, T]] into an [Either[E, Tuple15]].
func SequenceTuple15[E, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15 any](t T.Tuple15[Either[E, T1], Either[E, T2], Either[E, T3], Either[E, T4], Either[E, T5], Either[E, T6], Either[E, T7], Either[E, T8], Either[E, T9], Either[E, T10], Either[E, T11], Either[E, T12], Either[E, T13], Either[E, T14], Either[E, T15]]) Either[E, T.Tuple15[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15]] {
return A.SequenceTuple15(
Map[E, 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) T.Tuple15[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15]],
Ap[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) T.Tuple15[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15], E, T2],
Ap[func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) func(T13) func(T14) func(T15) T.Tuple15[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15], E, T3],
Ap[func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) func(T13) func(T14) func(T15) T.Tuple15[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15], E, T4],
Ap[func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) func(T13) func(T14) func(T15) T.Tuple15[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15], E, T5],
Ap[func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) func(T13) func(T14) func(T15) T.Tuple15[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15], E, T6],
Ap[func(T8) func(T9) func(T10) func(T11) func(T12) func(T13) func(T14) func(T15) T.Tuple15[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15], E, T7],
Ap[func(T9) func(T10) func(T11) func(T12) func(T13) func(T14) func(T15) T.Tuple15[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15], E, T8],
Ap[func(T10) func(T11) func(T12) func(T13) func(T14) func(T15) T.Tuple15[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15], E, T9],
Ap[func(T11) func(T12) func(T13) func(T14) func(T15) T.Tuple15[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15], E, T10],
Ap[func(T12) func(T13) func(T14) func(T15) T.Tuple15[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15], E, T11],
Ap[func(T13) func(T14) func(T15) T.Tuple15[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15], E, T12],
Ap[func(T14) func(T15) T.Tuple15[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15], E, T13],
Ap[func(T15) T.Tuple15[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15], E, T14],
Ap[T.Tuple15[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15], E, T15],
t,
)
}
// TraverseTuple15 converts a [Tuple15] of [A] via transformation functions transforming [A] to [Either[E, A]] into a [Either[E, Tuple15]].
func TraverseTuple15[F1 ~func(A1) Either[E, T1], F2 ~func(A2) Either[E, T2], F3 ~func(A3) Either[E, T3], F4 ~func(A4) Either[E, T4], F5 ~func(A5) Either[E, T5], F6 ~func(A6) Either[E, T6], F7 ~func(A7) Either[E, T7], F8 ~func(A8) Either[E, T8], F9 ~func(A9) Either[E, T9], F10 ~func(A10) Either[E, T10], F11 ~func(A11) Either[E, T11], F12 ~func(A12) Either[E, T12], F13 ~func(A13) Either[E, T13], F14 ~func(A14) Either[E, T14], F15 ~func(A15) Either[E, T15], E, A1, T1, A2, T2, A3, T3, A4, T4, A5, T5, A6, T6, A7, T7, A8, T8, A9, T9, A10, T10, A11, T11, A12, T12, A13, T13, A14, T14, A15, T15 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10, f11 F11, f12 F12, f13 F13, f14 F14, f15 F15) func(T.Tuple15[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15]) Either[E, T.Tuple15[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15]] {
return func(t T.Tuple15[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15]) Either[E, T.Tuple15[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15]] {
return A.TraverseTuple15(
Map[E, 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) T.Tuple15[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15]],
Ap[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) T.Tuple15[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15], E, T2],
Ap[func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) func(T13) func(T14) func(T15) T.Tuple15[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15], E, T3],
Ap[func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) func(T13) func(T14) func(T15) T.Tuple15[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15], E, T4],
Ap[func(T6) func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) func(T13) func(T14) func(T15) T.Tuple15[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15], E, T5],
Ap[func(T7) func(T8) func(T9) func(T10) func(T11) func(T12) func(T13) func(T14) func(T15) T.Tuple15[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15], E, T6],
Ap[func(T8) func(T9) func(T10) func(T11) func(T12) func(T13) func(T14) func(T15) T.Tuple15[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15], E, T7],
Ap[func(T9) func(T10) func(T11) func(T12) func(T13) func(T14) func(T15) T.Tuple15[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15], E, T8],
Ap[func(T10) func(T11) func(T12) func(T13) func(T14) func(T15) T.Tuple15[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15], E, T9],
Ap[func(T11) func(T12) func(T13) func(T14) func(T15) T.Tuple15[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15], E, T10],
Ap[func(T12) func(T13) func(T14) func(T15) T.Tuple15[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15], E, T11],
Ap[func(T13) func(T14) func(T15) T.Tuple15[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15], E, T12],
Ap[func(T14) func(T15) T.Tuple15[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15], E, T13],
Ap[func(T15) T.Tuple15[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15], E, T14],
Ap[T.Tuple15[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15], E, T15],
f1,
f2,
f3,
f4,
f5,
f6,
f7,
f8,
f9,
f10,
f11,
f12,
f13,
f14,
f15,
t,
)
}
}

View File

@@ -1,43 +0,0 @@
// Copyright (c) 2024 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 either
import (
"github.com/IBM/fp-go/internal/monad"
)
type eitherMonad[E, A, B any] struct{}
func (o *eitherMonad[E, A, B]) Of(a A) Either[E, A] {
return Of[E, A](a)
}
func (o *eitherMonad[E, A, B]) Map(f func(A) B) func(Either[E, A]) Either[E, B] {
return Map[E, A, B](f)
}
func (o *eitherMonad[E, A, B]) Chain(f func(A) Either[E, B]) func(Either[E, A]) Either[E, B] {
return Chain[E, A, B](f)
}
func (o *eitherMonad[E, A, B]) Ap(fa Either[E, A]) func(Either[E, func(A) B]) Either[E, B] {
return Ap[B, E, A](fa)
}
// Monad implements the monadic operations for [Either]
func Monad[E, A, B any]() monad.Monad[A, B, Either[E, A], Either[E, B], Either[E, func(A) B]] {
return &eitherMonad[E, A, B]{}
}

View File

@@ -1,31 +0,0 @@
// Copyright (c) 2024 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 either
import (
"github.com/IBM/fp-go/internal/pointed"
)
type eitherPointed[E, A any] struct{}
func (o *eitherPointed[E, A]) Of(a A) Either[E, A] {
return Of[E, A](a)
}
// Pointed implements the pointedic operations for [Either]
func Pointed[E, A any]() pointed.Pointed[A, Either[E, A]] {
return &eitherPointed[E, A]{}
}

View File

@@ -19,17 +19,38 @@ import (
F "github.com/IBM/fp-go/function"
)
/*
*
We need to pass the members of the applicative explicitly, because golang does neither support higher kinded types nor template methods on structs or interfaces
HKTRB = HKT<Either[B]>
HKTA = HKT<A>
HKTB = HKT<B>
*/
func traverse[E, A, B, HKTB, HKTRB any](
mof func(Either[E, B]) HKTRB,
mmap func(func(B) Either[E, B]) func(HKTB) HKTRB,
) func(Either[E, A], func(A) HKTB) HKTRB {
left := F.Flow2(Left[B, E], mof)
right := mmap(Right[E, B])
return func(ta Either[E, A], f func(A) HKTB) HKTRB {
return MonadFold(ta,
left,
F.Flow2(f, right),
)
}
}
// Traverse converts an [Either] of some higher kinded type into the higher kinded type of an [Either]
func Traverse[A, E, B, HKTB, HKTRB any](
mof func(Either[E, B]) HKTRB,
mmap func(func(B) Either[E, B]) func(HKTB) HKTRB,
) func(func(A) HKTB) func(Either[E, A]) HKTRB {
left := F.Flow2(Left[B, E], mof)
right := mmap(Right[E, B])
delegate := traverse[E, A, B](mof, mmap)
return func(f func(A) HKTB) func(Either[E, A]) HKTRB {
return Fold(left, F.Flow2(f, right))
return F.Bind2nd(delegate, f)
}
}

View File

@@ -1,30 +0,0 @@
// 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)
}

View File

@@ -1,36 +0,0 @@
// 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"
)
func MonadAp[A any](fab Endomorphism[A], fa A) A {
return G.MonadAp[Endomorphism[A]](fab, fa)
}
func Ap[A any](fa A) func(Endomorphism[A]) A {
return G.Ap[Endomorphism[A]](fa)
}
func MonadChain[A any](ma Endomorphism[A], f Endomorphism[A]) Endomorphism[A] {
return G.MonadChain[Endomorphism[A]](ma, f)
}
func Chain[A any](f Endomorphism[A]) Endomorphism[Endomorphism[A]] {
return G.Chain[Endomorphism[Endomorphism[A]], Endomorphism[A], A](f)
}

View File

@@ -1,36 +0,0 @@
// 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)
}
}
}
}

View File

@@ -1,37 +0,0 @@
// 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"
I "github.com/IBM/fp-go/identity/generic"
)
func MonadAp[GA ~func(A) A, A any](fab GA, fa A) A {
return I.MonadAp[GA, A, A](fab, fa)
}
func Ap[GA ~func(A) A, A any](fa A) func(GA) A {
return I.Ap[GA, A, A](fa)
}
func MonadChain[GA ~func(A) A, A any](ma GA, f GA) GA {
return Compose(ma, f)
}
func Chain[ENDO ~func(GA) GA, GA ~func(A) A, A any](f GA) ENDO {
return Of[ENDO](F.Bind2nd(Compose[GA], f))
}

View File

@@ -1,57 +0,0 @@
// 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"
M "github.com/IBM/fp-go/monoid"
S "github.com/IBM/fp-go/semigroup"
)
// Of converts any function to an [Endomorphism]
func Of[ENDO ~func(A) A, F ~func(A) A, A any](f F) ENDO {
return func(a A) A {
return f(a)
}
}
// 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 {
return Of[ENDO](F.Identity[A])
}
func Compose[ENDO ~func(A) A, A any](f1, f2 ENDO) ENDO {
return Of[ENDO](F.Flow2(f1, f2))
}
// Semigroup for the Endomorphism where the `concat` operation is the usual function composition.
func Semigroup[ENDO ~func(A) A, A any]() S.Semigroup[ENDO] {
return S.MakeSemigroup(Compose[ENDO])
}
// Monoid for the Endomorphism where the `concat` operation is the usual function composition.
func Monoid[ENDO ~func(A) A, A any]() M.Monoid[ENDO] {
return M.MakeMonoid(Compose[ENDO], Identity[ENDO]())
}

View File

@@ -16,40 +16,17 @@
package endomorphism
import (
G "github.com/IBM/fp-go/endomorphism/generic"
F "github.com/IBM/fp-go/function"
M "github.com/IBM/fp-go/monoid"
S "github.com/IBM/fp-go/semigroup"
)
// Endomorphism is a function that
type Endomorphism[A any] func(A) A
// Of converts any function to an [Endomorphism]
func Of[F ~func(A) A, A any](f F) Endomorphism[A] {
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]
func Identity[A any]() Endomorphism[A] {
return G.Identity[Endomorphism[A]]()
}
// Semigroup for the Endomorphism where the `concat` operation is the usual function composition.
func Semigroup[A any]() S.Semigroup[Endomorphism[A]] {
return G.Semigroup[Endomorphism[A]]()
func Semigroup[A any]() S.Semigroup[func(A) A] {
return S.MakeSemigroup(F.Flow2[func(A) A, func(A) A])
}
// Monoid for the Endomorphism where the `concat` operation is the usual function composition.
func Monoid[A any]() M.Monoid[Endomorphism[A]] {
return G.Monoid[Endomorphism[A]]()
func Monoid[A any]() M.Monoid[func(A) A] {
return M.MakeMonoid(F.Flow2[func(A) A, func(A) A], F.Identity[A])
}

View File

@@ -27,20 +27,20 @@ type eq[T any] struct {
c func(x, y T) bool
}
func (e eq[T]) Equals(x, y T) bool {
return e.c(x, y)
func (self eq[T]) Equals(x, y T) bool {
return self.c(x, y)
}
func strictEq[A comparable](a, b A) bool {
return a == b
}
// FromStrictEquals constructs an [EQ.Eq] from the canonical comparison function
// FromStrictEquals constructs an `Eq` from the canonical comparison function
func FromStrictEquals[T comparable]() Eq[T] {
return FromEquals(strictEq[T])
}
// FromEquals constructs an [EQ.Eq] from the comparison function
// FromEquals constructs an `Eq` from the comparison function
func FromEquals[T any](c func(x, y T) bool) Eq[T] {
return eq[T]{c: c}
}

View File

@@ -16,18 +16,18 @@
package exec
import (
P "github.com/IBM/fp-go/pair"
T "github.com/IBM/fp-go/tuple"
)
type (
// CommandOutput represents the output of executing a command. The first field in the [Tuple2] is
// stdout, the second one is stderr. Use [StdOut] and [StdErr] to access these fields
CommandOutput = P.Pair[[]byte, []byte]
CommandOutput = T.Tuple2[[]byte, []byte]
)
var (
// StdOut returns the field of a [CommandOutput] representing `stdout`
StdOut = P.Head[[]byte, []byte]
StdOut = T.First[[]byte, []byte]
// StdErr returns the field of a [CommandOutput] representing `stderr`
StdErr = P.Tail[[]byte, []byte]
StdErr = T.Second[[]byte, []byte]
)

View File

@@ -15,10 +15,7 @@
package file
import (
"io"
"path/filepath"
)
import "path/filepath"
// Join appends a filename to a root path
func Join(name string) func(root string) string {
@@ -26,18 +23,3 @@ func Join(name string) func(root string) string {
return filepath.Join(root, name)
}
}
// ToReader converts a [io.Reader]
func ToReader[R io.Reader](r R) io.Reader {
return r
}
// ToWriter converts a [io.Writer]
func ToWriter[W io.Writer](w W) io.Writer {
return w
}
// ToCloser converts a [io.Closer]
func ToCloser[C io.Closer](c C) io.Closer {
return c
}

View File

@@ -1,6 +1,6 @@
// Code generated by go generate; DO NOT EDIT.
// This file was generated by robots at
// 2024-02-29 16:19:01.120389 +0100 CET m=+0.011216001
// 2023-10-23 08:30:44.6474482 +0200 CEST m=+0.150851901
package function

View File

@@ -25,17 +25,6 @@ func Memoize[K comparable, T any](f func(K) T) func(K) T {
}
// ContramapMemoize converts a unary function into a unary function that caches the value depending on the parameter
func ContramapMemoize[T, A any, K comparable](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)
}
// CacheCallback converts a unary function into a unary function that caches the value depending on the parameter
func CacheCallback[
T, A any, K comparable](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]()
}

View File

@@ -16,8 +16,6 @@
package function
import (
"fmt"
"math/rand"
"testing"
"github.com/stretchr/testify/assert"
@@ -50,21 +48,3 @@ func TestCache(t *testing.T) {
assert.Equal(t, 10, cached(10))
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)
}

View File

@@ -1,6 +1,6 @@
// Code generated by go generate; DO NOT EDIT.
// This file was generated by robots at
// 2024-02-29 16:18:53.6664566 +0100 CET m=+0.011085101
// 2023-10-23 08:30:41.7972101 +0200 CEST m=+0.008029101
package function
@@ -34,7 +34,8 @@ func Unsliced0[F ~func([]T) R, T, R any](f F) func() R {
// Pipe1 takes an initial value t0 and successively applies 1 functions where the input of a function is the return value of the previous function
// The final return value is the result of the last function application
func Pipe1[F1 ~func(T0) T1, T0, T1 any](t0 T0, f1 F1) T1 {
return f1(t0)
t1 := f1(t0)
return t1
}
// Flow1 creates a function that takes an initial value t0 and successively applies 1 functions where the input of a function is the return value of the previous function
@@ -54,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.
// The inverse function is [Uncurry1]
func Curry1[FCT ~func(T0) T1, T0, T1 any](f FCT) func(T0) T1 {
func Curry1[T0, T1 any](f func(T0) T1) func(T0) T1 {
return func(t0 T0) T1 {
return f(t0)
}
@@ -62,7 +63,7 @@ func Curry1[FCT ~func(T0) T1, T0, T1 any](f FCT) func(T0) T1 {
// Uncurry1 takes a cascade of 1 functions each taking only one parameter and returns a function with 1 parameters .
// The inverse function is [Curry1]
func Uncurry1[FCT ~func(T0) T1, T0, T1 any](f FCT) func(T0) T1 {
func Uncurry1[T0, T1 any](f func(T0) T1) func(T0) T1 {
return func(t0 T0) T1 {
return f(t0)
}
@@ -92,7 +93,9 @@ func Unsliced1[F ~func([]T) R, T, R any](f F) func(T) R {
// Pipe2 takes an initial value t0 and successively applies 2 functions where the input of a function is the return value of the previous function
// The final return value is the result of the last function application
func Pipe2[F1 ~func(T0) T1, F2 ~func(T1) T2, T0, T1, T2 any](t0 T0, f1 F1, f2 F2) T2 {
return f2(f1(t0))
t1 := f1(t0)
t2 := f2(t1)
return t2
}
// Flow2 creates a function that takes an initial value t0 and successively applies 2 functions where the input of a function is the return value of the previous function
@@ -112,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.
// The inverse function is [Uncurry2]
func Curry2[FCT ~func(T0, T1) T2, T0, T1, T2 any](f FCT) func(T0) func(T1) T2 {
func Curry2[T0, T1, T2 any](f func(T0, T1) T2) func(T0) func(T1) T2 {
return func(t0 T0) func(t1 T1) T2 {
return func(t1 T1) T2 {
return f(t0, t1)
@@ -122,7 +125,7 @@ func Curry2[FCT ~func(T0, T1) T2, T0, T1, T2 any](f FCT) func(T0) func(T1) T2 {
// Uncurry2 takes a cascade of 2 functions each taking only one parameter and returns a function with 2 parameters .
// The inverse function is [Curry2]
func Uncurry2[FCT ~func(T0) func(T1) T2, T0, T1, T2 any](f FCT) func(T0, T1) T2 {
func Uncurry2[T0, T1, T2 any](f func(T0) func(T1) T2) func(T0, T1) T2 {
return func(t0 T0, t1 T1) T2 {
return f(t0)(t1)
}
@@ -152,7 +155,10 @@ func Unsliced2[F ~func([]T) R, T, R any](f F) func(T, T) R {
// Pipe3 takes an initial value t0 and successively applies 3 functions where the input of a function is the return value of the previous function
// The final return value is the result of the last function application
func Pipe3[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, T0, T1, T2, T3 any](t0 T0, f1 F1, f2 F2, f3 F3) T3 {
return f3(f2(f1(t0)))
t1 := f1(t0)
t2 := f2(t1)
t3 := f3(t2)
return t3
}
// Flow3 creates a function that takes an initial value t0 and successively applies 3 functions where the input of a function is the return value of the previous function
@@ -172,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.
// The inverse function is [Uncurry3]
func Curry3[FCT ~func(T0, T1, T2) T3, T0, T1, T2, T3 any](f FCT) func(T0) func(T1) func(T2) T3 {
func Curry3[T0, T1, T2, T3 any](f func(T0, T1, T2) T3) func(T0) func(T1) func(T2) T3 {
return func(t0 T0) func(t1 T1) func(t2 T2) T3 {
return func(t1 T1) func(t2 T2) T3 {
return func(t2 T2) T3 {
@@ -184,7 +190,7 @@ func Curry3[FCT ~func(T0, T1, T2) T3, T0, T1, T2, T3 any](f FCT) func(T0) func(T
// Uncurry3 takes a cascade of 3 functions each taking only one parameter and returns a function with 3 parameters .
// The inverse function is [Curry3]
func Uncurry3[FCT ~func(T0) func(T1) func(T2) T3, T0, T1, T2, T3 any](f FCT) func(T0, T1, T2) T3 {
func Uncurry3[T0, T1, T2, T3 any](f func(T0) func(T1) func(T2) T3) func(T0, T1, T2) T3 {
return func(t0 T0, t1 T1, t2 T2) T3 {
return f(t0)(t1)(t2)
}
@@ -214,7 +220,11 @@ func Unsliced3[F ~func([]T) R, T, R any](f F) func(T, T, T) R {
// Pipe4 takes an initial value t0 and successively applies 4 functions where the input of a function is the return value of the previous function
// The final return value is the result of the last function application
func Pipe4[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, T0, T1, T2, T3, T4 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4) T4 {
return f4(f3(f2(f1(t0))))
t1 := f1(t0)
t2 := f2(t1)
t3 := f3(t2)
t4 := f4(t3)
return t4
}
// Flow4 creates a function that takes an initial value t0 and successively applies 4 functions where the input of a function is the return value of the previous function
@@ -234,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.
// The inverse function is [Uncurry4]
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 {
func Curry4[T0, T1, T2, T3, T4 any](f func(T0, T1, T2, T3) T4) 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(t1 T1) func(t2 T2) func(t3 T3) T4 {
return func(t2 T2) func(t3 T3) T4 {
@@ -248,7 +258,7 @@ func Curry4[FCT ~func(T0, T1, T2, T3) T4, T0, T1, T2, T3, T4 any](f FCT) func(T0
// Uncurry4 takes a cascade of 4 functions each taking only one parameter and returns a function with 4 parameters .
// The inverse function is [Curry4]
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 {
func Uncurry4[T0, T1, T2, T3, T4 any](f func(T0) func(T1) func(T2) func(T3) T4) func(T0, T1, T2, T3) T4 {
return func(t0 T0, t1 T1, t2 T2, t3 T3) T4 {
return f(t0)(t1)(t2)(t3)
}
@@ -278,7 +288,12 @@ func Unsliced4[F ~func([]T) R, T, R any](f F) func(T, T, T, T) R {
// Pipe5 takes an initial value t0 and successively applies 5 functions where the input of a function is the return value of the previous function
// The final return value is the result of the last function application
func Pipe5[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, T0, T1, T2, T3, T4, T5 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5) T5 {
return f5(f4(f3(f2(f1(t0)))))
t1 := f1(t0)
t2 := f2(t1)
t3 := f3(t2)
t4 := f4(t3)
t5 := f5(t4)
return t5
}
// Flow5 creates a function that takes an initial value t0 and successively applies 5 functions where the input of a function is the return value of the previous function
@@ -298,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.
// The inverse function is [Uncurry5]
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 {
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 {
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(t2 T2) func(t3 T3) func(t4 T4) T5 {
@@ -314,7 +329,7 @@ func Curry5[FCT ~func(T0, T1, T2, T3, T4) T5, T0, T1, T2, T3, T4, T5 any](f FCT)
// Uncurry5 takes a cascade of 5 functions each taking only one parameter and returns a function with 5 parameters .
// The inverse function is [Curry5]
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 {
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 {
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4) T5 {
return f(t0)(t1)(t2)(t3)(t4)
}
@@ -344,7 +359,13 @@ func Unsliced5[F ~func([]T) R, T, R any](f F) func(T, T, T, T, T) R {
// Pipe6 takes an initial value t0 and successively applies 6 functions where the input of a function is the return value of the previous function
// The final return value is the result of the last function application
func Pipe6[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, T0, T1, T2, T3, T4, T5, T6 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6) T6 {
return f6(f5(f4(f3(f2(f1(t0))))))
t1 := f1(t0)
t2 := f2(t1)
t3 := f3(t2)
t4 := f4(t3)
t5 := f5(t4)
t6 := f6(t5)
return t6
}
// Flow6 creates a function that takes an initial value t0 and successively applies 6 functions where the input of a function is the return value of the previous function
@@ -364,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.
// The inverse function is [Uncurry6]
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 {
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 {
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(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) T6 {
@@ -382,7 +403,7 @@ func Curry6[FCT ~func(T0, T1, T2, T3, T4, T5) T6, T0, T1, T2, T3, T4, T5, T6 any
// Uncurry6 takes a cascade of 6 functions each taking only one parameter and returns a function with 6 parameters .
// The inverse function is [Curry6]
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 {
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 {
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4, t5 T5) T6 {
return f(t0)(t1)(t2)(t3)(t4)(t5)
}
@@ -412,7 +433,14 @@ func Unsliced6[F ~func([]T) R, T, R any](f F) func(T, T, T, T, T, T) R {
// Pipe7 takes an initial value t0 and successively applies 7 functions where the input of a function is the return value of the previous function
// The final return value is the result of the last function application
func Pipe7[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, T0, T1, T2, T3, T4, T5, T6, T7 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7) T7 {
return f7(f6(f5(f4(f3(f2(f1(t0)))))))
t1 := f1(t0)
t2 := f2(t1)
t3 := f3(t2)
t4 := f4(t3)
t5 := f5(t4)
t6 := f6(t5)
t7 := f7(t6)
return t7
}
// Flow7 creates a function that takes an initial value t0 and successively applies 7 functions where the input of a function is the return value of the previous function
@@ -432,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.
// The inverse function is [Uncurry7]
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 {
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 {
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(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) T7 {
@@ -452,7 +480,7 @@ func Curry7[FCT ~func(T0, T1, T2, T3, T4, T5, T6) T7, T0, T1, T2, T3, T4, T5, T6
// Uncurry7 takes a cascade of 7 functions each taking only one parameter and returns a function with 7 parameters .
// The inverse function is [Curry7]
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 {
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 {
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)
}
@@ -482,7 +510,15 @@ func Unsliced7[F ~func([]T) R, T, R any](f F) func(T, T, T, T, T, T, T) R {
// Pipe8 takes an initial value t0 and successively applies 8 functions where the input of a function is the return value of the previous function
// The final return value is the result of the last function application
func Pipe8[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, T0, T1, T2, T3, T4, T5, T6, T7, T8 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8) T8 {
return f8(f7(f6(f5(f4(f3(f2(f1(t0))))))))
t1 := f1(t0)
t2 := f2(t1)
t3 := f3(t2)
t4 := f4(t3)
t5 := f5(t4)
t6 := f6(t5)
t7 := f7(t6)
t8 := f8(t7)
return t8
}
// Flow8 creates a function that takes an initial value t0 and successively applies 8 functions where the input of a function is the return value of the previous function
@@ -502,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.
// The inverse function is [Uncurry8]
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 {
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 {
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(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) func(t7 T7) T8 {
@@ -524,7 +560,7 @@ func Curry8[FCT ~func(T0, T1, T2, T3, T4, T5, T6, T7) T8, T0, T1, T2, T3, T4, T5
// Uncurry8 takes a cascade of 8 functions each taking only one parameter and returns a function with 8 parameters .
// The inverse function is [Curry8]
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 {
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 {
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)
}
@@ -554,7 +590,16 @@ func Unsliced8[F ~func([]T) R, T, R any](f F) func(T, T, T, T, T, T, T, T) R {
// Pipe9 takes an initial value t0 and successively applies 9 functions where the input of a function is the return value of the previous function
// The final return value is the result of the last function application
func Pipe9[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, F9 ~func(T8) T9, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9) T9 {
return f9(f8(f7(f6(f5(f4(f3(f2(f1(t0)))))))))
t1 := f1(t0)
t2 := f2(t1)
t3 := f3(t2)
t4 := f4(t3)
t5 := f5(t4)
t6 := f6(t5)
t7 := f7(t6)
t8 := f8(t7)
t9 := f9(t8)
return t9
}
// Flow9 creates a function that takes an initial value t0 and successively applies 9 functions where the input of a function is the return value of the previous function
@@ -574,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.
// The inverse function is [Uncurry9]
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 {
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 {
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(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) func(t7 T7) func(t8 T8) T9 {
@@ -598,7 +643,7 @@ func Curry9[FCT ~func(T0, T1, T2, T3, T4, T5, T6, T7, T8) T9, T0, T1, T2, T3, T4
// Uncurry9 takes a cascade of 9 functions each taking only one parameter and returns a function with 9 parameters .
// The inverse function is [Curry9]
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 {
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 {
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)
}
@@ -628,7 +673,17 @@ func Unsliced9[F ~func([]T) R, T, R any](f F) func(T, T, T, T, T, T, T, T, T) R
// Pipe10 takes an initial value t0 and successively applies 10 functions where the input of a function is the return value of the previous function
// The final return value is the result of the last function application
func Pipe10[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, F9 ~func(T8) T9, F10 ~func(T9) T10, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10) T10 {
return f10(f9(f8(f7(f6(f5(f4(f3(f2(f1(t0))))))))))
t1 := f1(t0)
t2 := f2(t1)
t3 := f3(t2)
t4 := f4(t3)
t5 := f5(t4)
t6 := f6(t5)
t7 := f7(t6)
t8 := f8(t7)
t9 := f9(t8)
t10 := f10(t9)
return t10
}
// Flow10 creates a function that takes an initial value t0 and successively applies 10 functions where the input of a function is the return value of the previous function
@@ -648,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.
// The inverse function is [Uncurry10]
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 {
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 {
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(t2 T2) func(t3 T3) func(t4 T4) func(t5 T5) func(t6 T6) func(t7 T7) func(t8 T8) func(t9 T9) T10 {
@@ -674,7 +729,7 @@ func Curry10[FCT ~func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9) T10, T0, T1, T2,
// Uncurry10 takes a cascade of 10 functions each taking only one parameter and returns a function with 10 parameters .
// The inverse function is [Curry10]
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 {
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 {
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)
}
@@ -704,7 +759,18 @@ func Unsliced10[F ~func([]T) R, T, R any](f F) func(T, T, T, T, T, T, T, T, T, T
// Pipe11 takes an initial value t0 and successively applies 11 functions where the input of a function is the return value of the previous function
// The final return value is the result of the last function application
func Pipe11[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, F9 ~func(T8) T9, F10 ~func(T9) T10, F11 ~func(T10) T11, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10, f11 F11) T11 {
return f11(f10(f9(f8(f7(f6(f5(f4(f3(f2(f1(t0)))))))))))
t1 := f1(t0)
t2 := f2(t1)
t3 := f3(t2)
t4 := f4(t3)
t5 := f5(t4)
t6 := f6(t5)
t7 := f7(t6)
t8 := f8(t7)
t9 := f9(t8)
t10 := f10(t9)
t11 := f11(t10)
return t11
}
// Flow11 creates a function that takes an initial value t0 and successively applies 11 functions where the input of a function is the return value of the previous function
@@ -724,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.
// The inverse function is [Uncurry11]
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 {
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 {
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(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 {
@@ -752,7 +818,7 @@ func Curry11[FCT ~func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10) T11, T0, T1,
// Uncurry11 takes a cascade of 11 functions each taking only one parameter and returns a function with 11 parameters .
// The inverse function is [Curry11]
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 {
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 {
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)
}
@@ -782,7 +848,19 @@ func Unsliced11[F ~func([]T) R, T, R any](f F) func(T, T, T, T, T, T, T, T, T, T
// Pipe12 takes an initial value t0 and successively applies 12 functions where the input of a function is the return value of the previous function
// The final return value is the result of the last function application
func Pipe12[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, F9 ~func(T8) T9, F10 ~func(T9) T10, F11 ~func(T10) T11, F12 ~func(T11) T12, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10, f11 F11, f12 F12) T12 {
return f12(f11(f10(f9(f8(f7(f6(f5(f4(f3(f2(f1(t0))))))))))))
t1 := f1(t0)
t2 := f2(t1)
t3 := f3(t2)
t4 := f4(t3)
t5 := f5(t4)
t6 := f6(t5)
t7 := f7(t6)
t8 := f8(t7)
t9 := f9(t8)
t10 := f10(t9)
t11 := f11(t10)
t12 := f12(t11)
return t12
}
// Flow12 creates a function that takes an initial value t0 and successively applies 12 functions where the input of a function is the return value of the previous function
@@ -802,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.
// The inverse function is [Uncurry12]
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 {
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 {
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(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 {
@@ -832,7 +910,7 @@ func Curry12[FCT ~func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11) T12, T0
// Uncurry12 takes a cascade of 12 functions each taking only one parameter and returns a function with 12 parameters .
// The inverse function is [Curry12]
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 {
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 {
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)
}
@@ -862,7 +940,20 @@ func Unsliced12[F ~func([]T) R, T, R any](f F) func(T, T, T, T, T, T, T, T, T, T
// Pipe13 takes an initial value t0 and successively applies 13 functions where the input of a function is the return value of the previous function
// The final return value is the result of the last function application
func Pipe13[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, F9 ~func(T8) T9, F10 ~func(T9) T10, F11 ~func(T10) T11, F12 ~func(T11) T12, F13 ~func(T12) T13, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10, f11 F11, f12 F12, f13 F13) T13 {
return f13(f12(f11(f10(f9(f8(f7(f6(f5(f4(f3(f2(f1(t0)))))))))))))
t1 := f1(t0)
t2 := f2(t1)
t3 := f3(t2)
t4 := f4(t3)
t5 := f5(t4)
t6 := f6(t5)
t7 := f7(t6)
t8 := f8(t7)
t9 := f9(t8)
t10 := f10(t9)
t11 := f11(t10)
t12 := f12(t11)
t13 := f13(t12)
return t13
}
// Flow13 creates a function that takes an initial value t0 and successively applies 13 functions where the input of a function is the return value of the previous function
@@ -882,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.
// The inverse function is [Uncurry13]
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 {
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 {
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(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 {
@@ -914,7 +1005,7 @@ func Curry13[FCT ~func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12) T1
// Uncurry13 takes a cascade of 13 functions each taking only one parameter and returns a function with 13 parameters .
// The inverse function is [Curry13]
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 {
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 {
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)
}
@@ -944,7 +1035,21 @@ func Unsliced13[F ~func([]T) R, T, R any](f F) func(T, T, T, T, T, T, T, T, T, T
// Pipe14 takes an initial value t0 and successively applies 14 functions where the input of a function is the return value of the previous function
// The final return value is the result of the last function application
func Pipe14[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, F9 ~func(T8) T9, F10 ~func(T9) T10, F11 ~func(T10) T11, F12 ~func(T11) T12, F13 ~func(T12) T13, F14 ~func(T13) T14, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10, f11 F11, f12 F12, f13 F13, f14 F14) T14 {
return f14(f13(f12(f11(f10(f9(f8(f7(f6(f5(f4(f3(f2(f1(t0))))))))))))))
t1 := f1(t0)
t2 := f2(t1)
t3 := f3(t2)
t4 := f4(t3)
t5 := f5(t4)
t6 := f6(t5)
t7 := f7(t6)
t8 := f8(t7)
t9 := f9(t8)
t10 := f10(t9)
t11 := f11(t10)
t12 := f12(t11)
t13 := f13(t12)
t14 := f14(t13)
return t14
}
// Flow14 creates a function that takes an initial value t0 and successively applies 14 functions where the input of a function is the return value of the previous function
@@ -964,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.
// The inverse function is [Uncurry14]
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 {
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 {
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(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 {
@@ -998,7 +1103,7 @@ func Curry14[FCT ~func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T1
// Uncurry14 takes a cascade of 14 functions each taking only one parameter and returns a function with 14 parameters .
// The inverse function is [Curry14]
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 {
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 {
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)
}
@@ -1028,7 +1133,22 @@ func Unsliced14[F ~func([]T) R, T, R any](f F) func(T, T, T, T, T, T, T, T, T, T
// Pipe15 takes an initial value t0 and successively applies 15 functions where the input of a function is the return value of the previous function
// The final return value is the result of the last function application
func Pipe15[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, F9 ~func(T8) T9, F10 ~func(T9) T10, F11 ~func(T10) T11, F12 ~func(T11) T12, F13 ~func(T12) T13, F14 ~func(T13) T14, F15 ~func(T14) T15, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10, f11 F11, f12 F12, f13 F13, f14 F14, f15 F15) T15 {
return f15(f14(f13(f12(f11(f10(f9(f8(f7(f6(f5(f4(f3(f2(f1(t0)))))))))))))))
t1 := f1(t0)
t2 := f2(t1)
t3 := f3(t2)
t4 := f4(t3)
t5 := f5(t4)
t6 := f6(t5)
t7 := f7(t6)
t8 := f8(t7)
t9 := f9(t8)
t10 := f10(t9)
t11 := f11(t10)
t12 := f12(t11)
t13 := f13(t12)
t14 := f14(t13)
t15 := f15(t14)
return t15
}
// Flow15 creates a function that takes an initial value t0 and successively applies 15 functions where the input of a function is the return value of the previous function
@@ -1048,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.
// The inverse function is [Uncurry15]
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 {
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 {
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(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 {
@@ -1084,7 +1204,7 @@ func Curry15[FCT ~func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T1
// Uncurry15 takes a cascade of 15 functions each taking only one parameter and returns a function with 15 parameters .
// The inverse function is [Curry15]
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 {
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 {
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)
}
@@ -1114,7 +1234,23 @@ func Unsliced15[F ~func([]T) R, T, R any](f F) func(T, T, T, T, T, T, T, T, T, T
// Pipe16 takes an initial value t0 and successively applies 16 functions where the input of a function is the return value of the previous function
// The final return value is the result of the last function application
func Pipe16[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, F9 ~func(T8) T9, F10 ~func(T9) T10, F11 ~func(T10) T11, F12 ~func(T11) T12, F13 ~func(T12) T13, F14 ~func(T13) T14, F15 ~func(T14) T15, F16 ~func(T15) T16, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10, f11 F11, f12 F12, f13 F13, f14 F14, f15 F15, f16 F16) T16 {
return f16(f15(f14(f13(f12(f11(f10(f9(f8(f7(f6(f5(f4(f3(f2(f1(t0))))))))))))))))
t1 := f1(t0)
t2 := f2(t1)
t3 := f3(t2)
t4 := f4(t3)
t5 := f5(t4)
t6 := f6(t5)
t7 := f7(t6)
t8 := f8(t7)
t9 := f9(t8)
t10 := f10(t9)
t11 := f11(t10)
t12 := f12(t11)
t13 := f13(t12)
t14 := f14(t13)
t15 := f15(t14)
t16 := f16(t15)
return t16
}
// Flow16 creates a function that takes an initial value t0 and successively applies 16 functions where the input of a function is the return value of the previous function
@@ -1134,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.
// The inverse function is [Uncurry16]
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 {
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 {
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(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 {
@@ -1172,7 +1308,7 @@ func Curry16[FCT ~func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T1
// Uncurry16 takes a cascade of 16 functions each taking only one parameter and returns a function with 16 parameters .
// The inverse function is [Curry16]
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 {
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 {
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)
}
@@ -1202,7 +1338,24 @@ func Unsliced16[F ~func([]T) R, T, R any](f F) func(T, T, T, T, T, T, T, T, T, T
// Pipe17 takes an initial value t0 and successively applies 17 functions where the input of a function is the return value of the previous function
// The final return value is the result of the last function application
func Pipe17[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, F9 ~func(T8) T9, F10 ~func(T9) T10, F11 ~func(T10) T11, F12 ~func(T11) T12, F13 ~func(T12) T13, F14 ~func(T13) T14, F15 ~func(T14) T15, F16 ~func(T15) T16, F17 ~func(T16) T17, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10, f11 F11, f12 F12, f13 F13, f14 F14, f15 F15, f16 F16, f17 F17) T17 {
return f17(f16(f15(f14(f13(f12(f11(f10(f9(f8(f7(f6(f5(f4(f3(f2(f1(t0)))))))))))))))))
t1 := f1(t0)
t2 := f2(t1)
t3 := f3(t2)
t4 := f4(t3)
t5 := f5(t4)
t6 := f6(t5)
t7 := f7(t6)
t8 := f8(t7)
t9 := f9(t8)
t10 := f10(t9)
t11 := f11(t10)
t12 := f12(t11)
t13 := f13(t12)
t14 := f14(t13)
t15 := f15(t14)
t16 := f16(t15)
t17 := f17(t16)
return t17
}
// Flow17 creates a function that takes an initial value t0 and successively applies 17 functions where the input of a function is the return value of the previous function
@@ -1222,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.
// The inverse function is [Uncurry17]
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 {
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 {
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(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 {
@@ -1262,7 +1415,7 @@ func Curry17[FCT ~func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T1
// Uncurry17 takes a cascade of 17 functions each taking only one parameter and returns a function with 17 parameters .
// The inverse function is [Curry17]
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 {
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 {
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)
}
@@ -1292,7 +1445,25 @@ func Unsliced17[F ~func([]T) R, T, R any](f F) func(T, T, T, T, T, T, T, T, T, T
// Pipe18 takes an initial value t0 and successively applies 18 functions where the input of a function is the return value of the previous function
// The final return value is the result of the last function application
func Pipe18[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, F9 ~func(T8) T9, F10 ~func(T9) T10, F11 ~func(T10) T11, F12 ~func(T11) T12, F13 ~func(T12) T13, F14 ~func(T13) T14, F15 ~func(T14) T15, F16 ~func(T15) T16, F17 ~func(T16) T17, F18 ~func(T17) T18, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10, f11 F11, f12 F12, f13 F13, f14 F14, f15 F15, f16 F16, f17 F17, f18 F18) T18 {
return f18(f17(f16(f15(f14(f13(f12(f11(f10(f9(f8(f7(f6(f5(f4(f3(f2(f1(t0))))))))))))))))))
t1 := f1(t0)
t2 := f2(t1)
t3 := f3(t2)
t4 := f4(t3)
t5 := f5(t4)
t6 := f6(t5)
t7 := f7(t6)
t8 := f8(t7)
t9 := f9(t8)
t10 := f10(t9)
t11 := f11(t10)
t12 := f12(t11)
t13 := f13(t12)
t14 := f14(t13)
t15 := f15(t14)
t16 := f16(t15)
t17 := f17(t16)
t18 := f18(t17)
return t18
}
// Flow18 creates a function that takes an initial value t0 and successively applies 18 functions where the input of a function is the return value of the previous function
@@ -1312,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.
// The inverse function is [Uncurry18]
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 {
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 {
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(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 {
@@ -1354,7 +1525,7 @@ func Curry18[FCT ~func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T1
// Uncurry18 takes a cascade of 18 functions each taking only one parameter and returns a function with 18 parameters .
// The inverse function is [Curry18]
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 {
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 {
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)
}
@@ -1384,7 +1555,26 @@ func Unsliced18[F ~func([]T) R, T, R any](f F) func(T, T, T, T, T, T, T, T, T, T
// Pipe19 takes an initial value t0 and successively applies 19 functions where the input of a function is the return value of the previous function
// The final return value is the result of the last function application
func Pipe19[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, F9 ~func(T8) T9, F10 ~func(T9) T10, F11 ~func(T10) T11, F12 ~func(T11) T12, F13 ~func(T12) T13, F14 ~func(T13) T14, F15 ~func(T14) T15, F16 ~func(T15) T16, F17 ~func(T16) T17, F18 ~func(T17) T18, F19 ~func(T18) T19, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10, f11 F11, f12 F12, f13 F13, f14 F14, f15 F15, f16 F16, f17 F17, f18 F18, f19 F19) T19 {
return f19(f18(f17(f16(f15(f14(f13(f12(f11(f10(f9(f8(f7(f6(f5(f4(f3(f2(f1(t0)))))))))))))))))))
t1 := f1(t0)
t2 := f2(t1)
t3 := f3(t2)
t4 := f4(t3)
t5 := f5(t4)
t6 := f6(t5)
t7 := f7(t6)
t8 := f8(t7)
t9 := f9(t8)
t10 := f10(t9)
t11 := f11(t10)
t12 := f12(t11)
t13 := f13(t12)
t14 := f14(t13)
t15 := f15(t14)
t16 := f16(t15)
t17 := f17(t16)
t18 := f18(t17)
t19 := f19(t18)
return t19
}
// Flow19 creates a function that takes an initial value t0 and successively applies 19 functions where the input of a function is the return value of the previous function
@@ -1404,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.
// The inverse function is [Uncurry19]
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 {
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 {
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(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 {
@@ -1448,7 +1638,7 @@ func Curry19[FCT ~func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T1
// Uncurry19 takes a cascade of 19 functions each taking only one parameter and returns a function with 19 parameters .
// The inverse function is [Curry19]
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 {
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 {
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)
}
@@ -1478,7 +1668,27 @@ func Unsliced19[F ~func([]T) R, T, R any](f F) func(T, T, T, T, T, T, T, T, T, T
// Pipe20 takes an initial value t0 and successively applies 20 functions where the input of a function is the return value of the previous function
// The final return value is the result of the last function application
func Pipe20[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, F9 ~func(T8) T9, F10 ~func(T9) T10, F11 ~func(T10) T11, F12 ~func(T11) T12, F13 ~func(T12) T13, F14 ~func(T13) T14, F15 ~func(T14) T15, F16 ~func(T15) T16, F17 ~func(T16) T17, F18 ~func(T17) T18, F19 ~func(T18) T19, F20 ~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](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10, f11 F11, f12 F12, f13 F13, f14 F14, f15 F15, f16 F16, f17 F17, f18 F18, f19 F19, f20 F20) T20 {
return f20(f19(f18(f17(f16(f15(f14(f13(f12(f11(f10(f9(f8(f7(f6(f5(f4(f3(f2(f1(t0))))))))))))))))))))
t1 := f1(t0)
t2 := f2(t1)
t3 := f3(t2)
t4 := f4(t3)
t5 := f5(t4)
t6 := f6(t5)
t7 := f7(t6)
t8 := f8(t7)
t9 := f9(t8)
t10 := f10(t9)
t11 := f11(t10)
t12 := f12(t11)
t13 := f13(t12)
t14 := f14(t13)
t15 := f15(t14)
t16 := f16(t15)
t17 := f17(t16)
t18 := f18(t17)
t19 := f19(t18)
t20 := f20(t19)
return t20
}
// Flow20 creates a function that takes an initial value t0 and successively applies 20 functions where the input of a function is the return value of the previous function
@@ -1498,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.
// The inverse function is [Uncurry20]
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 {
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 {
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(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 {
@@ -1544,7 +1754,7 @@ func Curry20[FCT ~func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T1
// Uncurry20 takes a cascade of 20 functions each taking only one parameter and returns a function with 20 parameters .
// The inverse function is [Curry20]
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 {
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 {
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)
}

View File

@@ -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
func ContramapMemoize[F ~func(A) T, KF func(A) K, A any, K comparable, T any](kf KF) func(F) F {
return CacheCallback[func(F) F, func() func() T](kf, getOrCreate[K, T]())
return CacheCallback[F](kf, getOrCreate[K, T]())
}
// getOrCreate is a naive implementation of a cache, without bounds
@@ -50,51 +50,13 @@ 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
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 {
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 {
return func(f F) F {
return func(a A) T {
// cache entry
return getOrCreate(kf(a), func() LT {
return L.Memoize[LT](func() T {
return getOrCreate(kf(a), func() func() T {
return L.Memoize[func() T](func() T {
return f(a)
})
})()

8
go.mod
View File

@@ -3,15 +3,15 @@ module github.com/IBM/fp-go
go 1.20
require (
github.com/stretchr/testify v1.11.1
github.com/urfave/cli/v2 v2.27.7
github.com/stretchr/testify v1.8.4
github.com/urfave/cli/v2 v2.25.7
)
require (
github.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.3 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

32
go.sum
View File

@@ -1,33 +1,17 @@
github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4=
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/cpuguy83/go-md2man/v2 v2.0.5 h1:ZtcqGrnekaHpVLArFSe4HK5DoKx1T0rq2DwVB0alcyc=
github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/cpuguy83/go-md2man/v2 v2.0.7 h1:zbFlGlXEAKlwXpmvle3d8Oe3YnkKIK4xSRTd3sHPnBo=
github.com/cpuguy83/go-md2man/v2 v2.0.7/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
github.com/cpuguy83/go-md2man/v2 v2.0.3 h1:qMCsGGgs+MAzDFyp9LpAe1Lqy/fY/qCovCm0qnXZOBM=
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/stretchr/testify v1.11.0 h1:ib4sjIrwZKxE5u/Japgo/7SJV3PvgjGiRNAvTVGqQl8=
github.com/stretchr/testify v1.11.0/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/urfave/cli/v2 v2.27.4 h1:o1owoI+02Eb+K107p27wEX9Bb8eqIoZCfLXloLUSWJ8=
github.com/urfave/cli/v2 v2.27.4/go.mod h1:m4QzxcD2qpra4z7WhzEGn74WZLViBnMpb1ToCAKdGRQ=
github.com/urfave/cli/v2 v2.27.5 h1:WoHEJLdsXr6dDWoJgMq/CboDmyY/8HMMH1fTECbih+w=
github.com/urfave/cli/v2 v2.27.5/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5hrMvTQ=
github.com/urfave/cli/v2 v2.27.6 h1:VdRdS98FNhKZ8/Az8B7MTyGQmpIr36O1EHybx/LaZ4g=
github.com/urfave/cli/v2 v2.27.6/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5hrMvTQ=
github.com/urfave/cli/v2 v2.27.7 h1:bH59vdhbjLv3LAvIu6gd0usJHgoTTPhCFib8qqOwXYU=
github.com/urfave/cli/v2 v2.27.7/go.mod h1:CyNAG/xg+iAOg0N4MPGZqVmv2rCoP267496AOXUZjA4=
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4=
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM=
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/urfave/cli/v2 v2.25.7 h1:VAzn5oq403l5pHjc4OhD54+XGO9cdKVL/7lDjF+iKUs=
github.com/urfave/cli/v2 v2.25.7/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ=
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/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=

View File

@@ -1,387 +0,0 @@
// 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"
"crypto/sha256"
"fmt"
"net/http"
"net/url"
A "github.com/IBM/fp-go/array"
B "github.com/IBM/fp-go/bytes"
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"
R "github.com/IBM/fp-go/record"
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
//
// Deprecated: use [URL] instead
Url = L.MakeLensRef((*Builder).GetURL, (*Builder).SetURL)
// 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 the URL
//
// Deprecated: use [WithURL] instead
WithUrl = URL.Set
// WithURL creates a [Endomorphism] for the URL
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)),
)
// bodyAsBytes returns a []byte with a fallback to the empty array
bodyAsBytes = O.Fold(B.Empty, E.Fold(F.Ignore1of1[error](B.Empty), F.Identity[[]byte]))
)
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
//
// Deprecated: use [GetTargetURL] instead
func (builder *Builder) GetTargetUrl() E.Either[error, string] {
return builder.GetTargetURL()
}
// 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),
)),
)
}
// Deprecated: use [GetURL] instead
func (builder *Builder) GetUrl() string {
return builder.url
}
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
}
// Deprecated: use [SetURL] instead
func (builder *Builder) SetUrl(url string) *Builder {
builder.url = url
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)
}
// GetHash returns a hash value for the builder that can be used as a cache key
func (builder *Builder) GetHash() string {
return MakeHash(builder)
}
// 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
//
// Deprecated: use [WithJSON] instead
func WithJson[T any](data T) Endomorphism {
return WithJSON[T](data)
}
// 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)
}
func hashWriteValue(buf *bytes.Buffer, value string) *bytes.Buffer {
buf.WriteString(value)
return buf
}
func hashWriteQuery(name string, buf *bytes.Buffer, values []string) *bytes.Buffer {
buf.WriteString(name)
return A.Reduce(hashWriteValue, buf)(values)
}
func makeBytes(b *Builder) []byte {
var buf bytes.Buffer
buf.WriteString(b.GetMethod())
buf.WriteString(b.GetURL())
b.GetHeaders().Write(&buf) // #nosec: G104
R.ReduceOrdWithIndex[[]string, *bytes.Buffer](S.Ord)(hashWriteQuery, &buf)(b.GetQuery())
buf.Write(bodyAsBytes(b.GetBody()))
return buf.Bytes()
}
// MakeHash converts a [Builder] into a hash string, convenient to use as a cache key
func MakeHash(b *Builder) string {
return fmt.Sprintf("%x", sha256.Sum256(makeBytes(b)))
}

View File

@@ -1,93 +0,0 @@
// 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 (
"fmt"
"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))
}
func TestHash(t *testing.T) {
b1 := F.Pipe4(
Default,
WithContentType(C.JSON),
WithHeader(H.Accept)(C.JSON),
WithURL("http://www.example.com"),
WithJSON(map[string]string{"a": "b"}),
)
b2 := F.Pipe4(
Default,
WithURL("http://www.example.com"),
WithHeader(H.Accept)(C.JSON),
WithContentType(C.JSON),
WithJSON(map[string]string{"a": "b"}),
)
assert.Equal(t, MakeHash(b1), MakeHash(b2))
assert.NotEqual(t, MakeHash(Default), MakeHash(b2))
fmt.Println(MakeHash(b1))
}

View File

@@ -1,23 +0,0 @@
// 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"
Json = JSON // Deprecated: use [JSON] instead
FormEncoded = "application/x-www-form-urlencoded"
)

View File

@@ -1,74 +0,0 @@
// 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 form
import (
"net/url"
A "github.com/IBM/fp-go/array"
ENDO "github.com/IBM/fp-go/endomorphism"
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"
O "github.com/IBM/fp-go/option"
RG "github.com/IBM/fp-go/record/generic"
)
type (
// Endomorphism returns an [ENDO.Endomorphism] that transforms a form
Endomorphism = ENDO.Endomorphism[url.Values]
)
var (
// Default is the default form field
Default = make(url.Values)
noField = O.None[string]()
// Monoid is the [M.Monoid] for the [Endomorphism]
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 = LRG.AtRecord[url.Values, []string]
composeHead = F.Pipe1(
LA.AtHead[string](),
L.ComposeOptions[url.Values, string](A.Empty[string]()),
)
// AtValue is a [L.Lens] that focusses on first value in form fields
AtValue = F.Flow2(
AtValues,
composeHead,
)
)
// WithValue creates a [FormBuilder] for a certain field
func WithValue(name string) func(value string) Endomorphism {
return F.Flow2(
O.Of[string],
AtValue(name).Set,
)
}
// WithoutValue creates a [FormBuilder] that removes a field
func WithoutValue(name string) Endomorphism {
return AtValue(name).Set(noField)
}

View File

@@ -1,93 +0,0 @@
// 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 form
import (
"net/url"
"testing"
A "github.com/IBM/fp-go/array"
"github.com/IBM/fp-go/eq"
F "github.com/IBM/fp-go/function"
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[url.Values](A.Eq(sEq))
)
func TestLaws(t *testing.T) {
name := "Content-Type"
fieldLaws := LT.AssertLaws[url.Values, O.Option[string]](t, O.Eq(sEq), valuesEq)(AtValue(name))
n := O.None[string]()
s1 := O.Some("s1")
v1 := F.Pipe1(
Default,
WithValue(name)("v1"),
)
v2 := F.Pipe1(
Default,
WithValue("Other-Header")("v2"),
)
assert.True(t, fieldLaws(Default, n))
assert.True(t, fieldLaws(v1, n))
assert.True(t, fieldLaws(v2, n))
assert.True(t, fieldLaws(Default, s1))
assert.True(t, fieldLaws(v1, s1))
assert.True(t, fieldLaws(v2, s1))
}
func TestFormField(t *testing.T) {
v1 := F.Pipe1(
Default,
WithValue("h1")("v1"),
)
v2 := F.Pipe1(
v1,
WithValue("h2")("v2"),
)
// make sure the code does not change structures
assert.False(t, valuesEq.Equals(Default, v1))
assert.False(t, valuesEq.Equals(Default, v2))
assert.False(t, valuesEq.Equals(v1, v2))
// check for existence of values
assert.Equal(t, "v1", v1.Get("h1"))
assert.Equal(t, "v1", v2.Get("h1"))
assert.Equal(t, "v2", v2.Get("h2"))
// check getter on lens
l1 := AtValue("h1")
l2 := AtValue("h2")
assert.Equal(t, O.Of("v1"), l1.Get(v1))
assert.Equal(t, O.Of("v1"), l1.Get(v2))
assert.Equal(t, O.Of("v2"), l2.Get(v2))
}

View File

@@ -1,58 +0,0 @@
// 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,
)
)

View File

@@ -1,58 +0,0 @@
// 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))
}

View File

@@ -18,15 +18,15 @@ package http
import (
H "net/http"
P "github.com/IBM/fp-go/pair"
T "github.com/IBM/fp-go/tuple"
)
type (
// FullResponse represents a full http response, including headers and body
FullResponse = P.Pair[*H.Response, []byte]
FullResponse = T.Tuple2[*H.Response, []byte]
)
var (
Response = P.Head[*H.Response, []byte]
Body = P.Tail[*H.Response, []byte]
Response = T.First[*H.Response, []byte]
Body = T.Second[*H.Response, []byte]
)

View File

@@ -20,7 +20,6 @@ import (
"io"
"mime"
H "net/http"
"net/url"
"regexp"
A "github.com/IBM/fp-go/array"
@@ -28,48 +27,39 @@ import (
"github.com/IBM/fp-go/errors"
F "github.com/IBM/fp-go/function"
O "github.com/IBM/fp-go/option"
P "github.com/IBM/fp-go/pair"
R "github.com/IBM/fp-go/record/generic"
T "github.com/IBM/fp-go/tuple"
)
type (
ParsedMediaType = P.Pair[string, map[string]string]
HttpError struct {
statusCode int
headers H.Header
body []byte
url *url.URL
}
ParsedMediaType = T.Tuple2[string, map[string]string]
)
var (
// mime type to check if a media type matches
isJSONMimeType = regexp.MustCompile(`application/(?:\w+\+)?json`).MatchString
reJsonMimeType = regexp.MustCompile(`application/(?:\w+\+)?json`)
// ValidateResponse validates an HTTP response and returns an [E.Either] if the response is not a success
ValidateResponse = E.FromPredicate(isValidStatus, StatusCodeError)
// alidateJsonContentTypeString parses a content type a validates that it is valid JSON
validateJSONContentTypeString = F.Flow2(
validateJsonContentTypeString = F.Flow2(
ParseMediaType,
E.ChainFirst(F.Flow2(
P.Head[string, map[string]string],
E.FromPredicate(isJSONMimeType, errors.OnSome[string]("mimetype [%s] is not a valid JSON content type")),
T.First[string, map[string]string],
E.FromPredicate(reJsonMimeType.MatchString, func(mimeType string) error {
return fmt.Errorf("mimetype [%s] is not a valid JSON content type", mimeType)
}),
)),
)
// ValidateJSONResponse checks if an HTTP response is a valid JSON response
ValidateJSONResponse = F.Flow2(
// ValidateJsonResponse checks if an HTTP response is a valid JSON response
ValidateJsonResponse = F.Flow2(
E.Of[error, *H.Response],
E.ChainFirst(F.Flow5(
GetHeader,
R.Lookup[H.Header](HeaderContentType),
O.Chain(A.First[string]),
E.FromOption[string](errors.OnNone("unable to access the [%s] header", HeaderContentType)),
E.ChainFirst(validateJSONContentTypeString),
E.ChainFirst(validateJsonContentTypeString),
)))
// ValidateJsonResponse checks if an HTTP response is a valid JSON response
//
// Deprecated: use [ValidateJSONResponse] instead
ValidateJsonResponse = ValidateJSONResponse
)
const (
@@ -79,32 +69,7 @@ const (
// ParseMediaType parses a media type into a tuple
func ParseMediaType(mediaType string) E.Either[error, ParsedMediaType] {
m, p, err := mime.ParseMediaType(mediaType)
return E.TryCatchError(P.MakePair(m, p), err)
}
// Error fulfills the error interface
func (r *HttpError) Error() string {
return fmt.Sprintf("invalid status code [%d] when accessing URL [%s]", r.statusCode, r.url)
}
func (r *HttpError) String() string {
return r.Error()
}
func (r *HttpError) StatusCode() int {
return r.statusCode
}
func (r *HttpError) Headers() H.Header {
return r.headers
}
func (r *HttpError) URL() *url.URL {
return r.url
}
func (r *HttpError) Body() []byte {
return r.body
return E.TryCatchError(T.MakeTuple2(m, p), err)
}
func GetHeader(resp *H.Response) H.Header {
@@ -119,13 +84,6 @@ func isValidStatus(resp *H.Response) bool {
return resp.StatusCode >= H.StatusOK && resp.StatusCode < H.StatusMultipleChoices
}
// StatusCodeError creates an instance of [HttpError] filled with information from the response
func StatusCodeError(resp *H.Response) error {
// read the body
bodyRdr := GetBody(resp)
defer bodyRdr.Close()
// try to access body content
body, _ := io.ReadAll(bodyRdr)
// return an error with comprehensive information
return &HttpError{statusCode: resp.StatusCode, headers: GetHeader(resp).Clone(), body: body, url: resp.Request.URL}
return fmt.Errorf("invalid status code [%d] when accessing URL [%s]", resp.StatusCode, resp.Request.URL)
}

View File

@@ -20,7 +20,6 @@ import (
E "github.com/IBM/fp-go/either"
F "github.com/IBM/fp-go/function"
C "github.com/IBM/fp-go/http/content"
"github.com/stretchr/testify/assert"
)
@@ -39,7 +38,7 @@ func Error[A any](t *testing.T) func(E.Either[error, A]) bool {
func TestValidateJsonContentTypeString(t *testing.T) {
res := F.Pipe1(
validateJSONContentTypeString(C.JSON),
validateJsonContentTypeString("application/json"),
NoError[ParsedMediaType](t),
)
@@ -49,7 +48,7 @@ func TestValidateJsonContentTypeString(t *testing.T) {
func TestValidateInvalidJsonContentTypeString(t *testing.T) {
res := F.Pipe1(
validateJSONContentTypeString("application/xml"),
validateJsonContentTypeString("application/xml"),
Error[ParsedMediaType](t),
)

View File

@@ -1,89 +0,0 @@
// 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 identity
import (
A "github.com/IBM/fp-go/internal/apply"
C "github.com/IBM/fp-go/internal/chain"
F "github.com/IBM/fp-go/internal/functor"
)
// Bind creates an empty context of type [S] to be used with the [Bind] operation
func Do[S any](
empty S,
) S {
return empty
}
// Bind attaches the result of a computation to a context [S1] to produce a context [S2]
func Bind[S1, S2, T any](
setter func(T) func(S1) S2,
f func(S1) T,
) func(S1) S2 {
return C.Bind(
Chain[S1, S2],
Map[T, S2],
setter,
f,
)
}
// Let attaches the result of a computation to a context [S1] to produce a context [S2]
func Let[S1, S2, T any](
key func(T) func(S1) S2,
f func(S1) T,
) func(S1) S2 {
return F.Let(
Map[S1, S2],
key,
f,
)
}
// LetTo attaches the a value to a context [S1] to produce a context [S2]
func LetTo[S1, S2, B any](
key func(B) func(S1) S2,
b B,
) func(S1) S2 {
return F.LetTo(
Map[S1, S2],
key,
b,
)
}
// BindTo initializes a new state [S1] from a value [T]
func BindTo[S1, T any](
setter func(T) S1,
) func(T) S1 {
return C.BindTo(
Map[T, S1],
setter,
)
}
// ApS attaches a value to a context [S1] to produce a context [S2] by considering the context and the value concurrently
func ApS[S1, S2, T any](
setter func(T) func(S1) S2,
fa T,
) func(S1) S2 {
return A.ApS(
Ap[S2, T],
Map[S1, func(T) S2],
setter,
fa,
)
}

View File

@@ -1,6 +1,6 @@
// Code generated by go generate; DO NOT EDIT.
// This file was generated by robots at
// 2024-02-29 16:19:02.7798504 +0100 CET m=+0.021933401
// 2023-10-23 08:30:50.5492271 +0200 CEST m=+0.023274501
package identity

View File

@@ -50,11 +50,7 @@ func MonadChainFirst[GAB ~func(A) B, A, B any](fa A, f GAB) A {
}
func ChainFirst[GAB ~func(A) B, A, B any](f GAB) func(A) A {
return C.ChainFirst(
Chain[func(A) A, A, A],
Map[func(B) A, B, A],
f,
)
return C.ChainFirst(MonadChain[func(A) A, A, A], MonadMap[func(B) A, B, A], f)
}
func MonadFlap[GAB ~func(A) B, A, B any](fab GAB, a A) B {
@@ -62,5 +58,5 @@ func MonadFlap[GAB ~func(A) B, A, B any](fab GAB, a A) B {
}
func Flap[GAB ~func(A) B, B, A any](a A) func(GAB) B {
return FC.Flap(Map[func(GAB) B, GAB, B], a)
return F.Bind2nd(MonadFlap[GAB, A, B], a)
}

View File

@@ -36,7 +36,7 @@ func Map[A, B any](f func(A) B) func(A) B {
return G.Map(f)
}
func MonadMapTo[A, B any](_ A, b B) B {
func MonadMapTo[A, B any](fa A, b B) B {
return b
}

View File

@@ -1,43 +0,0 @@
// Copyright (c) 2024 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 identity
import (
"github.com/IBM/fp-go/internal/monad"
)
type identityMonad[A, B any] struct{}
func (o *identityMonad[A, B]) Of(a A) A {
return Of[A](a)
}
func (o *identityMonad[A, B]) Map(f func(A) B) func(A) B {
return Map[A, B](f)
}
func (o *identityMonad[A, B]) Chain(f func(A) B) func(A) B {
return Chain[A, B](f)
}
func (o *identityMonad[A, B]) Ap(fa A) func(func(A) B) B {
return Ap[B, A](fa)
}
// Monad implements the monadic operations for [Option]
func Monad[A, B any]() monad.Monad[A, B, A, B, func(A) B] {
return &identityMonad[A, B]{}
}

View File

@@ -20,19 +20,13 @@ import (
E "github.com/IBM/fp-go/eq"
F "github.com/IBM/fp-go/function"
"github.com/IBM/fp-go/internal/applicative"
"github.com/IBM/fp-go/internal/apply"
L "github.com/IBM/fp-go/internal/apply/testing"
"github.com/IBM/fp-go/internal/functor"
"github.com/IBM/fp-go/internal/pointed"
"github.com/stretchr/testify/assert"
)
// Applicative identity law
//
// A.ap(A.of(a => a), fa) <-> fa
//
// Deprecated: use [ApplicativeAssertIdentity]
func AssertIdentity[HKTA, HKTAA, A any](t *testing.T,
eq E.Eq[HKTA],
@@ -40,9 +34,6 @@ func AssertIdentity[HKTA, HKTAA, A any](t *testing.T,
fap func(HKTAA, HKTA) HKTA,
) func(fa HKTA) bool {
// mark as test helper
t.Helper()
return func(fa HKTA) bool {
left := fap(fof(F.Identity[A]), fa)
@@ -52,33 +43,9 @@ func AssertIdentity[HKTA, HKTAA, A any](t *testing.T,
}
}
// Applicative identity law
//
// A.ap(A.of(a => a), fa) <-> fa
func ApplicativeAssertIdentity[HKTA, HKTFAA, A any](t *testing.T,
eq E.Eq[HKTA],
ap applicative.Applicative[A, A, HKTA, HKTA, HKTFAA],
paa pointed.Pointed[func(A) A, HKTFAA],
) func(fa HKTA) bool {
// mark as test helper
t.Helper()
return func(fa HKTA) bool {
left := ap.Ap(fa)(paa.Of(F.Identity[A]))
right := fa
return assert.True(t, eq.Equals(left, right), "Applicative identity")
}
}
// Applicative homomorphism law
//
// A.ap(A.of(ab), A.of(a)) <-> A.of(ab(a))
//
// Deprecated: use [ApplicativeAssertHomomorphism]
func AssertHomomorphism[HKTA, HKTB, HKTAB, A, B any](t *testing.T,
eq E.Eq[HKTB],
@@ -90,9 +57,6 @@ func AssertHomomorphism[HKTA, HKTB, HKTAB, A, B any](t *testing.T,
ab func(A) B,
) func(a A) bool {
// mark as test helper
t.Helper()
return func(a A) bool {
left := fap(fofab(ab), fofa(a))
@@ -102,39 +66,14 @@ func AssertHomomorphism[HKTA, HKTB, HKTAB, A, B any](t *testing.T,
}
}
// Applicative homomorphism law
//
// A.ap(A.of(ab), A.of(a)) <-> A.of(ab(a))
func ApplicativeAssertHomomorphism[HKTA, HKTB, HKTFAB, A, B any](t *testing.T,
eq E.Eq[HKTB],
apab applicative.Applicative[A, B, HKTA, HKTB, HKTFAB],
pb pointed.Pointed[B, HKTB],
pfab pointed.Pointed[func(A) B, HKTFAB],
ab func(A) B,
) func(a A) bool {
// mark as test helper
t.Helper()
return func(a A) bool {
left := apab.Ap(apab.Of(a))(pfab.Of(ab))
right := pb.Of(ab(a))
return assert.True(t, eq.Equals(left, right), "Applicative homomorphism")
}
}
// Applicative interchange law
//
// A.ap(fab, A.of(a)) <-> A.ap(A.of(ab => ab(a)), fab)
//
// Deprecated: use [ApplicativeAssertInterchange]
func AssertInterchange[HKTA, HKTB, HKTAB, HKTABB, A, B any](t *testing.T,
eq E.Eq[HKTB],
fofa func(A) HKTA,
fofb func(B) HKTB,
fofab func(func(A) B) HKTAB,
fofabb func(func(func(A) B) B) HKTABB,
@@ -143,9 +82,6 @@ func AssertInterchange[HKTA, HKTB, HKTAB, HKTABB, A, B any](t *testing.T,
ab func(A) B,
) func(a A) bool {
// mark as test helper
t.Helper()
return func(a A) bool {
fab := fofab(ab)
@@ -159,38 +95,7 @@ func AssertInterchange[HKTA, HKTB, HKTAB, HKTABB, A, B any](t *testing.T,
}
}
// Applicative interchange law
//
// A.ap(fab, A.of(a)) <-> A.ap(A.of(ab => ab(a)), fab)
func ApplicativeAssertInterchange[HKTA, HKTB, HKTFAB, HKTABB, A, B any](t *testing.T,
eq E.Eq[HKTB],
apab applicative.Applicative[A, B, HKTA, HKTB, HKTFAB],
apabb applicative.Applicative[func(A) B, B, HKTFAB, HKTB, HKTABB],
pabb pointed.Pointed[func(func(A) B) B, HKTABB],
ab func(A) B,
) func(a A) bool {
// mark as test helper
t.Helper()
return func(a A) bool {
fab := apabb.Of(ab)
left := apab.Ap(apab.Of(a))(fab)
right := apabb.Ap(fab)(pabb.Of(func(ab func(A) B) B {
return ab(a)
}))
return assert.True(t, eq.Equals(left, right), "Applicative homomorphism")
}
}
// AssertLaws asserts the apply laws `identity`, `composition`, `associative composition`, 'applicative identity', 'homomorphism', 'interchange'
//
// Deprecated: use [ApplicativeAssertLaws] instead
func AssertLaws[HKTA, HKTB, HKTC, HKTAA, HKTAB, HKTBC, HKTAC, HKTABB, HKTABAC, A, B, C any](t *testing.T,
eqa E.Eq[HKTA],
eqb E.Eq[HKTB],
@@ -222,62 +127,15 @@ func AssertLaws[HKTA, HKTB, HKTC, HKTAA, HKTAB, HKTBC, HKTAC, HKTABB, HKTABAC, A
ab func(A) B,
bc func(B) C,
) func(a A) bool {
// mark as test helper
t.Helper()
// apply laws
apply := L.AssertLaws(t, eqa, eqc, fofab, fofbc, faa, fab, fac, fbc, fmap, fapab, fapbc, fapac, fapabac, ab, bc)
// applicative laws
identity := AssertIdentity(t, eqa, fofaa, fapaa)
homomorphism := AssertHomomorphism(t, eqb, fofa, fofb, fofab, fapab, ab)
interchange := AssertInterchange(t, eqb, fofa, fofab, fofabb, fapab, fapabb, ab)
interchange := AssertInterchange(t, eqb, fofa, fofb, fofab, fofabb, fapab, fapabb, ab)
return func(a A) bool {
fa := fofa(a)
return apply(fa) && identity(fa) && homomorphism(a) && interchange(a)
}
}
// ApplicativeAssertLaws asserts the apply laws `identity`, `composition`, `associative composition`, 'applicative identity', 'homomorphism', 'interchange'
func ApplicativeAssertLaws[HKTA, HKTB, HKTC, HKTAA, HKTAB, HKTBC, HKTAC, HKTABB, HKTABAC, A, B, C any](t *testing.T,
eqa E.Eq[HKTA],
eqb E.Eq[HKTB],
eqc E.Eq[HKTC],
fofb pointed.Pointed[B, HKTB],
fofaa pointed.Pointed[func(A) A, HKTAA],
fofbc pointed.Pointed[func(B) C, HKTBC],
fofabb pointed.Pointed[func(func(A) B) B, HKTABB],
faa functor.Functor[A, A, HKTA, HKTA],
fmap functor.Functor[func(B) C, func(func(A) B) func(A) C, HKTBC, HKTABAC],
fapaa applicative.Applicative[A, A, HKTA, HKTA, HKTAA],
fapab applicative.Applicative[A, B, HKTA, HKTB, HKTAB],
fapbc apply.Apply[B, C, HKTB, HKTC, HKTBC],
fapac apply.Apply[A, C, HKTA, HKTC, HKTAC],
fapabb applicative.Applicative[func(A) B, B, HKTAB, HKTB, HKTABB],
fapabac applicative.Applicative[func(A) B, func(A) C, HKTAB, HKTAC, HKTABAC],
ab func(A) B,
bc func(B) C,
) func(a A) bool {
// mark as test helper
t.Helper()
// apply laws
apply := L.ApplyAssertLaws(t, eqa, eqc, applicative.ToPointed(fapabac), fofbc, faa, fmap, applicative.ToApply(fapab), fapbc, fapac, applicative.ToApply(fapabac), ab, bc)
// applicative laws
identity := ApplicativeAssertIdentity(t, eqa, fapaa, fofaa)
homomorphism := ApplicativeAssertHomomorphism(t, eqb, fapab, fofb, applicative.ToPointed(fapabb), ab)
interchange := ApplicativeAssertInterchange(t, eqb, fapab, fapabb, fofabb, ab)
return func(a A) bool {
fa := fapaa.Of(a)
return apply(fa) && identity(fa) && homomorphism(a) && interchange(a)
}
}

View File

@@ -1,42 +0,0 @@
// 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 applicative
import (
"github.com/IBM/fp-go/internal/apply"
"github.com/IBM/fp-go/internal/functor"
"github.com/IBM/fp-go/internal/pointed"
)
type Applicative[A, B, HKTA, HKTB, HKTFAB any] interface {
apply.Apply[A, B, HKTA, HKTB, HKTFAB]
pointed.Pointed[A, HKTA]
}
// ToFunctor converts from [Applicative] to [functor.Functor]
func ToFunctor[A, B, HKTA, HKTB, HKTFAB any](ap Applicative[A, B, HKTA, HKTB, HKTFAB]) functor.Functor[A, B, HKTA, HKTB] {
return ap
}
// ToApply converts from [Applicative] to [apply.Apply]
func ToApply[A, B, HKTA, HKTB, HKTFAB any](ap Applicative[A, B, HKTA, HKTB, HKTFAB]) apply.Apply[A, B, HKTA, HKTB, HKTFAB] {
return ap
}
// ToPointed converts from [Applicative] to [pointed.Pointed]
func ToPointed[A, B, HKTA, HKTB, HKTFAB any](ap Applicative[A, B, HKTA, HKTB, HKTFAB]) pointed.Pointed[A, HKTA] {
return ap
}

Some files were not shown because too many files have changed in this diff Show More