mirror of
https://github.com/IBM/fp-go.git
synced 2025-08-30 19:52:00 +02:00
Compare commits
20 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
e2da181297 | ||
|
24960f87a0 | ||
|
6cffae8f89 | ||
|
4fa30b60c0 | ||
|
6b03e19c67 | ||
|
3be4a9ee9d | ||
|
b553ff8d9d | ||
|
5bb85ecca7 | ||
|
2d2f4fa325 | ||
|
e7e58c9d54 | ||
|
e20679d73c | ||
|
b8013af7fa | ||
|
4d008e636a | ||
|
8a4ecd2203 | ||
|
24a7cae6e9 | ||
|
c641a1ae7c | ||
|
d6766c5439 | ||
|
b53ae32570 | ||
|
eb4218c575 | ||
|
ddb9e48441 |
75
.github/workflows/build.yml
vendored
75
.github/workflows/build.yml
vendored
@@ -4,9 +4,7 @@ on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
pull_request:
|
||||
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
dryRun:
|
||||
@@ -15,35 +13,59 @@ on:
|
||||
required: false
|
||||
|
||||
env:
|
||||
# Currently no way to detect automatically
|
||||
DEFAULT_BRANCH: main
|
||||
GO_VERSION: 1.21.6 # renovate: datasource=golang-version depName=golang
|
||||
LATEST_GO_VERSION: 1.21.6 # renovate: datasource=golang-version depName=golang
|
||||
NODE_VERSION: 22
|
||||
DRY_RUN: true
|
||||
|
||||
jobs:
|
||||
build:
|
||||
build-v1:
|
||||
name: Build v1 (Go ${{ matrix.go-version }})
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
go-version: [ '1.20.x', '1.21.x', '1.22.x', '1.23.x']
|
||||
go-version: ['1.20.x', '1.21.x', '1.22.x', '1.23.x']
|
||||
fail-fast: false # Continue with other versions if one fails
|
||||
steps:
|
||||
# full checkout for semantic-release
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Set up go ${{ matrix.go-version }}
|
||||
- name: Set up Go ${{ matrix.go-version }}
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ${{ matrix.go-version }}
|
||||
-
|
||||
name: Tests
|
||||
cache: true # Enable Go module caching
|
||||
- name: Run tests
|
||||
run: |
|
||||
go mod tidy
|
||||
go test -v ./...
|
||||
|
||||
build-v2:
|
||||
name: Build v2 (Go ${{ matrix.go-version }})
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
go-version: ['1.24.x']
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
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 ./...
|
||||
|
||||
release:
|
||||
needs: [build]
|
||||
name: Release
|
||||
needs:
|
||||
- build-v1
|
||||
- build-v2
|
||||
if: github.repository == 'IBM/fp-go' && github.event_name != 'pull_request'
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 15
|
||||
@@ -51,38 +73,37 @@ jobs:
|
||||
contents: write
|
||||
issues: write
|
||||
pull-requests: write
|
||||
|
||||
steps:
|
||||
# full checkout for semantic-release
|
||||
- name: Full checkout
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up Node.js ${{ env.NODE_VERSION }}
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0
|
||||
with:
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
cache: 'npm' # Enable npm caching
|
||||
|
||||
- name: Set up go ${{env.GO_VERSION}}
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ${{env.GO_VERSION}}
|
||||
go-version: ${{ env.LATEST_GO_VERSION }}
|
||||
cache: true # Enable Go module caching
|
||||
|
||||
# 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
|
||||
- name: Determine release mode
|
||||
id: release-mode
|
||||
run: |
|
||||
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
|
||||
if [[ "${{ github.event_name }}" == "workflow_dispatch" && "${{ github.event.inputs.dryRun }}" != "true" ]]; then
|
||||
echo "DRY_RUN=false" >> $GITHUB_ENV
|
||||
elif [[ "${{github.ref}}" =~ ^refs/heads/v[0-9]+(\.[0-9]+)?$ ]]; then
|
||||
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
|
||||
echo "DRY_RUN=false" >> $GITHUB_ENV
|
||||
fi
|
||||
|
||||
- name: Semantic Release
|
||||
- name: Run 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 }}
|
@@ -13,7 +13,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package file
|
||||
package bracket
|
||||
|
||||
import (
|
||||
F "github.com/IBM/fp-go/function"
|
||||
|
43
v2/README.md
Normal file
43
v2/README.md
Normal file
@@ -0,0 +1,43 @@
|
||||
# Functional programming library for golang V2
|
||||
|
||||
Go 1.24 introduces [generic type aliases](https://github.com/golang/go/issues/46477) which are leveraged by V2.
|
||||
|
||||
## ⚠️ Breaking Changes
|
||||
|
||||
- use of [generic type aliases](https://github.com/golang/go/issues/46477) which requires [go1.24](https://tip.golang.org/doc/go1.24)
|
||||
- order of generic type arguments adjusted such that types that _cannot_ be inferred by the method argument come first, e.g. in the `Ap` methods
|
||||
- monadic operations for `Pair` operate on the second argument, to be compatible with the [Haskell](https://hackage.haskell.org/package/TypeCompose-0.9.14/docs/Data-Pair.html) definition
|
||||
|
||||
## Simplifications
|
||||
|
||||
- use type aliases to get rid of namespace imports for type declarations, e.g. instead of
|
||||
|
||||
```go
|
||||
import (
|
||||
ET "github.com/IBM/fp-go/v2/either"
|
||||
)
|
||||
|
||||
func doSth() ET.Either[error, string] {
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
you can declare your type once
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/IBM/fp-go/v2/either"
|
||||
)
|
||||
|
||||
type Either[A any] = either.Either[error, A]
|
||||
```
|
||||
|
||||
and then use it across your codebase
|
||||
|
||||
```go
|
||||
func doSth() Either[string] {
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
- library implementation does no longer need to use the `generic` subpackage, this simplifies reading and understanding of the code
|
30
v2/array/any.go
Normal file
30
v2/array/any.go
Normal file
@@ -0,0 +1,30 @@
|
||||
// Copyright (c) 2023 IBM Corp.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package array
|
||||
|
||||
import (
|
||||
G "github.com/IBM/fp-go/v2/array/generic"
|
||||
)
|
||||
|
||||
// AnyWithIndex tests if any of the elements in the array matches the predicate
|
||||
func AnyWithIndex[A any](pred func(int, A) bool) func([]A) bool {
|
||||
return G.AnyWithIndex[[]A](pred)
|
||||
}
|
||||
|
||||
// Any tests if any of the elements in the array matches the predicate
|
||||
func Any[A any](pred func(A) bool) func([]A) bool {
|
||||
return G.Any[[]A](pred)
|
||||
}
|
30
v2/array/any_test.go
Normal file
30
v2/array/any_test.go
Normal file
@@ -0,0 +1,30 @@
|
||||
// Copyright (c) 2023 IBM Corp.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package array
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
F "github.com/IBM/fp-go/v2/function"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestAny(t *testing.T) {
|
||||
anyBool := Any(F.Identity[bool])
|
||||
|
||||
assert.True(t, anyBool(From(false, true, false)))
|
||||
assert.False(t, anyBool(From(false, false, false)))
|
||||
}
|
351
v2/array/array.go
Normal file
351
v2/array/array.go
Normal file
@@ -0,0 +1,351 @@
|
||||
// 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/v2/array/generic"
|
||||
EM "github.com/IBM/fp-go/v2/endomorphism"
|
||||
F "github.com/IBM/fp-go/v2/function"
|
||||
"github.com/IBM/fp-go/v2/internal/array"
|
||||
M "github.com/IBM/fp-go/v2/monoid"
|
||||
O "github.com/IBM/fp-go/v2/option"
|
||||
"github.com/IBM/fp-go/v2/tuple"
|
||||
)
|
||||
|
||||
// From constructs an array from a set of variadic arguments
|
||||
func From[A any](data ...A) []A {
|
||||
return G.From[[]A](data...)
|
||||
}
|
||||
|
||||
// MakeBy returns a `Array` of length `n` with element `i` initialized with `f(i)`.
|
||||
func MakeBy[F ~func(int) A, A any](n int, f F) []A {
|
||||
return G.MakeBy[[]A](n, f)
|
||||
}
|
||||
|
||||
// Replicate creates a `Array` containing a value repeated the specified number of times.
|
||||
func Replicate[A any](n int, a A) []A {
|
||||
return G.Replicate[[]A](n, a)
|
||||
}
|
||||
|
||||
func MonadMap[A, B any](as []A, f func(a A) B) []B {
|
||||
return G.MonadMap[[]A, []B](as, f)
|
||||
}
|
||||
|
||||
func MonadMapRef[A, B any](as []A, f func(a *A) B) []B {
|
||||
count := len(as)
|
||||
bs := make([]B, count)
|
||||
for i := count - 1; i >= 0; i-- {
|
||||
bs[i] = f(&as[i])
|
||||
}
|
||||
return bs
|
||||
}
|
||||
|
||||
func MapWithIndex[A, B any](f func(int, A) B) func([]A) []B {
|
||||
return G.MapWithIndex[[]A, []B](f)
|
||||
}
|
||||
|
||||
func Map[A, B any](f func(a A) B) func([]A) []B {
|
||||
return G.Map[[]A, []B, A, B](f)
|
||||
}
|
||||
|
||||
func MapRef[A, B any](f func(a *A) B) func([]A) []B {
|
||||
return F.Bind2nd(MonadMapRef[A, B], f)
|
||||
}
|
||||
|
||||
func filterRef[A any](fa []A, pred func(a *A) bool) []A {
|
||||
var result []A
|
||||
count := len(fa)
|
||||
for i := 0; i < count; i++ {
|
||||
a := fa[i]
|
||||
if pred(&a) {
|
||||
result = append(result, a)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func filterMapRef[A, B any](fa []A, pred func(a *A) bool, f func(a *A) B) []B {
|
||||
var result []B
|
||||
count := len(fa)
|
||||
for i := 0; i < count; i++ {
|
||||
a := fa[i]
|
||||
if pred(&a) {
|
||||
result = append(result, f(&a))
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// 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] {
|
||||
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] {
|
||||
return G.FilterWithIndex[[]A](pred)
|
||||
}
|
||||
|
||||
func FilterRef[A any](pred func(*A) bool) EM.Endomorphism[[]A] {
|
||||
return F.Bind2nd(filterRef[A], pred)
|
||||
}
|
||||
|
||||
func MonadFilterMap[A, B any](fa []A, f func(A) O.Option[B]) []B {
|
||||
return G.MonadFilterMap[[]A, []B](fa, f)
|
||||
}
|
||||
|
||||
func MonadFilterMapWithIndex[A, B any](fa []A, f func(int, A) O.Option[B]) []B {
|
||||
return G.MonadFilterMapWithIndex[[]A, []B](fa, f)
|
||||
}
|
||||
|
||||
// FilterMap maps an array with an iterating function that returns an [O.Option] and it keeps only the Some values discarding the Nones.
|
||||
func FilterMap[A, B any](f func(A) O.Option[B]) func([]A) []B {
|
||||
return G.FilterMap[[]A, []B](f)
|
||||
}
|
||||
|
||||
// FilterMapWithIndex maps an array with an iterating function that returns an [O.Option] and it keeps only the Some values discarding the Nones.
|
||||
func FilterMapWithIndex[A, B any](f func(int, A) O.Option[B]) func([]A) []B {
|
||||
return G.FilterMapWithIndex[[]A, []B](f)
|
||||
}
|
||||
|
||||
// FilterChain maps an array with an iterating function that returns an [O.Option] of an array. It keeps only the Some values discarding the Nones and then flattens the result.
|
||||
func FilterChain[A, B any](f func(A) O.Option[[]B]) func([]A) []B {
|
||||
return G.FilterChain[[]A](f)
|
||||
}
|
||||
|
||||
func FilterMapRef[A, B any](pred func(a *A) bool, f func(a *A) B) func([]A) []B {
|
||||
return func(fa []A) []B {
|
||||
return filterMapRef(fa, pred, f)
|
||||
}
|
||||
}
|
||||
|
||||
func reduceRef[A, B any](fa []A, f func(B, *A) B, initial B) B {
|
||||
current := initial
|
||||
count := len(fa)
|
||||
for i := 0; i < count; i++ {
|
||||
current = f(current, &fa[i])
|
||||
}
|
||||
return current
|
||||
}
|
||||
|
||||
func Reduce[A, B any](f func(B, A) B, initial B) func([]A) B {
|
||||
return G.Reduce[[]A](f, initial)
|
||||
}
|
||||
|
||||
func ReduceWithIndex[A, B any](f func(int, B, A) B, initial B) func([]A) B {
|
||||
return G.ReduceWithIndex[[]A](f, initial)
|
||||
}
|
||||
|
||||
func ReduceRight[A, B any](f func(A, B) B, initial B) func([]A) B {
|
||||
return G.ReduceRight[[]A](f, initial)
|
||||
}
|
||||
|
||||
func ReduceRightWithIndex[A, B any](f func(int, A, B) B, initial B) func([]A) B {
|
||||
return G.ReduceRightWithIndex[[]A](f, initial)
|
||||
}
|
||||
|
||||
func ReduceRef[A, B any](f func(B, *A) B, initial B) func([]A) B {
|
||||
return func(as []A) B {
|
||||
return reduceRef(as, f, initial)
|
||||
}
|
||||
}
|
||||
|
||||
func Append[A any](as []A, a A) []A {
|
||||
return G.Append(as, a)
|
||||
}
|
||||
|
||||
func IsEmpty[A any](as []A) bool {
|
||||
return G.IsEmpty(as)
|
||||
}
|
||||
|
||||
func IsNonEmpty[A any](as []A) bool {
|
||||
return len(as) > 0
|
||||
}
|
||||
|
||||
func Empty[A any]() []A {
|
||||
return G.Empty[[]A]()
|
||||
}
|
||||
|
||||
func Zero[A any]() []A {
|
||||
return Empty[A]()
|
||||
}
|
||||
|
||||
// Of constructs a single element array
|
||||
func Of[A any](a A) []A {
|
||||
return G.Of[[]A](a)
|
||||
}
|
||||
|
||||
func MonadChain[A, B any](fa []A, f func(a A) []B) []B {
|
||||
return G.MonadChain[[]A, []B](fa, f)
|
||||
}
|
||||
|
||||
func Chain[A, B any](f func(A) []B) func([]A) []B {
|
||||
return G.Chain[[]A, []B](f)
|
||||
}
|
||||
|
||||
func MonadAp[B, A any](fab []func(A) B, fa []A) []B {
|
||||
return G.MonadAp[[]B](fab, fa)
|
||||
}
|
||||
|
||||
func Ap[B, A any](fa []A) func([]func(A) B) []B {
|
||||
return G.Ap[[]B, []func(A) B](fa)
|
||||
}
|
||||
|
||||
func Match[A, B any](onEmpty func() B, onNonEmpty func([]A) B) func([]A) B {
|
||||
return G.Match[[]A](onEmpty, onNonEmpty)
|
||||
}
|
||||
|
||||
func MatchLeft[A, B any](onEmpty func() B, onNonEmpty func(A, []A) B) func([]A) B {
|
||||
return G.MatchLeft[[]A](onEmpty, onNonEmpty)
|
||||
}
|
||||
|
||||
func Tail[A any](as []A) O.Option[[]A] {
|
||||
return G.Tail(as)
|
||||
}
|
||||
|
||||
func Head[A any](as []A) O.Option[A] {
|
||||
return G.Head(as)
|
||||
}
|
||||
|
||||
func First[A any](as []A) O.Option[A] {
|
||||
return G.First(as)
|
||||
}
|
||||
|
||||
func Last[A any](as []A) O.Option[A] {
|
||||
return G.Last(as)
|
||||
}
|
||||
|
||||
func PrependAll[A any](middle A) EM.Endomorphism[[]A] {
|
||||
return func(as []A) []A {
|
||||
count := len(as)
|
||||
dst := count * 2
|
||||
result := make([]A, dst)
|
||||
for i := count - 1; i >= 0; i-- {
|
||||
dst--
|
||||
result[dst] = as[i]
|
||||
dst--
|
||||
result[dst] = middle
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
func Intersperse[A any](middle A) EM.Endomorphism[[]A] {
|
||||
prepend := PrependAll(middle)
|
||||
return func(as []A) []A {
|
||||
if IsEmpty(as) {
|
||||
return as
|
||||
}
|
||||
return prepend(as)[1:]
|
||||
}
|
||||
}
|
||||
|
||||
func Intercalate[A any](m M.Monoid[A]) func(A) func([]A) A {
|
||||
concatAll := ConcatAll[A](m)
|
||||
return func(middle A) func([]A) A {
|
||||
return Match(m.Empty, F.Flow2(Intersperse(middle), concatAll))
|
||||
}
|
||||
}
|
||||
|
||||
func Flatten[A any](mma [][]A) []A {
|
||||
return G.Flatten(mma)
|
||||
}
|
||||
|
||||
func Slice[A any](low, high int) func(as []A) []A {
|
||||
return array.Slice[[]A](low, high)
|
||||
}
|
||||
|
||||
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] {
|
||||
return G.UpsertAt[[]A](a)
|
||||
}
|
||||
|
||||
func Size[A any](as []A) int {
|
||||
return G.Size(as)
|
||||
}
|
||||
|
||||
func MonadPartition[A any](as []A, pred func(A) bool) tuple.Tuple2[[]A, []A] {
|
||||
return G.MonadPartition(as, pred)
|
||||
}
|
||||
|
||||
// Partition creates two new arrays out of one, the left result contains the elements
|
||||
// for which the predicate returns false, the right one those for which the predicate returns true
|
||||
func Partition[A any](pred func(A) bool) func([]A) tuple.Tuple2[[]A, []A] {
|
||||
return G.Partition[[]A](pred)
|
||||
}
|
||||
|
||||
// IsNil checks if the array is set to nil
|
||||
func IsNil[A any](as []A) bool {
|
||||
return array.IsNil(as)
|
||||
}
|
||||
|
||||
// IsNonNil checks if the array is set to nil
|
||||
func IsNonNil[A any](as []A) bool {
|
||||
return array.IsNonNil(as)
|
||||
}
|
||||
|
||||
// ConstNil returns a nil array
|
||||
func ConstNil[A any]() []A {
|
||||
return array.ConstNil[[]A]()
|
||||
}
|
||||
|
||||
func SliceRight[A any](start int) EM.Endomorphism[[]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)
|
||||
}
|
||||
|
||||
// FoldMapWithIndex maps and folds an array. Map the Array passing each value to the iterating function. Then fold the results using the provided Monoid.
|
||||
func FoldMapWithIndex[A, B any](m M.Monoid[B]) func(func(int, A) B) func([]A) B {
|
||||
return G.FoldMapWithIndex[[]A](m)
|
||||
}
|
||||
|
||||
// Fold folds the array using the provided Monoid.
|
||||
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 MonadFlap[B, A any](fab []func(A) B, a A) []B {
|
||||
return G.MonadFlap[func(A) B, []func(A) B, []B, A, B](fab, a)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
205
v2/array/array_test.go
Normal file
205
v2/array/array_test.go
Normal file
@@ -0,0 +1,205 @@
|
||||
// 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 (
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
F "github.com/IBM/fp-go/v2/function"
|
||||
"github.com/IBM/fp-go/v2/internal/utils"
|
||||
O "github.com/IBM/fp-go/v2/option"
|
||||
S "github.com/IBM/fp-go/v2/string"
|
||||
T "github.com/IBM/fp-go/v2/tuple"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestMap1(t *testing.T) {
|
||||
|
||||
src := []string{"a", "b", "c"}
|
||||
|
||||
up := Map(strings.ToUpper)(src)
|
||||
|
||||
var up1 = []string{}
|
||||
for _, s := range src {
|
||||
up1 = append(up1, strings.ToUpper(s))
|
||||
}
|
||||
|
||||
var up2 = []string{}
|
||||
for i := range src {
|
||||
up2 = append(up2, strings.ToUpper(src[i]))
|
||||
}
|
||||
|
||||
assert.Equal(t, up, up1)
|
||||
assert.Equal(t, up, up2)
|
||||
}
|
||||
|
||||
func TestMap(t *testing.T) {
|
||||
|
||||
mapper := Map(utils.Upper)
|
||||
|
||||
src := []string{"a", "b", "c"}
|
||||
|
||||
dst := mapper(src)
|
||||
|
||||
assert.Equal(t, dst, []string{"A", "B", "C"})
|
||||
}
|
||||
|
||||
func TestReduceRight(t *testing.T) {
|
||||
values := From("a", "b", "c")
|
||||
f := func(a, acc string) string {
|
||||
return fmt.Sprintf("%s%s", acc, a)
|
||||
}
|
||||
b := ""
|
||||
|
||||
assert.Equal(t, "cba", ReduceRight(f, b)(values))
|
||||
assert.Equal(t, "", ReduceRight(f, b)(Empty[string]()))
|
||||
}
|
||||
|
||||
func TestReduce(t *testing.T) {
|
||||
|
||||
values := MakeBy(101, F.Identity[int])
|
||||
|
||||
sum := func(val int, current int) int {
|
||||
return val + current
|
||||
}
|
||||
reducer := Reduce(sum, 0)
|
||||
|
||||
result := reducer(values)
|
||||
assert.Equal(t, result, 5050)
|
||||
|
||||
}
|
||||
|
||||
func TestEmpty(t *testing.T) {
|
||||
assert.True(t, IsNonEmpty(MakeBy(101, F.Identity[int])))
|
||||
assert.True(t, IsEmpty([]int{}))
|
||||
}
|
||||
|
||||
func TestAp(t *testing.T) {
|
||||
assert.Equal(t,
|
||||
[]int{2, 4, 6, 3, 6, 9},
|
||||
F.Pipe1(
|
||||
[]func(int) int{
|
||||
utils.Double,
|
||||
utils.Triple,
|
||||
},
|
||||
Ap[int, int]([]int{1, 2, 3}),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
func TestIntercalate(t *testing.T) {
|
||||
is := Intercalate(S.Monoid)("-")
|
||||
|
||||
assert.Equal(t, "", is(Empty[string]()))
|
||||
assert.Equal(t, "a", is([]string{"a"}))
|
||||
assert.Equal(t, "a-b-c", is([]string{"a", "b", "c"}))
|
||||
assert.Equal(t, "a--c", is([]string{"a", "", "c"}))
|
||||
assert.Equal(t, "a-b", is([]string{"a", "b"}))
|
||||
assert.Equal(t, "a-b-c-d", is([]string{"a", "b", "c", "d"}))
|
||||
}
|
||||
|
||||
func TestPrependAll(t *testing.T) {
|
||||
empty := Empty[int]()
|
||||
prep := PrependAll(0)
|
||||
assert.Equal(t, empty, prep(empty))
|
||||
assert.Equal(t, []int{0, 1, 0, 2, 0, 3}, prep([]int{1, 2, 3}))
|
||||
assert.Equal(t, []int{0, 1}, prep([]int{1}))
|
||||
assert.Equal(t, []int{0, 1, 0, 2, 0, 3, 0, 4}, prep([]int{1, 2, 3, 4}))
|
||||
}
|
||||
|
||||
func TestFlatten(t *testing.T) {
|
||||
assert.Equal(t, []int{1, 2, 3}, Flatten([][]int{{1}, {2}, {3}}))
|
||||
}
|
||||
|
||||
func TestLookup(t *testing.T) {
|
||||
data := []int{0, 1, 2}
|
||||
none := O.None[int]()
|
||||
|
||||
assert.Equal(t, none, Lookup[int](-1)(data))
|
||||
assert.Equal(t, none, Lookup[int](10)(data))
|
||||
assert.Equal(t, O.Some(1), Lookup[int](1)(data))
|
||||
}
|
||||
|
||||
func TestSlice(t *testing.T) {
|
||||
data := []int{0, 1, 2, 3}
|
||||
|
||||
assert.Equal(t, []int{1, 2}, Slice[int](1, 3)(data))
|
||||
}
|
||||
|
||||
func TestFrom(t *testing.T) {
|
||||
assert.Equal(t, []int{1, 2, 3}, From(1, 2, 3))
|
||||
}
|
||||
|
||||
func TestPartition(t *testing.T) {
|
||||
|
||||
pred := func(n int) bool {
|
||||
return n > 2
|
||||
}
|
||||
|
||||
assert.Equal(t, T.MakeTuple2(Empty[int](), Empty[int]()), Partition(pred)(Empty[int]()))
|
||||
assert.Equal(t, T.MakeTuple2(From(1), From(3)), Partition(pred)(From(1, 3)))
|
||||
}
|
||||
|
||||
func TestFilterChain(t *testing.T) {
|
||||
src := From(1, 2, 3)
|
||||
|
||||
f := func(i int) O.Option[[]string] {
|
||||
if i%2 != 0 {
|
||||
return O.Of(From(fmt.Sprintf("a%d", i), fmt.Sprintf("b%d", i)))
|
||||
}
|
||||
return O.None[[]string]()
|
||||
}
|
||||
|
||||
res := FilterChain(f)(src)
|
||||
|
||||
assert.Equal(t, From("a1", "b1", "a3", "b3"), res)
|
||||
}
|
||||
|
||||
func TestFilterMap(t *testing.T) {
|
||||
src := From(1, 2, 3)
|
||||
|
||||
f := func(i int) O.Option[string] {
|
||||
if i%2 != 0 {
|
||||
return O.Of(fmt.Sprintf("a%d", i))
|
||||
}
|
||||
return O.None[string]()
|
||||
}
|
||||
|
||||
res := FilterMap(f)(src)
|
||||
|
||||
assert.Equal(t, From("a1", "a3"), res)
|
||||
}
|
||||
|
||||
func TestFoldMap(t *testing.T) {
|
||||
src := From("a", "b", "c")
|
||||
|
||||
fold := FoldMap[string](S.Monoid)(strings.ToUpper)
|
||||
|
||||
assert.Equal(t, "ABC", fold(src))
|
||||
}
|
||||
|
||||
func ExampleFoldMap() {
|
||||
src := From("a", "b", "c")
|
||||
|
||||
fold := FoldMap[string](S.Monoid)(strings.ToUpper)
|
||||
|
||||
fmt.Println(fold(src))
|
||||
|
||||
// Output: ABC
|
||||
|
||||
}
|
66
v2/array/bind.go
Normal file
66
v2/array/bind.go
Normal file
@@ -0,0 +1,66 @@
|
||||
// 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/v2/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)
|
||||
}
|
56
v2/array/bind_test.go
Normal file
56
v2/array/bind_test.go
Normal file
@@ -0,0 +1,56 @@
|
||||
// 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/v2/function"
|
||||
"github.com/IBM/fp-go/v2/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"))
|
||||
}
|
40
v2/array/eq.go
Normal file
40
v2/array/eq.go
Normal file
@@ -0,0 +1,40 @@
|
||||
// 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 (
|
||||
E "github.com/IBM/fp-go/v2/eq"
|
||||
)
|
||||
|
||||
func equals[T any](left []T, right []T, eq func(T, T) bool) bool {
|
||||
if len(left) != len(right) {
|
||||
return false
|
||||
}
|
||||
for i, v1 := range left {
|
||||
v2 := right[i]
|
||||
if !eq(v1, v2) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func Eq[T any](e E.Eq[T]) E.Eq[[]T] {
|
||||
eq := e.Equals
|
||||
return E.FromEquals(func(left, right []T) bool {
|
||||
return equals(left, right, eq)
|
||||
})
|
||||
}
|
77
v2/array/example_any_test.go
Normal file
77
v2/array/example_any_test.go
Normal file
@@ -0,0 +1,77 @@
|
||||
// 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 (
|
||||
"fmt"
|
||||
|
||||
F "github.com/IBM/fp-go/v2/function"
|
||||
O "github.com/IBM/fp-go/v2/option"
|
||||
)
|
||||
|
||||
func Example_any() {
|
||||
|
||||
pred := func(val int) bool {
|
||||
return val&2 == 0
|
||||
}
|
||||
|
||||
data1 := From(1, 2, 3)
|
||||
|
||||
fmt.Println(Any(pred)(data1))
|
||||
|
||||
// Output:
|
||||
// true
|
||||
}
|
||||
|
||||
func Example_any_filter() {
|
||||
|
||||
pred := func(val int) bool {
|
||||
return val&2 == 0
|
||||
}
|
||||
|
||||
data1 := From(1, 2, 3)
|
||||
|
||||
// Any tests if any of the entries in the array matches the condition
|
||||
Any := F.Flow2(
|
||||
Filter(pred),
|
||||
IsNonEmpty[int],
|
||||
)
|
||||
|
||||
fmt.Println(Any(data1))
|
||||
|
||||
// Output:
|
||||
// true
|
||||
}
|
||||
|
||||
func Example_any_find() {
|
||||
|
||||
pred := func(val int) bool {
|
||||
return val&2 == 0
|
||||
}
|
||||
|
||||
data1 := From(1, 2, 3)
|
||||
|
||||
// Any tests if any of the entries in the array matches the condition
|
||||
Any := F.Flow2(
|
||||
FindFirst(pred),
|
||||
O.IsSome[int],
|
||||
)
|
||||
|
||||
fmt.Println(Any(data1))
|
||||
|
||||
// Output:
|
||||
// true
|
||||
}
|
55
v2/array/example_find_test.go
Normal file
55
v2/array/example_find_test.go
Normal file
@@ -0,0 +1,55 @@
|
||||
// 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 (
|
||||
"fmt"
|
||||
|
||||
F "github.com/IBM/fp-go/v2/function"
|
||||
)
|
||||
|
||||
func Example_find() {
|
||||
|
||||
pred := func(val int) bool {
|
||||
return val&2 == 0
|
||||
}
|
||||
|
||||
data1 := From(1, 2, 3)
|
||||
|
||||
fmt.Println(FindFirst(pred)(data1))
|
||||
|
||||
// Output:
|
||||
// Some[int](1)
|
||||
}
|
||||
|
||||
func Example_find_filter() {
|
||||
|
||||
pred := func(val int) bool {
|
||||
return val&2 == 0
|
||||
}
|
||||
|
||||
data1 := From(1, 2, 3)
|
||||
|
||||
Find := F.Flow2(
|
||||
Filter(pred),
|
||||
Head[int],
|
||||
)
|
||||
|
||||
fmt.Println(Find(data1))
|
||||
|
||||
// Output:
|
||||
// Some[int](1)
|
||||
}
|
59
v2/array/examples_basic_test.go
Normal file
59
v2/array/examples_basic_test.go
Normal file
@@ -0,0 +1,59 @@
|
||||
// Copyright (c) 2023 IBM Corp.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package array
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
F "github.com/IBM/fp-go/v2/function"
|
||||
O "github.com/IBM/fp-go/v2/option"
|
||||
)
|
||||
|
||||
// Example_basic adapts examples from [https://github.com/inato/fp-ts-cheatsheet#basic-manipulation]
|
||||
func Example_basic() {
|
||||
|
||||
someArray := From(0, 1, 2, 3, 4, 5, 6, 7, 8, 9) // []int
|
||||
|
||||
isEven := func(num int) bool {
|
||||
return num%2 == 0
|
||||
}
|
||||
|
||||
square := func(num int) int {
|
||||
return num * num
|
||||
}
|
||||
|
||||
// filter and map
|
||||
result := F.Pipe2(
|
||||
someArray,
|
||||
Filter(isEven),
|
||||
Map(square),
|
||||
) // [0 4 16 36 64]
|
||||
|
||||
// or in one go with filterMap
|
||||
resultFilterMap := F.Pipe1(
|
||||
someArray,
|
||||
FilterMap(
|
||||
F.Flow2(O.FromPredicate(isEven), O.Map(square)),
|
||||
),
|
||||
)
|
||||
|
||||
fmt.Println(result)
|
||||
fmt.Println(resultFilterMap)
|
||||
|
||||
// Output:
|
||||
// [0 4 16 36 64]
|
||||
// [0 4 16 36 64]
|
||||
}
|
92
v2/array/examples_sort_test.go
Normal file
92
v2/array/examples_sort_test.go
Normal file
@@ -0,0 +1,92 @@
|
||||
// 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 (
|
||||
"fmt"
|
||||
|
||||
F "github.com/IBM/fp-go/v2/function"
|
||||
I "github.com/IBM/fp-go/v2/number/integer"
|
||||
O "github.com/IBM/fp-go/v2/option"
|
||||
"github.com/IBM/fp-go/v2/ord"
|
||||
S "github.com/IBM/fp-go/v2/string"
|
||||
)
|
||||
|
||||
type user struct {
|
||||
name string
|
||||
age O.Option[int]
|
||||
}
|
||||
|
||||
func (user user) GetName() string {
|
||||
return user.name
|
||||
}
|
||||
|
||||
func (user user) GetAge() O.Option[int] {
|
||||
return user.age
|
||||
}
|
||||
|
||||
// Example_sort adapts examples from [https://github.com/inato/fp-ts-cheatsheet#sort-elements-with-ord]
|
||||
func Example_sort() {
|
||||
|
||||
strings := From("zyx", "abc", "klm")
|
||||
|
||||
sortedStrings := F.Pipe1(
|
||||
strings,
|
||||
Sort(S.Ord),
|
||||
) // => ['abc', 'klm', 'zyx']
|
||||
|
||||
// reverse sort
|
||||
reverseSortedStrings := F.Pipe1(
|
||||
strings,
|
||||
Sort(ord.Reverse(S.Ord)),
|
||||
) // => ['zyx', 'klm', 'abc']
|
||||
|
||||
// sort Option
|
||||
optionalNumbers := From(O.Some(1337), O.None[int](), O.Some(42))
|
||||
|
||||
sortedNums := F.Pipe1(
|
||||
optionalNumbers,
|
||||
Sort(O.Ord(I.Ord)),
|
||||
)
|
||||
|
||||
// complex object with different rules
|
||||
byName := F.Pipe1(
|
||||
S.Ord,
|
||||
ord.Contramap(user.GetName),
|
||||
) // ord.Ord[user]
|
||||
|
||||
byAge := F.Pipe1(
|
||||
O.Ord(I.Ord),
|
||||
ord.Contramap(user.GetAge),
|
||||
) // ord.Ord[user]
|
||||
|
||||
sortedUsers := F.Pipe1(
|
||||
From(user{name: "a", age: O.Of(30)}, user{name: "d", age: O.Of(10)}, user{name: "c"}, user{name: "b", age: O.Of(10)}),
|
||||
SortBy(From(byAge, byName)),
|
||||
)
|
||||
|
||||
fmt.Println(sortedStrings)
|
||||
fmt.Println(reverseSortedStrings)
|
||||
fmt.Println(sortedNums)
|
||||
fmt.Println(sortedUsers)
|
||||
|
||||
// Output:
|
||||
// [abc klm zyx]
|
||||
// [zyx klm abc]
|
||||
// [None[int] Some[int](42) Some[int](1337)]
|
||||
// [{c {false 0}} {b {true 10}} {d {true 10}} {a {true 30}}]
|
||||
|
||||
}
|
61
v2/array/find.go
Normal file
61
v2/array/find.go
Normal file
@@ -0,0 +1,61 @@
|
||||
// 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/v2/array/generic"
|
||||
O "github.com/IBM/fp-go/v2/option"
|
||||
)
|
||||
|
||||
// FindFirst finds the first element which satisfies a predicate (or a refinement) function
|
||||
func FindFirst[A any](pred func(A) bool) func([]A) O.Option[A] {
|
||||
return G.FindFirst[[]A](pred)
|
||||
}
|
||||
|
||||
// FindFirstWithIndex finds the first element which satisfies a predicate (or a refinement) function
|
||||
func FindFirstWithIndex[A any](pred func(int, A) bool) func([]A) O.Option[A] {
|
||||
return G.FindFirstWithIndex[[]A](pred)
|
||||
}
|
||||
|
||||
// FindFirstMap finds the first element returned by an [O.Option] based selector function
|
||||
func FindFirstMap[A, B any](sel func(A) O.Option[B]) func([]A) O.Option[B] {
|
||||
return G.FindFirstMap[[]A](sel)
|
||||
}
|
||||
|
||||
// FindFirstMapWithIndex finds the first element returned by an [O.Option] based selector function
|
||||
func FindFirstMapWithIndex[A, B any](sel func(int, A) O.Option[B]) func([]A) O.Option[B] {
|
||||
return G.FindFirstMapWithIndex[[]A](sel)
|
||||
}
|
||||
|
||||
// FindLast finds the Last element which satisfies a predicate (or a refinement) function
|
||||
func FindLast[A any](pred func(A) bool) func([]A) O.Option[A] {
|
||||
return G.FindLast[[]A](pred)
|
||||
}
|
||||
|
||||
// FindLastWithIndex finds the Last element which satisfies a predicate (or a refinement) function
|
||||
func FindLastWithIndex[A any](pred func(int, A) bool) func([]A) O.Option[A] {
|
||||
return G.FindLastWithIndex[[]A](pred)
|
||||
}
|
||||
|
||||
// FindLastMap finds the Last element returned by an [O.Option] based selector function
|
||||
func FindLastMap[A, B any](sel func(A) O.Option[B]) func([]A) O.Option[B] {
|
||||
return G.FindLastMap[[]A](sel)
|
||||
}
|
||||
|
||||
// FindLastMapWithIndex finds the Last element returned by an [O.Option] based selector function
|
||||
func FindLastMapWithIndex[A, B any](sel func(int, A) O.Option[B]) func([]A) O.Option[B] {
|
||||
return G.FindLastMapWithIndex[[]A](sel)
|
||||
}
|
34
v2/array/generic/any.go
Normal file
34
v2/array/generic/any.go
Normal file
@@ -0,0 +1,34 @@
|
||||
// Copyright (c) 2023 IBM Corp.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package generic
|
||||
|
||||
import (
|
||||
F "github.com/IBM/fp-go/v2/function"
|
||||
O "github.com/IBM/fp-go/v2/option"
|
||||
)
|
||||
|
||||
// AnyWithIndex tests if any of the elements in the array matches the predicate
|
||||
func AnyWithIndex[AS ~[]A, PRED ~func(int, A) bool, A any](pred PRED) func(AS) bool {
|
||||
return F.Flow2(
|
||||
FindFirstWithIndex[AS](pred),
|
||||
O.IsSome[A],
|
||||
)
|
||||
}
|
||||
|
||||
// Any tests if any of the elements in the array matches the predicate
|
||||
func Any[AS ~[]A, PRED ~func(A) bool, A any](pred PRED) func(AS) bool {
|
||||
return AnyWithIndex[AS](F.Ignore1of2[int](pred))
|
||||
}
|
352
v2/array/generic/array.go
Normal file
352
v2/array/generic/array.go
Normal file
@@ -0,0 +1,352 @@
|
||||
// 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/v2/function"
|
||||
"github.com/IBM/fp-go/v2/internal/array"
|
||||
FC "github.com/IBM/fp-go/v2/internal/functor"
|
||||
M "github.com/IBM/fp-go/v2/monoid"
|
||||
O "github.com/IBM/fp-go/v2/option"
|
||||
"github.com/IBM/fp-go/v2/tuple"
|
||||
)
|
||||
|
||||
// Of constructs a single element array
|
||||
func Of[GA ~[]A, A any](value A) GA {
|
||||
return GA{value}
|
||||
}
|
||||
|
||||
func Reduce[GA ~[]A, A, B any](f func(B, A) B, initial B) func(GA) B {
|
||||
return func(as GA) B {
|
||||
return MonadReduce[GA](as, f, initial)
|
||||
}
|
||||
}
|
||||
|
||||
func ReduceWithIndex[GA ~[]A, A, B any](f func(int, B, A) B, initial B) func(GA) B {
|
||||
return func(as GA) B {
|
||||
return MonadReduceWithIndex[GA](as, f, initial)
|
||||
}
|
||||
}
|
||||
|
||||
func ReduceRight[GA ~[]A, A, B any](f func(A, B) B, initial B) func(GA) B {
|
||||
return func(as GA) B {
|
||||
return MonadReduceRight[GA](as, f, initial)
|
||||
}
|
||||
}
|
||||
|
||||
func ReduceRightWithIndex[GA ~[]A, A, B any](f func(int, A, B) B, initial B) func(GA) B {
|
||||
return func(as GA) B {
|
||||
return MonadReduceRightWithIndex[GA](as, f, initial)
|
||||
}
|
||||
}
|
||||
|
||||
func MonadReduce[GA ~[]A, A, B any](fa GA, f func(B, A) B, initial B) B {
|
||||
return array.Reduce(fa, f, initial)
|
||||
}
|
||||
|
||||
func MonadReduceWithIndex[GA ~[]A, A, B any](fa GA, f func(int, B, A) B, initial B) B {
|
||||
return array.ReduceWithIndex(fa, f, initial)
|
||||
}
|
||||
|
||||
func MonadReduceRight[GA ~[]A, A, B any](fa GA, f func(A, B) B, initial B) B {
|
||||
return array.ReduceRight(fa, f, initial)
|
||||
}
|
||||
|
||||
func MonadReduceRightWithIndex[GA ~[]A, A, B any](fa GA, f func(int, A, B) B, initial B) B {
|
||||
return array.ReduceRightWithIndex(fa, f, initial)
|
||||
}
|
||||
|
||||
// From constructs an array from a set of variadic arguments
|
||||
func From[GA ~[]A, A any](data ...A) GA {
|
||||
return data
|
||||
}
|
||||
|
||||
// MakeBy returns a `Array` of length `n` with element `i` initialized with `f(i)`.
|
||||
func MakeBy[AS ~[]A, F ~func(int) A, A any](n int, f F) AS {
|
||||
// sanity check
|
||||
if n <= 0 {
|
||||
return Empty[AS]()
|
||||
}
|
||||
// run the generator function across the input
|
||||
as := make(AS, n)
|
||||
for i := n - 1; i >= 0; i-- {
|
||||
as[i] = f(i)
|
||||
}
|
||||
return as
|
||||
}
|
||||
|
||||
func Replicate[AS ~[]A, A any](n int, a A) AS {
|
||||
return MakeBy[AS](n, F.Constant1[int](a))
|
||||
}
|
||||
|
||||
func Lookup[GA ~[]A, A any](idx int) func(GA) O.Option[A] {
|
||||
none := O.None[A]()
|
||||
if idx < 0 {
|
||||
return F.Constant1[GA](none)
|
||||
}
|
||||
return func(as GA) O.Option[A] {
|
||||
if idx < len(as) {
|
||||
return O.Some(as[idx])
|
||||
}
|
||||
return none
|
||||
}
|
||||
}
|
||||
|
||||
func Tail[GA ~[]A, A any](as GA) O.Option[GA] {
|
||||
if array.IsEmpty(as) {
|
||||
return O.None[GA]()
|
||||
}
|
||||
return O.Some(as[1:])
|
||||
}
|
||||
|
||||
func Head[GA ~[]A, A any](as GA) O.Option[A] {
|
||||
if array.IsEmpty(as) {
|
||||
return O.None[A]()
|
||||
}
|
||||
return O.Some(as[0])
|
||||
}
|
||||
|
||||
func First[GA ~[]A, A any](as GA) O.Option[A] {
|
||||
return Head(as)
|
||||
}
|
||||
|
||||
func Last[GA ~[]A, A any](as GA) O.Option[A] {
|
||||
if array.IsEmpty(as) {
|
||||
return O.None[A]()
|
||||
}
|
||||
return O.Some(as[len(as)-1])
|
||||
}
|
||||
|
||||
func Append[GA ~[]A, A any](as GA, a A) GA {
|
||||
return array.Append(as, a)
|
||||
}
|
||||
|
||||
func Empty[GA ~[]A, A any]() GA {
|
||||
return array.Empty[GA]()
|
||||
}
|
||||
|
||||
func UpsertAt[GA ~[]A, A any](a A) func(GA) GA {
|
||||
return array.UpsertAt[GA](a)
|
||||
}
|
||||
|
||||
func MonadMap[GA ~[]A, GB ~[]B, A, B any](as GA, f func(a A) B) GB {
|
||||
return array.MonadMap[GA, GB](as, f)
|
||||
}
|
||||
|
||||
func Map[GA ~[]A, GB ~[]B, A, B any](f func(a A) B) func(GA) GB {
|
||||
return array.Map[GA, GB](f)
|
||||
}
|
||||
|
||||
func MonadMapWithIndex[GA ~[]A, GB ~[]B, A, B any](as GA, f func(int, A) B) GB {
|
||||
return array.MonadMapWithIndex[GA, GB](as, f)
|
||||
}
|
||||
|
||||
func MapWithIndex[GA ~[]A, GB ~[]B, A, B any](f func(int, A) B) func(GA) GB {
|
||||
return F.Bind2nd(MonadMapWithIndex[GA, GB, A, B], f)
|
||||
}
|
||||
|
||||
func Size[GA ~[]A, A any](as GA) int {
|
||||
return len(as)
|
||||
}
|
||||
|
||||
func filterMap[GA ~[]A, GB ~[]B, A, B any](fa GA, f func(A) O.Option[B]) GB {
|
||||
return array.Reduce(fa, func(bs GB, a A) GB {
|
||||
return O.MonadFold(f(a), F.Constant(bs), F.Bind1st(Append[GB, B], bs))
|
||||
}, Empty[GB]())
|
||||
}
|
||||
|
||||
func filterMapWithIndex[GA ~[]A, GB ~[]B, A, B any](fa GA, f func(int, A) O.Option[B]) GB {
|
||||
return array.ReduceWithIndex(fa, func(idx int, bs GB, a A) GB {
|
||||
return O.MonadFold(f(idx, a), F.Constant(bs), F.Bind1st(Append[GB, B], bs))
|
||||
}, Empty[GB]())
|
||||
}
|
||||
|
||||
func MonadFilterMap[GA ~[]A, GB ~[]B, A, B any](fa GA, f func(A) O.Option[B]) GB {
|
||||
return filterMap[GA, GB](fa, f)
|
||||
}
|
||||
|
||||
func MonadFilterMapWithIndex[GA ~[]A, GB ~[]B, A, B any](fa GA, f func(int, A) O.Option[B]) GB {
|
||||
return filterMapWithIndex[GA, GB](fa, f)
|
||||
}
|
||||
|
||||
func filterWithIndex[AS ~[]A, PRED ~func(int, A) bool, A any](fa AS, pred PRED) AS {
|
||||
result := make(AS, 0, len(fa))
|
||||
for i, a := range fa {
|
||||
if pred(i, a) {
|
||||
result = append(result, a)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func FilterWithIndex[AS ~[]A, PRED ~func(int, A) bool, A any](pred PRED) func(AS) AS {
|
||||
return F.Bind2nd(filterWithIndex[AS, PRED, A], pred)
|
||||
}
|
||||
|
||||
func Filter[AS ~[]A, PRED ~func(A) bool, A any](pred PRED) func(AS) AS {
|
||||
return FilterWithIndex[AS](F.Ignore1of2[int](pred))
|
||||
}
|
||||
|
||||
func FilterChain[GA ~[]A, GB ~[]B, A, B any](f func(a A) O.Option[GB]) func(GA) GB {
|
||||
return F.Flow2(
|
||||
FilterMap[GA, []GB](f),
|
||||
Flatten[[]GB],
|
||||
)
|
||||
}
|
||||
|
||||
func Flatten[GAA ~[]GA, GA ~[]A, A any](mma GAA) GA {
|
||||
return MonadChain(mma, F.Identity[GA])
|
||||
}
|
||||
|
||||
func FilterMap[GA ~[]A, GB ~[]B, A, B any](f func(A) O.Option[B]) func(GA) GB {
|
||||
return F.Bind2nd(MonadFilterMap[GA, GB, A, B], f)
|
||||
}
|
||||
|
||||
func FilterMapWithIndex[GA ~[]A, GB ~[]B, A, B any](f func(int, A) O.Option[B]) func(GA) GB {
|
||||
return F.Bind2nd(MonadFilterMapWithIndex[GA, GB, A, B], f)
|
||||
}
|
||||
|
||||
func MonadPartition[GA ~[]A, A any](as GA, pred func(A) bool) tuple.Tuple2[GA, GA] {
|
||||
left := Empty[GA]()
|
||||
right := Empty[GA]()
|
||||
array.Reduce(as, func(c bool, a A) bool {
|
||||
if pred(a) {
|
||||
right = append(right, a)
|
||||
} else {
|
||||
left = append(left, a)
|
||||
}
|
||||
return c
|
||||
}, true)
|
||||
// returns the partition
|
||||
return tuple.MakeTuple2(left, right)
|
||||
}
|
||||
|
||||
func Partition[GA ~[]A, A any](pred func(A) bool) func(GA) tuple.Tuple2[GA, GA] {
|
||||
return F.Bind2nd(MonadPartition[GA, A], pred)
|
||||
}
|
||||
|
||||
func MonadChain[AS ~[]A, BS ~[]B, A, B any](fa AS, f func(a A) BS) BS {
|
||||
return array.Reduce(fa, func(bs BS, a A) BS {
|
||||
return append(bs, f(a)...)
|
||||
}, Empty[BS]())
|
||||
}
|
||||
|
||||
func Chain[AS ~[]A, BS ~[]B, A, B any](f func(A) BS) func(AS) BS {
|
||||
return F.Bind2nd(MonadChain[AS, BS, A, B], f)
|
||||
}
|
||||
|
||||
func MonadAp[BS ~[]B, ABS ~[]func(A) B, AS ~[]A, B, A any](fab ABS, fa AS) BS {
|
||||
return MonadChain(fab, F.Bind1st(MonadMap[AS, BS, A, B], fa))
|
||||
}
|
||||
|
||||
func Ap[BS ~[]B, ABS ~[]func(A) B, AS ~[]A, B, A any](fa AS) func(ABS) BS {
|
||||
return F.Bind2nd(MonadAp[BS, ABS, AS], fa)
|
||||
}
|
||||
|
||||
func IsEmpty[AS ~[]A, A any](as AS) bool {
|
||||
return array.IsEmpty(as)
|
||||
}
|
||||
|
||||
func IsNil[GA ~[]A, A any](as GA) bool {
|
||||
return array.IsNil(as)
|
||||
}
|
||||
|
||||
func IsNonNil[GA ~[]A, A any](as GA) bool {
|
||||
return array.IsNonNil(as)
|
||||
}
|
||||
|
||||
func Match[AS ~[]A, A, B any](onEmpty func() B, onNonEmpty func(AS) B) func(AS) B {
|
||||
return func(as AS) B {
|
||||
if IsEmpty(as) {
|
||||
return onEmpty()
|
||||
}
|
||||
return onNonEmpty(as)
|
||||
}
|
||||
}
|
||||
|
||||
func MatchLeft[AS ~[]A, A, B any](onEmpty func() B, onNonEmpty func(A, AS) B) func(AS) B {
|
||||
return func(as AS) B {
|
||||
if IsEmpty(as) {
|
||||
return onEmpty()
|
||||
}
|
||||
return onNonEmpty(as[0], as[1:])
|
||||
}
|
||||
}
|
||||
|
||||
func Slice[AS ~[]A, A any](start int, end int) func(AS) AS {
|
||||
return func(a AS) AS {
|
||||
return a[start:end]
|
||||
}
|
||||
}
|
||||
|
||||
func SliceRight[AS ~[]A, A any](start int) func(AS) AS {
|
||||
return func(a AS) AS {
|
||||
return a[start:]
|
||||
}
|
||||
}
|
||||
|
||||
func Copy[AS ~[]A, A any](b AS) AS {
|
||||
buf := make(AS, len(b))
|
||||
copy(buf, b)
|
||||
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 {
|
||||
return array.Reduce(as, func(cur B, a A) B {
|
||||
return m.Concat(cur, f(a))
|
||||
}, m.Empty())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func FoldMapWithIndex[AS ~[]A, A, B any](m M.Monoid[B]) func(func(int, A) B) func(AS) B {
|
||||
return func(f func(int, A) B) func(AS) B {
|
||||
return func(as AS) B {
|
||||
return array.ReduceWithIndex(as, func(idx int, cur B, a A) B {
|
||||
return m.Concat(cur, f(idx, a))
|
||||
}, m.Empty())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Fold[AS ~[]A, A any](m M.Monoid[A]) func(AS) A {
|
||||
return func(as AS) A {
|
||||
return array.Reduce(as, m.Concat, m.Empty())
|
||||
}
|
||||
}
|
||||
|
||||
func Push[ENDO ~func(GA) GA, GA ~[]A, A any](a A) ENDO {
|
||||
return F.Bind2nd(array.Push[GA, A], a)
|
||||
}
|
||||
|
||||
func MonadFlap[FAB ~func(A) B, GFAB ~[]FAB, GB ~[]B, A, B any](fab GFAB, a A) GB {
|
||||
return FC.MonadFlap(MonadMap[GFAB, GB], fab, a)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
89
v2/array/generic/bind.go
Normal file
89
v2/array/generic/bind.go
Normal file
@@ -0,0 +1,89 @@
|
||||
// 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/v2/internal/apply"
|
||||
C "github.com/IBM/fp-go/v2/internal/chain"
|
||||
F "github.com/IBM/fp-go/v2/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,
|
||||
)
|
||||
}
|
97
v2/array/generic/find.go
Normal file
97
v2/array/generic/find.go
Normal file
@@ -0,0 +1,97 @@
|
||||
// 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/v2/function"
|
||||
O "github.com/IBM/fp-go/v2/option"
|
||||
)
|
||||
|
||||
// FindFirstWithIndex finds the first element which satisfies a predicate (or a refinement) function
|
||||
func FindFirstWithIndex[AS ~[]A, PRED ~func(int, A) bool, A any](pred PRED) func(AS) O.Option[A] {
|
||||
none := O.None[A]()
|
||||
return func(as AS) O.Option[A] {
|
||||
for i, a := range as {
|
||||
if pred(i, a) {
|
||||
return O.Some(a)
|
||||
}
|
||||
}
|
||||
return none
|
||||
}
|
||||
}
|
||||
|
||||
// FindFirst finds the first element which satisfies a predicate (or a refinement) function
|
||||
func FindFirst[AS ~[]A, PRED ~func(A) bool, A any](pred PRED) func(AS) O.Option[A] {
|
||||
return FindFirstWithIndex[AS](F.Ignore1of2[int](pred))
|
||||
}
|
||||
|
||||
// FindFirstMapWithIndex finds the first element returned by an [O.Option] based selector function
|
||||
func FindFirstMapWithIndex[AS ~[]A, PRED ~func(int, A) O.Option[B], A, B any](pred PRED) func(AS) O.Option[B] {
|
||||
none := O.None[B]()
|
||||
return func(as AS) O.Option[B] {
|
||||
count := len(as)
|
||||
for i := 0; i < count; i++ {
|
||||
out := pred(i, as[i])
|
||||
if O.IsSome(out) {
|
||||
return out
|
||||
}
|
||||
}
|
||||
return none
|
||||
}
|
||||
}
|
||||
|
||||
// FindFirstMap finds the first element returned by an [O.Option] based selector function
|
||||
func FindFirstMap[AS ~[]A, PRED ~func(A) O.Option[B], A, B any](pred PRED) func(AS) O.Option[B] {
|
||||
return FindFirstMapWithIndex[AS](F.Ignore1of2[int](pred))
|
||||
}
|
||||
|
||||
// FindLastWithIndex finds the first element which satisfies a predicate (or a refinement) function
|
||||
func FindLastWithIndex[AS ~[]A, PRED ~func(int, A) bool, A any](pred PRED) func(AS) O.Option[A] {
|
||||
none := O.None[A]()
|
||||
return func(as AS) O.Option[A] {
|
||||
for i := len(as) - 1; i >= 0; i-- {
|
||||
a := as[i]
|
||||
if pred(i, a) {
|
||||
return O.Some(a)
|
||||
}
|
||||
}
|
||||
return none
|
||||
}
|
||||
}
|
||||
|
||||
// FindLast finds the first element which satisfies a predicate (or a refinement) function
|
||||
func FindLast[AS ~[]A, PRED ~func(A) bool, A any](pred PRED) func(AS) O.Option[A] {
|
||||
return FindLastWithIndex[AS](F.Ignore1of2[int](pred))
|
||||
}
|
||||
|
||||
// FindLastMapWithIndex finds the first element returned by an [O.Option] based selector function
|
||||
func FindLastMapWithIndex[AS ~[]A, PRED ~func(int, A) O.Option[B], A, B any](pred PRED) func(AS) O.Option[B] {
|
||||
none := O.None[B]()
|
||||
return func(as AS) O.Option[B] {
|
||||
for i := len(as) - 1; i >= 0; i-- {
|
||||
out := pred(i, as[i])
|
||||
if O.IsSome(out) {
|
||||
return out
|
||||
}
|
||||
}
|
||||
return none
|
||||
}
|
||||
}
|
||||
|
||||
// FindLastMap finds the first element returned by an [O.Option] based selector function
|
||||
func FindLastMap[AS ~[]A, PRED ~func(A) O.Option[B], A, B any](pred PRED) func(AS) O.Option[B] {
|
||||
return FindLastMapWithIndex[AS](F.Ignore1of2[int](pred))
|
||||
}
|
43
v2/array/generic/monad.go
Normal file
43
v2/array/generic/monad.go
Normal file
@@ -0,0 +1,43 @@
|
||||
// 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/v2/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]{}
|
||||
}
|
56
v2/array/generic/sort.go
Normal file
56
v2/array/generic/sort.go
Normal file
@@ -0,0 +1,56 @@
|
||||
// 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 (
|
||||
"sort"
|
||||
|
||||
F "github.com/IBM/fp-go/v2/function"
|
||||
O "github.com/IBM/fp-go/v2/ord"
|
||||
)
|
||||
|
||||
// Sort implements a stable sort on the array given the provided ordering
|
||||
func Sort[GA ~[]T, T any](ord O.Ord[T]) func(ma GA) GA {
|
||||
return SortByKey[GA](ord, F.Identity[T])
|
||||
}
|
||||
|
||||
// SortByKey implements a stable sort on the array given the provided ordering on an extracted key
|
||||
func SortByKey[GA ~[]T, K, T any](ord O.Ord[K], f func(T) K) func(ma GA) GA {
|
||||
|
||||
return func(ma GA) GA {
|
||||
// nothing to sort
|
||||
l := len(ma)
|
||||
if l < 2 {
|
||||
return ma
|
||||
}
|
||||
// copy
|
||||
cpy := make(GA, l)
|
||||
copy(cpy, ma)
|
||||
sort.Slice(cpy, func(i, j int) bool {
|
||||
return ord.Compare(f(cpy[i]), f(cpy[j])) < 0
|
||||
})
|
||||
return cpy
|
||||
}
|
||||
}
|
||||
|
||||
// SortBy implements a stable sort on the array given the provided ordering
|
||||
func SortBy[GA ~[]T, GO ~[]O.Ord[T], T any](ord GO) func(ma GA) GA {
|
||||
return F.Pipe2(
|
||||
ord,
|
||||
Fold[GO](O.Monoid[T]()),
|
||||
Sort[GA, T],
|
||||
)
|
||||
}
|
32
v2/array/generic/uniq.go
Normal file
32
v2/array/generic/uniq.go
Normal file
@@ -0,0 +1,32 @@
|
||||
package generic
|
||||
|
||||
import F "github.com/IBM/fp-go/v2/function"
|
||||
|
||||
// StrictUniq converts an array of arbitrary items into an array or unique items
|
||||
// where uniqueness is determined by the built-in uniqueness constraint
|
||||
func StrictUniq[AS ~[]A, A comparable](as AS) AS {
|
||||
return Uniq[AS](F.Identity[A])(as)
|
||||
}
|
||||
|
||||
// uniquePredUnsafe returns a predicate on a map for uniqueness
|
||||
func uniquePredUnsafe[PRED ~func(A) K, A any, K comparable](f PRED) func(int, A) bool {
|
||||
lookup := make(map[K]bool)
|
||||
return func(_ int, a A) bool {
|
||||
k := f(a)
|
||||
_, has := lookup[k]
|
||||
if has {
|
||||
return false
|
||||
}
|
||||
lookup[k] = true
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// Uniq converts an array of arbitrary items into an array or unique items
|
||||
// where uniqueness is determined based on a key extractor function
|
||||
func Uniq[AS ~[]A, PRED ~func(A) K, A any, K comparable](f PRED) func(as AS) AS {
|
||||
return func(as AS) AS {
|
||||
// we need to create a new predicate for each iteration
|
||||
return filterWithIndex(as, uniquePredUnsafe(f))
|
||||
}
|
||||
}
|
52
v2/array/generic/zip.go
Normal file
52
v2/array/generic/zip.go
Normal file
@@ -0,0 +1,52 @@
|
||||
// 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/v2/function"
|
||||
N "github.com/IBM/fp-go/v2/number"
|
||||
T "github.com/IBM/fp-go/v2/tuple"
|
||||
)
|
||||
|
||||
// ZipWith applies a function to pairs of elements at the same index in two arrays, collecting the results in a new array. If one
|
||||
// input array is short, excess elements of the longer array are discarded.
|
||||
func ZipWith[AS ~[]A, BS ~[]B, CS ~[]C, FCT ~func(A, B) C, A, B, C any](fa AS, fb BS, f FCT) CS {
|
||||
l := N.Min(len(fa), len(fb))
|
||||
res := make(CS, l)
|
||||
for i := l - 1; i >= 0; i-- {
|
||||
res[i] = f(fa[i], fb[i])
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// Zip takes two arrays and returns an array of corresponding pairs. If one input array is short, excess elements of the
|
||||
// longer array are discarded
|
||||
func Zip[AS ~[]A, BS ~[]B, CS ~[]T.Tuple2[A, B], A, B any](fb BS) func(AS) CS {
|
||||
return F.Bind23of3(ZipWith[AS, BS, CS, func(A, B) T.Tuple2[A, B]])(fb, T.MakeTuple2[A, B])
|
||||
}
|
||||
|
||||
// Unzip is the function is reverse of [Zip]. Takes an array of pairs and return two corresponding arrays
|
||||
func Unzip[AS ~[]A, BS ~[]B, CS ~[]T.Tuple2[A, B], A, B any](cs CS) T.Tuple2[AS, BS] {
|
||||
l := len(cs)
|
||||
as := make(AS, l)
|
||||
bs := make(BS, l)
|
||||
for i := l - 1; i >= 0; i-- {
|
||||
t := cs[i]
|
||||
as[i] = t.F1
|
||||
bs[i] = t.F2
|
||||
}
|
||||
return T.MakeTuple2(as, bs)
|
||||
}
|
24
v2/array/magma.go
Normal file
24
v2/array/magma.go
Normal file
@@ -0,0 +1,24 @@
|
||||
// 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 (
|
||||
M "github.com/IBM/fp-go/v2/monoid"
|
||||
)
|
||||
|
||||
func ConcatAll[A any](m M.Monoid[A]) func([]A) A {
|
||||
return Reduce(m.Concat, m.Empty())
|
||||
}
|
36
v2/array/magma_test.go
Normal file
36
v2/array/magma_test.go
Normal file
@@ -0,0 +1,36 @@
|
||||
// Copyright (c) 2023 IBM Corp.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package array
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
M "github.com/IBM/fp-go/v2/monoid"
|
||||
)
|
||||
|
||||
var subInt = M.MakeMonoid(func(first int, second int) int {
|
||||
return first - second
|
||||
}, 0)
|
||||
|
||||
func TestConcatAll(t *testing.T) {
|
||||
|
||||
var subAll = ConcatAll(subInt)
|
||||
|
||||
assert.Equal(t, subAll([]int{1, 2, 3}), -6)
|
||||
|
||||
}
|
26
v2/array/monad.go
Normal file
26
v2/array/monad.go
Normal file
@@ -0,0 +1,26 @@
|
||||
// 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/v2/array/generic"
|
||||
"github.com/IBM/fp-go/v2/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]()
|
||||
}
|
63
v2/array/monoid.go
Normal file
63
v2/array/monoid.go
Normal file
@@ -0,0 +1,63 @@
|
||||
// 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 (
|
||||
"github.com/IBM/fp-go/v2/internal/array"
|
||||
M "github.com/IBM/fp-go/v2/monoid"
|
||||
S "github.com/IBM/fp-go/v2/semigroup"
|
||||
)
|
||||
|
||||
func concat[T any](left, right []T) []T {
|
||||
// some performance checks
|
||||
ll := len(left)
|
||||
if ll == 0 {
|
||||
return right
|
||||
}
|
||||
lr := len(right)
|
||||
if lr == 0 {
|
||||
return left
|
||||
}
|
||||
// need to copy
|
||||
buf := make([]T, ll+lr)
|
||||
copy(buf[copy(buf, left):], right)
|
||||
return buf
|
||||
}
|
||||
|
||||
func Monoid[T any]() M.Monoid[[]T] {
|
||||
return M.MakeMonoid(concat[T], Empty[T]())
|
||||
}
|
||||
|
||||
func Semigroup[T any]() S.Semigroup[[]T] {
|
||||
return S.MakeSemigroup(concat[T])
|
||||
}
|
||||
|
||||
func addLen[A any](count int, data []A) int {
|
||||
return count + len(data)
|
||||
}
|
||||
|
||||
// ConcatAll efficiently concatenates the input arrays into a final array
|
||||
func ArrayConcatAll[A any](data ...[]A) []A {
|
||||
// get the full size
|
||||
count := array.Reduce(data, addLen[A], 0)
|
||||
buf := make([]A, count)
|
||||
// copy
|
||||
array.Reduce(data, func(idx int, seg []A) int {
|
||||
return idx + copy(buf[idx:], seg)
|
||||
}, 0)
|
||||
// returns the final array
|
||||
return buf
|
||||
}
|
26
v2/array/monoid_test.go
Normal file
26
v2/array/monoid_test.go
Normal file
@@ -0,0 +1,26 @@
|
||||
// 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"
|
||||
|
||||
M "github.com/IBM/fp-go/v2/monoid/testing"
|
||||
)
|
||||
|
||||
func TestMonoid(t *testing.T) {
|
||||
M.AssertLaws(t, Monoid[int]())([][]int{{}, {1}, {1, 2}})
|
||||
}
|
136
v2/array/nonempty/array.go
Normal file
136
v2/array/nonempty/array.go
Normal file
@@ -0,0 +1,136 @@
|
||||
// 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 nonempty
|
||||
|
||||
import (
|
||||
G "github.com/IBM/fp-go/v2/array/generic"
|
||||
EM "github.com/IBM/fp-go/v2/endomorphism"
|
||||
F "github.com/IBM/fp-go/v2/function"
|
||||
"github.com/IBM/fp-go/v2/internal/array"
|
||||
S "github.com/IBM/fp-go/v2/semigroup"
|
||||
)
|
||||
|
||||
// NonEmptyArray represents an array with at least one element
|
||||
type NonEmptyArray[A any] []A
|
||||
|
||||
// Of constructs a single element array
|
||||
func Of[A any](first A) NonEmptyArray[A] {
|
||||
return G.Of[NonEmptyArray[A]](first)
|
||||
}
|
||||
|
||||
// From constructs a [NonEmptyArray] from a set of variadic arguments
|
||||
func From[A any](first A, data ...A) NonEmptyArray[A] {
|
||||
count := len(data)
|
||||
if count == 0 {
|
||||
return Of(first)
|
||||
}
|
||||
// allocate the requested buffer
|
||||
buffer := make(NonEmptyArray[A], count+1)
|
||||
buffer[0] = first
|
||||
copy(buffer[1:], data)
|
||||
return buffer
|
||||
}
|
||||
|
||||
func IsEmpty[A any](_ NonEmptyArray[A]) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func IsNonEmpty[A any](_ NonEmptyArray[A]) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func MonadMap[A, B any](as NonEmptyArray[A], f func(a A) B) NonEmptyArray[B] {
|
||||
return G.MonadMap[NonEmptyArray[A], NonEmptyArray[B]](as, f)
|
||||
}
|
||||
|
||||
func Map[A, B any](f func(a A) B) func(NonEmptyArray[A]) NonEmptyArray[B] {
|
||||
return F.Bind2nd(MonadMap[A, B], f)
|
||||
}
|
||||
|
||||
func Reduce[A, B any](f func(B, A) B, initial B) func(NonEmptyArray[A]) B {
|
||||
return func(as NonEmptyArray[A]) B {
|
||||
return array.Reduce(as, f, initial)
|
||||
}
|
||||
}
|
||||
|
||||
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:]
|
||||
}
|
||||
|
||||
func Head[A any](as NonEmptyArray[A]) A {
|
||||
return as[0]
|
||||
}
|
||||
|
||||
func First[A any](as NonEmptyArray[A]) A {
|
||||
return as[0]
|
||||
}
|
||||
|
||||
func Last[A any](as NonEmptyArray[A]) A {
|
||||
return as[len(as)-1]
|
||||
}
|
||||
|
||||
func Size[A any](as NonEmptyArray[A]) int {
|
||||
return G.Size(as)
|
||||
}
|
||||
|
||||
func Flatten[A any](mma NonEmptyArray[NonEmptyArray[A]]) NonEmptyArray[A] {
|
||||
return G.Flatten(mma)
|
||||
}
|
||||
|
||||
func MonadChain[A, B any](fa NonEmptyArray[A], f func(a A) NonEmptyArray[B]) NonEmptyArray[B] {
|
||||
return G.MonadChain[NonEmptyArray[A], NonEmptyArray[B]](fa, f)
|
||||
}
|
||||
|
||||
func Chain[A, B any](f func(A) NonEmptyArray[B]) func(NonEmptyArray[A]) NonEmptyArray[B] {
|
||||
return G.Chain[NonEmptyArray[A], NonEmptyArray[B]](f)
|
||||
}
|
||||
|
||||
func MonadAp[B, A any](fab NonEmptyArray[func(A) B], fa NonEmptyArray[A]) NonEmptyArray[B] {
|
||||
return G.MonadAp[NonEmptyArray[B]](fab, fa)
|
||||
}
|
||||
|
||||
func Ap[B, A any](fa NonEmptyArray[A]) func(NonEmptyArray[func(A) B]) NonEmptyArray[B] {
|
||||
return G.Ap[NonEmptyArray[B], NonEmptyArray[func(A) B]](fa)
|
||||
}
|
||||
|
||||
// FoldMap maps and folds a [NonEmptyArray]. Map the [NonEmptyArray] passing each value to the iterating function. Then fold the results using the provided [Semigroup].
|
||||
func FoldMap[A, B any](s S.Semigroup[B]) func(func(A) B) func(NonEmptyArray[A]) B {
|
||||
return func(f func(A) B) func(NonEmptyArray[A]) B {
|
||||
return func(as NonEmptyArray[A]) B {
|
||||
return array.Reduce(Tail(as), func(cur B, a A) B {
|
||||
return s.Concat(cur, f(a))
|
||||
}, f(Head(as)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fold folds the [NonEmptyArray] using the provided [Semigroup].
|
||||
func Fold[A any](s S.Semigroup[A]) func(NonEmptyArray[A]) A {
|
||||
return func(as 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)
|
||||
}
|
58
v2/array/sequence.go
Normal file
58
v2/array/sequence.go
Normal file
@@ -0,0 +1,58 @@
|
||||
// Copyright (c) 2023 IBM Corp.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package array
|
||||
|
||||
import (
|
||||
F "github.com/IBM/fp-go/v2/function"
|
||||
O "github.com/IBM/fp-go/v2/option"
|
||||
)
|
||||
|
||||
// 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
|
||||
|
||||
// HKTA = HKT<A>
|
||||
// HKTRA = HKT<[]A>
|
||||
// HKTFRA = HKT<func(A)[]A>
|
||||
|
||||
// Sequence takes an `Array` where elements are `HKT<A>` (higher kinded type) and,
|
||||
// using an applicative of that `HKT`, returns an `HKT` of `[]A`.
|
||||
// e.g. it can turn an `[]Either[error, string]` into an `Either[error, []string]`.
|
||||
//
|
||||
// Sequence requires an `Applicative` of the `HKT` you are targeting, e.g. to turn an
|
||||
// `[]Either[E, A]` into an `Either[E, []A]`, it needs an
|
||||
// Applicative` for `Either`, to to turn an `[]Option[A]` into an `Option[ []A]`,
|
||||
// it needs an `Applicative` for `Option`.
|
||||
func Sequence[A, HKTA, HKTRA, HKTFRA any](
|
||||
_of func([]A) HKTRA,
|
||||
_map func(HKTRA, func([]A) func(A) []A) HKTFRA,
|
||||
_ap func(HKTFRA, HKTA) HKTRA,
|
||||
) func([]HKTA) HKTRA {
|
||||
ca := F.Curry2(Append[A])
|
||||
return Reduce(func(fas HKTRA, fa HKTA) HKTRA {
|
||||
return _ap(
|
||||
_map(fas, ca),
|
||||
fa,
|
||||
)
|
||||
}, _of(Empty[A]()))
|
||||
}
|
||||
|
||||
// ArrayOption returns a function to convert sequence of options into an option of a sequence
|
||||
func ArrayOption[A any]() func([]O.Option[A]) O.Option[[]A] {
|
||||
return Sequence(
|
||||
O.Of[[]A],
|
||||
O.MonadMap[[]A, func(A) []A],
|
||||
O.MonadAp[[]A, A],
|
||||
)
|
||||
}
|
31
v2/array/sequence_test.go
Normal file
31
v2/array/sequence_test.go
Normal file
@@ -0,0 +1,31 @@
|
||||
// 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"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
O "github.com/IBM/fp-go/v2/option"
|
||||
)
|
||||
|
||||
func TestSequenceOption(t *testing.T) {
|
||||
seq := ArrayOption[int]()
|
||||
|
||||
assert.Equal(t, O.Of([]int{1, 3}), seq([]O.Option[int]{O.Of(1), O.Of(3)}))
|
||||
assert.Equal(t, O.None[[]int](), seq([]O.Option[int]{O.Of(1), O.None[int]()}))
|
||||
}
|
36
v2/array/sort.go
Normal file
36
v2/array/sort.go
Normal file
@@ -0,0 +1,36 @@
|
||||
// Copyright (c) 2023 IBM Corp.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package array
|
||||
|
||||
import (
|
||||
G "github.com/IBM/fp-go/v2/array/generic"
|
||||
O "github.com/IBM/fp-go/v2/ord"
|
||||
)
|
||||
|
||||
// Sort implements a stable sort on the array given the provided ordering
|
||||
func Sort[T any](ord O.Ord[T]) func(ma []T) []T {
|
||||
return G.Sort[[]T](ord)
|
||||
}
|
||||
|
||||
// SortByKey implements a stable sort on the array given the provided ordering on an extracted key
|
||||
func SortByKey[K, T any](ord O.Ord[K], f func(T) K) func(ma []T) []T {
|
||||
return G.SortByKey[[]T](ord, f)
|
||||
}
|
||||
|
||||
// SortBy implements a stable sort on the array given the provided ordering
|
||||
func SortBy[T any](ord []O.Ord[T]) func(ma []T) []T {
|
||||
return G.SortBy[[]T, []O.Ord[T]](ord)
|
||||
}
|
36
v2/array/sort_test.go
Normal file
36
v2/array/sort_test.go
Normal file
@@ -0,0 +1,36 @@
|
||||
// Copyright (c) 2023 IBM Corp.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package array
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
O "github.com/IBM/fp-go/v2/ord"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestSort(t *testing.T) {
|
||||
|
||||
ordInt := O.FromStrictCompare[int]()
|
||||
|
||||
input := []int{2, 1, 3}
|
||||
|
||||
res := Sort(ordInt)(input)
|
||||
|
||||
assert.Equal(t, []int{1, 2, 3}, res)
|
||||
assert.Equal(t, []int{2, 1, 3}, input)
|
||||
|
||||
}
|
74
v2/array/testing/laws.go
Normal file
74
v2/array/testing/laws.go
Normal file
@@ -0,0 +1,74 @@
|
||||
// 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/v2/array"
|
||||
EQ "github.com/IBM/fp-go/v2/eq"
|
||||
L "github.com/IBM/fp-go/v2/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,
|
||||
)
|
||||
|
||||
}
|
47
v2/array/testing/laws_test.go
Normal file
47
v2/array/testing/laws_test.go
Normal file
@@ -0,0 +1,47 @@
|
||||
// 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/v2/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))
|
||||
}
|
40
v2/array/traverse.go
Normal file
40
v2/array/traverse.go
Normal file
@@ -0,0 +1,40 @@
|
||||
// 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 (
|
||||
"github.com/IBM/fp-go/v2/internal/array"
|
||||
)
|
||||
|
||||
func Traverse[A, B, HKTB, HKTAB, HKTRB any](
|
||||
fof func([]B) HKTRB,
|
||||
fmap func(func([]B) func(B) []B) func(HKTRB) HKTAB,
|
||||
fap func(HKTB) func(HKTAB) HKTRB,
|
||||
|
||||
f func(A) HKTB) func([]A) HKTRB {
|
||||
return array.Traverse[[]A](fof, fmap, fap, f)
|
||||
}
|
||||
|
||||
func MonadTraverse[A, B, HKTB, HKTAB, HKTRB any](
|
||||
fof func([]B) HKTRB,
|
||||
fmap func(func([]B) func(B) []B) func(HKTRB) HKTAB,
|
||||
fap func(HKTB) func(HKTAB) HKTRB,
|
||||
|
||||
ta []A,
|
||||
f func(A) HKTB) HKTRB {
|
||||
|
||||
return array.MonadTraverse(fof, fmap, fap, ta, f)
|
||||
}
|
43
v2/array/traverse_test.go
Normal file
43
v2/array/traverse_test.go
Normal file
@@ -0,0 +1,43 @@
|
||||
// Copyright (c) 2023 IBM Corp.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package array
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
O "github.com/IBM/fp-go/v2/option"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
type ArrayType = []int
|
||||
|
||||
func TestTraverse(t *testing.T) {
|
||||
|
||||
traverse := Traverse(
|
||||
O.Of[ArrayType],
|
||||
O.Map[ArrayType, func(int) ArrayType],
|
||||
O.Ap[ArrayType, int],
|
||||
|
||||
func(n int) O.Option[int] {
|
||||
if n%2 == 0 {
|
||||
return O.None[int]()
|
||||
}
|
||||
return O.Of(n)
|
||||
})
|
||||
|
||||
assert.Equal(t, O.None[[]int](), traverse(ArrayType{1, 2}))
|
||||
assert.Equal(t, O.Of(ArrayType{1, 3}), traverse(ArrayType{1, 3}))
|
||||
}
|
17
v2/array/uniq.go
Normal file
17
v2/array/uniq.go
Normal file
@@ -0,0 +1,17 @@
|
||||
package array
|
||||
|
||||
import (
|
||||
G "github.com/IBM/fp-go/v2/array/generic"
|
||||
)
|
||||
|
||||
// StrictUniq converts an array of arbitrary items into an array or unique items
|
||||
// where uniqueness is determined by the built-in uniqueness constraint
|
||||
func StrictUniq[A comparable](as []A) []A {
|
||||
return G.StrictUniq[[]A](as)
|
||||
}
|
||||
|
||||
// Uniq converts an array of arbitrary items into an array or unique items
|
||||
// where uniqueness is determined based on a key extractor function
|
||||
func Uniq[A any, K comparable](f func(A) K) func(as []A) []A {
|
||||
return G.Uniq[[]A](f)
|
||||
}
|
14
v2/array/uniq_test.go
Normal file
14
v2/array/uniq_test.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package array
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestUniq(t *testing.T) {
|
||||
data := From(1, 2, 3, 2, 4, 1)
|
||||
|
||||
uniq := StrictUniq(data)
|
||||
assert.Equal(t, From(1, 2, 3, 4), uniq)
|
||||
}
|
38
v2/array/zip.go
Normal file
38
v2/array/zip.go
Normal file
@@ -0,0 +1,38 @@
|
||||
// Copyright (c) 2023 IBM Corp.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package array
|
||||
|
||||
import (
|
||||
G "github.com/IBM/fp-go/v2/array/generic"
|
||||
T "github.com/IBM/fp-go/v2/tuple"
|
||||
)
|
||||
|
||||
// ZipWith applies a function to pairs of elements at the same index in two arrays, collecting the results in a new array. If one
|
||||
// input array is short, excess elements of the longer array are discarded.
|
||||
func ZipWith[FCT ~func(A, B) C, A, B, C any](fa []A, fb []B, f FCT) []C {
|
||||
return G.ZipWith[[]A, []B, []C, FCT](fa, fb, f)
|
||||
}
|
||||
|
||||
// Zip takes two arrays and returns an array of corresponding pairs. If one input array is short, excess elements of the
|
||||
// longer array are discarded
|
||||
func Zip[A, B any](fb []B) func([]A) []T.Tuple2[A, B] {
|
||||
return G.Zip[[]A, []B, []T.Tuple2[A, B]](fb)
|
||||
}
|
||||
|
||||
// Unzip is the function is reverse of [Zip]. Takes an array of pairs and return two corresponding arrays
|
||||
func Unzip[A, B any](cs []T.Tuple2[A, B]) T.Tuple2[[]A, []B] {
|
||||
return G.Unzip[[]A, []B, []T.Tuple2[A, B]](cs)
|
||||
}
|
56
v2/array/zip_test.go
Normal file
56
v2/array/zip_test.go
Normal file
@@ -0,0 +1,56 @@
|
||||
// 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 (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
T "github.com/IBM/fp-go/v2/tuple"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestZipWith(t *testing.T) {
|
||||
left := From(1, 2, 3)
|
||||
right := From("a", "b", "c", "d")
|
||||
|
||||
res := ZipWith(left, right, func(l int, r string) string {
|
||||
return fmt.Sprintf("%s%d", r, l)
|
||||
})
|
||||
|
||||
assert.Equal(t, From("a1", "b2", "c3"), res)
|
||||
}
|
||||
|
||||
func TestZip(t *testing.T) {
|
||||
left := From(1, 2, 3)
|
||||
right := From("a", "b", "c", "d")
|
||||
|
||||
res := Zip[string](left)(right)
|
||||
|
||||
assert.Equal(t, From(T.MakeTuple2("a", 1), T.MakeTuple2("b", 2), T.MakeTuple2("c", 3)), res)
|
||||
}
|
||||
|
||||
func TestUnzip(t *testing.T) {
|
||||
left := From(1, 2, 3)
|
||||
right := From("a", "b", "c")
|
||||
|
||||
zipped := Zip[string](left)(right)
|
||||
|
||||
unzipped := Unzip(zipped)
|
||||
|
||||
assert.Equal(t, right, unzipped.F1)
|
||||
assert.Equal(t, left, unzipped.F2)
|
||||
}
|
109
v2/assert/assert_test.go
Normal file
109
v2/assert/assert_test.go
Normal file
@@ -0,0 +1,109 @@
|
||||
// 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 assert
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
E "github.com/IBM/fp-go/v2/either"
|
||||
EQ "github.com/IBM/fp-go/v2/eq"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var (
|
||||
errTest = fmt.Errorf("test failure")
|
||||
|
||||
// Eq is the equal predicate checking if objects are equal
|
||||
Eq = EQ.FromEquals(assert.ObjectsAreEqual)
|
||||
)
|
||||
|
||||
func wrap1[T any](wrapped func(t assert.TestingT, expected, actual any, msgAndArgs ...any) bool, t *testing.T, expected T) func(actual T) E.Either[error, T] {
|
||||
return func(actual T) E.Either[error, T] {
|
||||
ok := wrapped(t, expected, actual)
|
||||
if ok {
|
||||
return E.Of[error](actual)
|
||||
}
|
||||
return E.Left[T](errTest)
|
||||
}
|
||||
}
|
||||
|
||||
// NotEqual tests if the expected and the actual values are not equal
|
||||
func NotEqual[T any](t *testing.T, expected T) func(actual T) E.Either[error, T] {
|
||||
return wrap1(assert.NotEqual, t, expected)
|
||||
}
|
||||
|
||||
// Equal tests if the expected and the actual values are equal
|
||||
func Equal[T any](t *testing.T, expected T) func(actual T) E.Either[error, T] {
|
||||
return wrap1(assert.Equal, t, expected)
|
||||
}
|
||||
|
||||
// Length tests if an array has the expected length
|
||||
func Length[T any](t *testing.T, expected int) func(actual []T) E.Either[error, []T] {
|
||||
return func(actual []T) E.Either[error, []T] {
|
||||
ok := assert.Len(t, actual, expected)
|
||||
if ok {
|
||||
return E.Of[error](actual)
|
||||
}
|
||||
return E.Left[[]T](errTest)
|
||||
}
|
||||
}
|
||||
|
||||
// NoError validates that there is no error
|
||||
func NoError[T any](t *testing.T) func(actual E.Either[error, T]) E.Either[error, T] {
|
||||
return func(actual E.Either[error, T]) E.Either[error, T] {
|
||||
return E.MonadFold(actual, func(e error) E.Either[error, T] {
|
||||
assert.NoError(t, e)
|
||||
return E.Left[T](e)
|
||||
}, func(value T) E.Either[error, T] {
|
||||
assert.NoError(t, nil)
|
||||
return E.Right[error](value)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// ArrayContains tests if a value is contained in an array
|
||||
func ArrayContains[T any](t *testing.T, expected T) func(actual []T) E.Either[error, []T] {
|
||||
return func(actual []T) E.Either[error, []T] {
|
||||
ok := assert.Contains(t, actual, expected)
|
||||
if ok {
|
||||
return E.Of[error](actual)
|
||||
}
|
||||
return E.Left[[]T](errTest)
|
||||
}
|
||||
}
|
||||
|
||||
// ContainsKey tests if a key is contained in a map
|
||||
func ContainsKey[T any, K comparable](t *testing.T, expected K) func(actual map[K]T) E.Either[error, map[K]T] {
|
||||
return func(actual map[K]T) E.Either[error, map[K]T] {
|
||||
ok := assert.Contains(t, actual, expected)
|
||||
if ok {
|
||||
return E.Of[error](actual)
|
||||
}
|
||||
return E.Left[map[K]T](errTest)
|
||||
}
|
||||
}
|
||||
|
||||
// NotContainsKey tests if a key is not contained in a map
|
||||
func NotContainsKey[T any, K comparable](t *testing.T, expected K) func(actual map[K]T) E.Either[error, map[K]T] {
|
||||
return func(actual map[K]T) E.Either[error, map[K]T] {
|
||||
ok := assert.NotContains(t, actual, expected)
|
||||
if ok {
|
||||
return E.Of[error](actual)
|
||||
}
|
||||
return E.Left[map[K]T](errTest)
|
||||
}
|
||||
}
|
59
v2/boolean/boolean.go
Normal file
59
v2/boolean/boolean.go
Normal file
@@ -0,0 +1,59 @@
|
||||
// Copyright (c) 2023 IBM Corp.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package boolean
|
||||
|
||||
import (
|
||||
"github.com/IBM/fp-go/v2/eq"
|
||||
"github.com/IBM/fp-go/v2/monoid"
|
||||
"github.com/IBM/fp-go/v2/ord"
|
||||
)
|
||||
|
||||
var (
|
||||
// MonoidAny is the boolean [monoid.Monoid] under disjunction
|
||||
MonoidAny = monoid.MakeMonoid(
|
||||
func(l, r bool) bool {
|
||||
return l || r
|
||||
},
|
||||
false,
|
||||
)
|
||||
|
||||
// MonoidAll is the boolean [monoid.Monoid] under conjuction
|
||||
MonoidAll = monoid.MakeMonoid(
|
||||
func(l, r bool) bool {
|
||||
return l && r
|
||||
},
|
||||
true,
|
||||
)
|
||||
|
||||
// Eq is the equals predicate for boolean
|
||||
Eq = eq.FromStrictEquals[bool]()
|
||||
|
||||
// Ord is the strict ordering for boolean
|
||||
Ord = ord.MakeOrd(func(l, r bool) int {
|
||||
if l {
|
||||
if r {
|
||||
return 0
|
||||
}
|
||||
return +1
|
||||
}
|
||||
if r {
|
||||
return -1
|
||||
}
|
||||
return 0
|
||||
}, func(l, r bool) bool {
|
||||
return l == r
|
||||
})
|
||||
)
|
22
v2/boolean/types.go
Normal file
22
v2/boolean/types.go
Normal file
@@ -0,0 +1,22 @@
|
||||
// Copyright (c) 2023 IBM Corp.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package boolean
|
||||
|
||||
import "github.com/IBM/fp-go/v2/monoid"
|
||||
|
||||
type (
|
||||
Monoid = monoid.Monoid[bool]
|
||||
)
|
62
v2/bounded/bounded.go
Normal file
62
v2/bounded/bounded.go
Normal file
@@ -0,0 +1,62 @@
|
||||
// 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 bounded
|
||||
|
||||
import "github.com/IBM/fp-go/v2/ord"
|
||||
|
||||
type Bounded[T any] interface {
|
||||
ord.Ord[T]
|
||||
Top() T
|
||||
Bottom() T
|
||||
}
|
||||
|
||||
type bounded[T any] struct {
|
||||
c func(x, y T) int
|
||||
e func(x, y T) bool
|
||||
t T
|
||||
b T
|
||||
}
|
||||
|
||||
func (b bounded[T]) Equals(x, y T) bool {
|
||||
return b.e(x, y)
|
||||
}
|
||||
|
||||
func (b bounded[T]) Compare(x, y T) int {
|
||||
return b.c(x, y)
|
||||
}
|
||||
|
||||
func (b bounded[T]) Top() T {
|
||||
return b.t
|
||||
}
|
||||
|
||||
func (b bounded[T]) Bottom() T {
|
||||
return b.b
|
||||
}
|
||||
|
||||
// MakeBounded creates an instance of a bounded type
|
||||
func MakeBounded[T any](o ord.Ord[T], t, b T) Bounded[T] {
|
||||
return bounded[T]{c: o.Compare, e: o.Equals, t: t, b: b}
|
||||
}
|
||||
|
||||
// Clamp returns a function that clamps against the bounds defined in the bounded type
|
||||
func Clamp[T any](b Bounded[T]) func(T) T {
|
||||
return ord.Clamp[T](b)(b.Bottom(), b.Top())
|
||||
}
|
||||
|
||||
// Reverse reverses the ordering and swaps the bounds
|
||||
func Reverse[T any](b Bounded[T]) Bounded[T] {
|
||||
return MakeBounded(ord.Reverse(b), b.Bottom(), b.Top())
|
||||
}
|
28
v2/bytes/bytes.go
Normal file
28
v2/bytes/bytes.go
Normal file
@@ -0,0 +1,28 @@
|
||||
// Copyright (c) 2023 IBM Corp.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package bytes
|
||||
|
||||
func Empty() []byte {
|
||||
return Monoid.Empty()
|
||||
}
|
||||
|
||||
func ToString(a []byte) string {
|
||||
return string(a)
|
||||
}
|
||||
|
||||
func Size(as []byte) int {
|
||||
return len(as)
|
||||
}
|
34
v2/bytes/monoid.go
Normal file
34
v2/bytes/monoid.go
Normal file
@@ -0,0 +1,34 @@
|
||||
// Copyright (c) 2023 IBM Corp.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package bytes
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
||||
A "github.com/IBM/fp-go/v2/array"
|
||||
O "github.com/IBM/fp-go/v2/ord"
|
||||
)
|
||||
|
||||
var (
|
||||
// monoid for byte arrays
|
||||
Monoid = A.Monoid[byte]()
|
||||
|
||||
// ConcatAll concatenates all bytes
|
||||
ConcatAll = A.ArrayConcatAll[byte]
|
||||
|
||||
// Ord implements the default ordering on bytes
|
||||
Ord = O.MakeOrd(bytes.Compare, bytes.Equal)
|
||||
)
|
26
v2/bytes/monoid_test.go
Normal file
26
v2/bytes/monoid_test.go
Normal file
@@ -0,0 +1,26 @@
|
||||
// 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 bytes
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
M "github.com/IBM/fp-go/v2/monoid/testing"
|
||||
)
|
||||
|
||||
func TestMonoid(t *testing.T) {
|
||||
M.AssertLaws(t, Monoid)([][]byte{[]byte(""), []byte("a"), []byte("some value")})
|
||||
}
|
432
v2/cli/apply.go
Normal file
432
v2/cli/apply.go
Normal file
@@ -0,0 +1,432 @@
|
||||
// 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 generateTraverseTuple(f *os.File, i int) {
|
||||
fmt.Fprintf(f, "\n// TraverseTuple%d is a utility function used to implement the sequence operation for higher kinded types based only on map and ap.\n", i)
|
||||
fmt.Fprintf(f, "// The function takes a [Tuple%d] of base types and %d functions that transform these based types into higher higher kinded types. It returns a higher kinded type of a [Tuple%d] with the resolved values.\n", i, i, i)
|
||||
fmt.Fprintf(f, "func TraverseTuple%d[\n", i)
|
||||
// map as the starting point
|
||||
fmt.Fprintf(f, " MAP ~func(")
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(f, " ")
|
||||
}
|
||||
fmt.Fprintf(f, "func(T%d)", j+1)
|
||||
}
|
||||
fmt.Fprintf(f, " ")
|
||||
fmt.Fprintf(f, "T.")
|
||||
writeTupleType(f, "T", i)
|
||||
fmt.Fprintf(f, ") func(HKT_T1)")
|
||||
if i > 1 {
|
||||
fmt.Fprintf(f, " HKT_F")
|
||||
for k := 1; k < i; k++ {
|
||||
fmt.Fprintf(f, "_T%d", k+1)
|
||||
}
|
||||
} else {
|
||||
fmt.Fprintf(f, " HKT_TUPLE%d", i)
|
||||
}
|
||||
fmt.Fprintf(f, ",\n")
|
||||
// the applicatives
|
||||
for j := 1; j < i; j++ {
|
||||
fmt.Fprintf(f, " AP%d ~func(", j)
|
||||
fmt.Fprintf(f, "HKT_T%d) func(", j+1)
|
||||
fmt.Fprintf(f, "HKT_F")
|
||||
for k := j; k < i; k++ {
|
||||
fmt.Fprintf(f, "_T%d", k+1)
|
||||
}
|
||||
fmt.Fprintf(f, ")")
|
||||
if j+1 < i {
|
||||
fmt.Fprintf(f, " HKT_F")
|
||||
for k := j + 1; k < i; k++ {
|
||||
fmt.Fprintf(f, "_T%d", k+1)
|
||||
}
|
||||
} else {
|
||||
fmt.Fprintf(f, " HKT_TUPLE%d", i)
|
||||
}
|
||||
fmt.Fprintf(f, ",\n")
|
||||
}
|
||||
for j := 0; j < i; j++ {
|
||||
fmt.Fprintf(f, " F%d ~func(A%d) HKT_T%d,\n", j+1, j+1, j+1)
|
||||
}
|
||||
for j := 0; j < i; j++ {
|
||||
fmt.Fprintf(f, " A%d, T%d,\n", j+1, j+1)
|
||||
}
|
||||
for j := 0; j < i; j++ {
|
||||
fmt.Fprintf(f, " HKT_T%d, // HKT[T%d]\n", j+1, j+1)
|
||||
}
|
||||
for j := 1; j < i; j++ {
|
||||
fmt.Fprintf(f, " HKT_F")
|
||||
for k := j; k < i; k++ {
|
||||
fmt.Fprintf(f, "_T%d", k+1)
|
||||
}
|
||||
fmt.Fprintf(f, ", // HKT[")
|
||||
for k := j; k < i; k++ {
|
||||
fmt.Fprintf(f, "func(T%d) ", k+1)
|
||||
}
|
||||
fmt.Fprintf(f, "T.")
|
||||
writeTupleType(f, "T", i)
|
||||
fmt.Fprintf(f, "]\n")
|
||||
}
|
||||
fmt.Fprintf(f, " HKT_TUPLE%d any, // HKT[", i)
|
||||
writeTupleType(f, "T", i)
|
||||
fmt.Fprintf(f, "]\n")
|
||||
fmt.Fprintf(f, "](\n")
|
||||
|
||||
// the callbacks
|
||||
fmt.Fprintf(f, " fmap MAP,\n")
|
||||
for j := 1; j < i; j++ {
|
||||
fmt.Fprintf(f, " fap%d AP%d,\n", j, j)
|
||||
}
|
||||
// the transformer functions
|
||||
for j := 1; j <= i; j++ {
|
||||
fmt.Fprintf(f, " f%d F%d,\n", j, j)
|
||||
}
|
||||
// the parameters
|
||||
fmt.Fprintf(f, " t T.Tuple%d[", i)
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "A%d", j+1)
|
||||
}
|
||||
fmt.Fprintf(f, "],\n")
|
||||
fmt.Fprintf(f, ") HKT_TUPLE%d {\n", i)
|
||||
|
||||
fmt.Fprintf(f, " return F.Pipe%d(\n", i)
|
||||
fmt.Fprintf(f, " f1(t.F1),\n")
|
||||
fmt.Fprintf(f, " fmap(tupleConstructor%d[", i)
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "T%d", j+1)
|
||||
}
|
||||
fmt.Fprintf(f, "]()),\n")
|
||||
for j := 1; j < i; j++ {
|
||||
fmt.Fprintf(f, " fap%d(f%d(t.F%d)),\n", j, j+1, j+1)
|
||||
}
|
||||
fmt.Fprintf(f, ")\n")
|
||||
fmt.Fprintf(f, "}\n")
|
||||
}
|
||||
|
||||
func generateSequenceTuple(f *os.File, i int) {
|
||||
fmt.Fprintf(f, "\n// SequenceTuple%d is a utility function used to implement the sequence operation for higher kinded types based only on map and ap.\n", i)
|
||||
fmt.Fprintf(f, "// The function takes a [Tuple%d] of higher higher kinded types and returns a higher kinded type of a [Tuple%d] with the resolved values.\n", i, i)
|
||||
fmt.Fprintf(f, "func SequenceTuple%d[\n", i)
|
||||
// map as the starting point
|
||||
fmt.Fprintf(f, " MAP ~func(")
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(f, " ")
|
||||
}
|
||||
fmt.Fprintf(f, "func(T%d)", j+1)
|
||||
}
|
||||
fmt.Fprintf(f, " ")
|
||||
fmt.Fprintf(f, "T.")
|
||||
writeTupleType(f, "T", i)
|
||||
fmt.Fprintf(f, ") func(HKT_T1)")
|
||||
if i > 1 {
|
||||
fmt.Fprintf(f, " HKT_F")
|
||||
for k := 1; k < i; k++ {
|
||||
fmt.Fprintf(f, "_T%d", k+1)
|
||||
}
|
||||
} else {
|
||||
fmt.Fprintf(f, " HKT_TUPLE%d", i)
|
||||
}
|
||||
fmt.Fprintf(f, ",\n")
|
||||
// the applicatives
|
||||
for j := 1; j < i; j++ {
|
||||
fmt.Fprintf(f, " AP%d ~func(", j)
|
||||
fmt.Fprintf(f, "HKT_T%d) func(", j+1)
|
||||
fmt.Fprintf(f, "HKT_F")
|
||||
for k := j; k < i; k++ {
|
||||
fmt.Fprintf(f, "_T%d", k+1)
|
||||
}
|
||||
fmt.Fprintf(f, ")")
|
||||
if j+1 < i {
|
||||
fmt.Fprintf(f, " HKT_F")
|
||||
for k := j + 1; k < i; k++ {
|
||||
fmt.Fprintf(f, "_T%d", k+1)
|
||||
}
|
||||
} else {
|
||||
fmt.Fprintf(f, " HKT_TUPLE%d", i)
|
||||
}
|
||||
fmt.Fprintf(f, ",\n")
|
||||
}
|
||||
|
||||
for j := 0; j < i; j++ {
|
||||
fmt.Fprintf(f, " T%d,\n", j+1)
|
||||
}
|
||||
for j := 0; j < i; j++ {
|
||||
fmt.Fprintf(f, " HKT_T%d, // HKT[T%d]\n", j+1, j+1)
|
||||
}
|
||||
for j := 1; j < i; j++ {
|
||||
fmt.Fprintf(f, " HKT_F")
|
||||
for k := j; k < i; k++ {
|
||||
fmt.Fprintf(f, "_T%d", k+1)
|
||||
}
|
||||
fmt.Fprintf(f, ", // HKT[")
|
||||
for k := j; k < i; k++ {
|
||||
fmt.Fprintf(f, "func(T%d) ", k+1)
|
||||
}
|
||||
fmt.Fprintf(f, "T.")
|
||||
writeTupleType(f, "T", i)
|
||||
fmt.Fprintf(f, "]\n")
|
||||
}
|
||||
fmt.Fprintf(f, " HKT_TUPLE%d any, // HKT[", i)
|
||||
writeTupleType(f, "T", i)
|
||||
fmt.Fprintf(f, "]\n")
|
||||
fmt.Fprintf(f, "](\n")
|
||||
|
||||
// the callbacks
|
||||
fmt.Fprintf(f, " fmap MAP,\n")
|
||||
for j := 1; j < i; j++ {
|
||||
fmt.Fprintf(f, " fap%d AP%d,\n", j, j)
|
||||
}
|
||||
// the parameters
|
||||
fmt.Fprintf(f, " t T.Tuple%d[", i)
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "HKT_T%d", j+1)
|
||||
}
|
||||
fmt.Fprintf(f, "],\n")
|
||||
fmt.Fprintf(f, ") HKT_TUPLE%d {\n", i)
|
||||
|
||||
fmt.Fprintf(f, " return F.Pipe%d(\n", i)
|
||||
fmt.Fprintf(f, " t.F1,\n")
|
||||
fmt.Fprintf(f, " fmap(tupleConstructor%d[", i)
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "T%d", j+1)
|
||||
}
|
||||
fmt.Fprintf(f, "]()),\n")
|
||||
for j := 1; j < i; j++ {
|
||||
fmt.Fprintf(f, " fap%d(t.F%d),\n", j, j+1)
|
||||
}
|
||||
fmt.Fprintf(f, ")\n")
|
||||
fmt.Fprintf(f, "}\n")
|
||||
}
|
||||
|
||||
func generateSequenceT(f *os.File, i int) {
|
||||
fmt.Fprintf(f, "\n// SequenceT%d is a utility function used to implement the sequence operation for higher kinded types based only on map and ap.\n", i)
|
||||
fmt.Fprintf(f, "// The function takes %d higher higher kinded types and returns a higher kinded type of a [Tuple%d] with the resolved values.\n", i, i)
|
||||
fmt.Fprintf(f, "func SequenceT%d[\n", i)
|
||||
// map as the starting point
|
||||
fmt.Fprintf(f, " MAP ~func(")
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(f, " ")
|
||||
}
|
||||
fmt.Fprintf(f, "func(T%d)", j+1)
|
||||
}
|
||||
fmt.Fprintf(f, " ")
|
||||
fmt.Fprintf(f, "T.")
|
||||
writeTupleType(f, "T", i)
|
||||
fmt.Fprintf(f, ") func(HKT_T1)")
|
||||
if i > 1 {
|
||||
fmt.Fprintf(f, " HKT_F")
|
||||
for k := 1; k < i; k++ {
|
||||
fmt.Fprintf(f, "_T%d", k+1)
|
||||
}
|
||||
} else {
|
||||
fmt.Fprintf(f, " HKT_TUPLE%d", i)
|
||||
}
|
||||
fmt.Fprintf(f, ",\n")
|
||||
// the applicatives
|
||||
for j := 1; j < i; j++ {
|
||||
fmt.Fprintf(f, " AP%d ~func(", j)
|
||||
fmt.Fprintf(f, "HKT_T%d) func(", j+1)
|
||||
fmt.Fprintf(f, "HKT_F")
|
||||
for k := j; k < i; k++ {
|
||||
fmt.Fprintf(f, "_T%d", k+1)
|
||||
}
|
||||
fmt.Fprintf(f, ")")
|
||||
if j+1 < i {
|
||||
fmt.Fprintf(f, " HKT_F")
|
||||
for k := j + 1; k < i; k++ {
|
||||
fmt.Fprintf(f, "_T%d", k+1)
|
||||
}
|
||||
} else {
|
||||
fmt.Fprintf(f, " HKT_TUPLE%d", i)
|
||||
}
|
||||
fmt.Fprintf(f, ",\n")
|
||||
}
|
||||
|
||||
for j := 0; j < i; j++ {
|
||||
fmt.Fprintf(f, " T%d,\n", j+1)
|
||||
}
|
||||
for j := 0; j < i; j++ {
|
||||
fmt.Fprintf(f, " HKT_T%d, // HKT[T%d]\n", j+1, j+1)
|
||||
}
|
||||
for j := 1; j < i; j++ {
|
||||
fmt.Fprintf(f, " HKT_F")
|
||||
for k := j; k < i; k++ {
|
||||
fmt.Fprintf(f, "_T%d", k+1)
|
||||
}
|
||||
fmt.Fprintf(f, ", // HKT[")
|
||||
for k := j; k < i; k++ {
|
||||
fmt.Fprintf(f, "func(T%d) ", k+1)
|
||||
}
|
||||
fmt.Fprintf(f, "T.")
|
||||
writeTupleType(f, "T", i)
|
||||
fmt.Fprintf(f, "]\n")
|
||||
}
|
||||
fmt.Fprintf(f, " HKT_TUPLE%d any, // HKT[", i)
|
||||
writeTupleType(f, "T", i)
|
||||
fmt.Fprintf(f, "]\n")
|
||||
fmt.Fprintf(f, "](\n")
|
||||
|
||||
// the callbacks
|
||||
fmt.Fprintf(f, " fmap MAP,\n")
|
||||
for j := 1; j < i; j++ {
|
||||
fmt.Fprintf(f, " fap%d AP%d,\n", j, j)
|
||||
}
|
||||
// the parameters
|
||||
for j := 0; j < i; j++ {
|
||||
fmt.Fprintf(f, " t%d HKT_T%d,\n", j+1, j+1)
|
||||
}
|
||||
fmt.Fprintf(f, ") HKT_TUPLE%d {\n", i)
|
||||
|
||||
fmt.Fprintf(f, " return F.Pipe%d(\n", i)
|
||||
fmt.Fprintf(f, " t1,\n")
|
||||
fmt.Fprintf(f, " fmap(tupleConstructor%d[", i)
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "T%d", j+1)
|
||||
}
|
||||
fmt.Fprintf(f, "]()),\n")
|
||||
for j := 1; j < i; j++ {
|
||||
fmt.Fprintf(f, " fap%d(t%d),\n", j, j+1)
|
||||
}
|
||||
fmt.Fprintf(f, ")\n")
|
||||
fmt.Fprintf(f, "}\n")
|
||||
}
|
||||
|
||||
func generateTupleConstructor(f *os.File, i int) {
|
||||
// Create the optionize version
|
||||
fmt.Fprintf(f, "\n// tupleConstructor%d returns a curried version of [T.MakeTuple%d]\n", i, i)
|
||||
fmt.Fprintf(f, "func tupleConstructor%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]()")
|
||||
for j := 0; j < i; j++ {
|
||||
fmt.Fprintf(f, " func(T%d)", j+1)
|
||||
}
|
||||
fmt.Fprintf(f, " T.Tuple%d[", i)
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "T%d", j+1)
|
||||
}
|
||||
fmt.Fprintf(f, "] {\n")
|
||||
|
||||
fmt.Fprintf(f, " return F.Curry%d(T.MakeTuple%d[", i, i)
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "T%d", j+1)
|
||||
}
|
||||
fmt.Fprintf(f, "])\n")
|
||||
|
||||
fmt.Fprintf(f, "}\n")
|
||||
}
|
||||
|
||||
func generateApplyHelpers(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)
|
||||
|
||||
// print out some helpers
|
||||
fmt.Fprintf(f, `
|
||||
import (
|
||||
F "github.com/IBM/fp-go/v2/function"
|
||||
T "github.com/IBM/fp-go/v2/tuple"
|
||||
)
|
||||
`)
|
||||
|
||||
for i := 1; i <= count; i++ {
|
||||
// tuple constructor
|
||||
generateTupleConstructor(f, i)
|
||||
// sequenceT
|
||||
generateSequenceT(f, i)
|
||||
// sequenceTuple
|
||||
generateSequenceTuple(f, i)
|
||||
// traverseTuple
|
||||
generateTraverseTuple(f, i)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func ApplyCommand() *C.Command {
|
||||
return &C.Command{
|
||||
Name: "apply",
|
||||
Usage: "generate code for the sequence operations of apply",
|
||||
Flags: []C.Flag{
|
||||
flagCount,
|
||||
flagFilename,
|
||||
},
|
||||
Action: func(ctx *C.Context) error {
|
||||
return generateApplyHelpers(
|
||||
ctx.String(keyFilename),
|
||||
ctx.Int(keyCount),
|
||||
)
|
||||
},
|
||||
}
|
||||
}
|
294
v2/cli/bind.go
Normal file
294
v2/cli/bind.go
Normal file
@@ -0,0 +1,294 @@
|
||||
// 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 createCombinations(n int, all, prev []int) [][]int {
|
||||
l := len(prev)
|
||||
if l == n {
|
||||
return [][]int{prev}
|
||||
}
|
||||
var res [][]int
|
||||
for idx, val := range all {
|
||||
cpy := make([]int, l+1)
|
||||
copy(cpy, prev)
|
||||
cpy[l] = val
|
||||
|
||||
res = append(res, createCombinations(n, all[idx+1:], cpy)...)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func remaining(comb []int, total int) []int {
|
||||
var res []int
|
||||
mp := make(map[int]int)
|
||||
for _, idx := range comb {
|
||||
mp[idx] = idx
|
||||
}
|
||||
for i := 1; i <= total; i++ {
|
||||
_, ok := mp[i]
|
||||
if !ok {
|
||||
res = append(res, i)
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func generateCombSingleBind(f *os.File, comb [][]int, total int) {
|
||||
for _, c := range comb {
|
||||
// remaining indexes
|
||||
rem := remaining(c, total)
|
||||
|
||||
// bind function
|
||||
fmt.Fprintf(f, "\n// Bind")
|
||||
for _, idx := range c {
|
||||
fmt.Fprintf(f, "%d", idx)
|
||||
}
|
||||
fmt.Fprintf(f, "of%d takes a function with %d parameters and returns a new function with %d parameters that will bind these parameters to the positions [", total, total, len(c))
|
||||
for i, idx := range c {
|
||||
if i > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "%d", idx)
|
||||
}
|
||||
fmt.Fprintf(f, "] of the original function.\n// The return value of is a function with the remaining %d parameters at positions [", len(rem))
|
||||
for i, idx := range rem {
|
||||
if i > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "%d", idx)
|
||||
}
|
||||
fmt.Fprintf(f, "] of the original function.\n")
|
||||
fmt.Fprintf(f, "func Bind")
|
||||
for _, idx := range c {
|
||||
fmt.Fprintf(f, "%d", idx)
|
||||
}
|
||||
fmt.Fprintf(f, "of%d[F ~func(", total)
|
||||
for i := 0; i < total; i++ {
|
||||
if i > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "T%d", i+1)
|
||||
}
|
||||
fmt.Fprintf(f, ") R")
|
||||
for i := 0; i < total; i++ {
|
||||
fmt.Fprintf(f, ", T%d", i+1)
|
||||
}
|
||||
fmt.Fprintf(f, ", R any](f F) func(")
|
||||
for i, idx := range c {
|
||||
if i > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "T%d", idx)
|
||||
}
|
||||
fmt.Fprintf(f, ") func(")
|
||||
for i, idx := range rem {
|
||||
if i > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "T%d", idx)
|
||||
}
|
||||
fmt.Fprintf(f, ") R {\n")
|
||||
|
||||
fmt.Fprintf(f, " return func(")
|
||||
|
||||
for i, idx := range c {
|
||||
if i > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "t%d T%d", idx, idx)
|
||||
}
|
||||
fmt.Fprintf(f, ") func(")
|
||||
for i, idx := range rem {
|
||||
if i > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "T%d", idx)
|
||||
}
|
||||
fmt.Fprintf(f, ") R {\n")
|
||||
|
||||
fmt.Fprintf(f, " return func(")
|
||||
for i, idx := range rem {
|
||||
if i > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "t%d T%d", idx, idx)
|
||||
}
|
||||
fmt.Fprintf(f, ") R {\n")
|
||||
|
||||
fmt.Fprintf(f, " return f(")
|
||||
for i := 1; i <= total; i++ {
|
||||
if i > 1 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "t%d", i)
|
||||
}
|
||||
fmt.Fprintf(f, ")\n")
|
||||
|
||||
fmt.Fprintf(f, " }\n")
|
||||
fmt.Fprintf(f, " }\n")
|
||||
fmt.Fprintf(f, "}\n")
|
||||
|
||||
// ignore function
|
||||
fmt.Fprintf(f, "\n// Ignore")
|
||||
for _, idx := range c {
|
||||
fmt.Fprintf(f, "%d", idx)
|
||||
}
|
||||
fmt.Fprintf(f, "of%d takes a function with %d parameters and returns a new function with %d parameters that will ignore the values at positions [", total, len(rem), total)
|
||||
for i, idx := range c {
|
||||
if i > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "%d", idx)
|
||||
}
|
||||
fmt.Fprintf(f, "] and pass the remaining %d parameters to the original function\n", len(rem))
|
||||
fmt.Fprintf(f, "func Ignore")
|
||||
for _, idx := range c {
|
||||
fmt.Fprintf(f, "%d", idx)
|
||||
}
|
||||
fmt.Fprintf(f, "of%d[", total)
|
||||
// start with the undefined parameters
|
||||
for i, idx := range c {
|
||||
if i > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "T%d", idx)
|
||||
}
|
||||
if len(c) > 0 {
|
||||
fmt.Fprintf(f, " any, ")
|
||||
}
|
||||
fmt.Fprintf(f, "F ~func(")
|
||||
for i, idx := range rem {
|
||||
if i > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "T%d", idx)
|
||||
}
|
||||
fmt.Fprintf(f, ") R")
|
||||
for _, idx := range rem {
|
||||
fmt.Fprintf(f, ", T%d", idx)
|
||||
}
|
||||
fmt.Fprintf(f, ", R any](f F) func(")
|
||||
for i := 0; i < total; i++ {
|
||||
if i > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "T%d", i+1)
|
||||
}
|
||||
fmt.Fprintf(f, ") R {\n")
|
||||
|
||||
fmt.Fprintf(f, " return func(")
|
||||
for i := 0; i < total; i++ {
|
||||
if i > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "t%d T%d", i+1, i+1)
|
||||
}
|
||||
fmt.Fprintf(f, ") R {\n")
|
||||
fmt.Fprintf(f, " return f(")
|
||||
for i, idx := range rem {
|
||||
if i > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "t%d", idx)
|
||||
}
|
||||
fmt.Fprintf(f, ")\n")
|
||||
|
||||
fmt.Fprintf(f, " }\n")
|
||||
fmt.Fprintf(f, "}\n")
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func generateSingleBind(f *os.File, total int) {
|
||||
|
||||
fmt.Fprintf(f, "// Combinations for a total of %d arguments\n", total)
|
||||
|
||||
// construct the indexes
|
||||
all := make([]int, total)
|
||||
for i := 0; i < total; i++ {
|
||||
all[i] = i + 1
|
||||
}
|
||||
// for all permutations of a certain length
|
||||
for j := 0; j < total; j++ {
|
||||
// get combinations of that size
|
||||
comb := createCombinations(j+1, all, []int{})
|
||||
generateCombSingleBind(f, comb, total)
|
||||
}
|
||||
}
|
||||
|
||||
func generateBind(f *os.File, i int) {
|
||||
for j := 1; j < i; j++ {
|
||||
generateSingleBind(f, j)
|
||||
}
|
||||
}
|
||||
|
||||
func generateBindHelpers(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", pkg)
|
||||
|
||||
generateBind(f, count)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func BindCommand() *C.Command {
|
||||
return &C.Command{
|
||||
Name: "bind",
|
||||
Usage: "generate code for binder functions etc",
|
||||
Description: "Code generation for bind, etc",
|
||||
Flags: []C.Flag{
|
||||
flagCount,
|
||||
flagFilename,
|
||||
},
|
||||
Action: func(ctx *C.Context) error {
|
||||
return generateBindHelpers(
|
||||
ctx.String(keyFilename),
|
||||
ctx.Int(keyCount),
|
||||
)
|
||||
},
|
||||
}
|
||||
}
|
39
v2/cli/commands.go
Normal file
39
v2/cli/commands.go
Normal file
@@ -0,0 +1,39 @@
|
||||
// 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 (
|
||||
C "github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
func Commands() []*C.Command {
|
||||
return []*C.Command{
|
||||
PipeCommand(),
|
||||
IdentityCommand(),
|
||||
OptionCommand(),
|
||||
EitherCommand(),
|
||||
TupleCommand(),
|
||||
BindCommand(),
|
||||
ApplyCommand(),
|
||||
ContextReaderIOEitherCommand(),
|
||||
ReaderIOEitherCommand(),
|
||||
ReaderCommand(),
|
||||
IOEitherCommand(),
|
||||
IOCommand(),
|
||||
IOOptionCommand(),
|
||||
DICommand(),
|
||||
}
|
||||
}
|
39
v2/cli/common.go
Normal file
39
v2/cli/common.go
Normal file
@@ -0,0 +1,39 @@
|
||||
// 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 (
|
||||
C "github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
const (
|
||||
keyFilename = "filename"
|
||||
keyCount = "count"
|
||||
)
|
||||
|
||||
var (
|
||||
flagFilename = &C.StringFlag{
|
||||
Name: keyFilename,
|
||||
Value: "gen.go",
|
||||
Usage: "Name of the generated file",
|
||||
}
|
||||
|
||||
flagCount = &C.IntFlag{
|
||||
Name: keyCount,
|
||||
Value: 20,
|
||||
Usage: "Number of variations to create",
|
||||
}
|
||||
)
|
271
v2/cli/contextreaderioeither.go
Normal file
271
v2/cli/contextreaderioeither.go
Normal file
@@ -0,0 +1,271 @@
|
||||
// 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"
|
||||
"strings"
|
||||
|
||||
A "github.com/IBM/fp-go/v2/array"
|
||||
C "github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
// Deprecated:
|
||||
func generateNestedCallbacks(i, total int) string {
|
||||
var buf strings.Builder
|
||||
for j := i; j < total; j++ {
|
||||
if j > i {
|
||||
buf.WriteString(" ")
|
||||
}
|
||||
buf.WriteString(fmt.Sprintf("func(T%d)", j+1))
|
||||
}
|
||||
if i > 0 {
|
||||
buf.WriteString(" ")
|
||||
}
|
||||
buf.WriteString(tupleType("T")(total))
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func generateNestedCallbacksPlain(i, total int) string {
|
||||
fs := A.MakeBy(total-i, func(j int) string {
|
||||
return fmt.Sprintf("func(T%d)", j+i+1)
|
||||
})
|
||||
ts := A.Of(tupleTypePlain("T")(total))
|
||||
return joinAll(" ")(fs, ts)
|
||||
}
|
||||
|
||||
func generateContextReaderIOEitherEitherize(f, fg *os.File, i int) {
|
||||
// non generic version
|
||||
fmt.Fprintf(f, "\n// Eitherize%d converts a function with %d parameters returning a tuple into a function with %d parameters returning a [ReaderIOEither[R]]\n// The inverse function is [Uneitherize%d]\n", i, i, i, i)
|
||||
fmt.Fprintf(f, "func Eitherize%d[F ~func(context.Context", i)
|
||||
for j := 0; j < i; j++ {
|
||||
fmt.Fprintf(f, ", T%d", j)
|
||||
}
|
||||
fmt.Fprintf(f, ") (R, error)")
|
||||
for j := 0; j < i; j++ {
|
||||
fmt.Fprintf(f, ", T%d", j)
|
||||
}
|
||||
fmt.Fprintf(f, ", R any](f F) func(")
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "T%d", j)
|
||||
}
|
||||
fmt.Fprintf(f, ") ReaderIOEither[R] {\n")
|
||||
fmt.Fprintf(f, " return G.Eitherize%d[ReaderIOEither[R]](f)\n", i)
|
||||
fmt.Fprintln(f, "}")
|
||||
|
||||
// generic version
|
||||
fmt.Fprintf(fg, "\n// Eitherize%d converts a function with %d parameters returning a tuple into a function with %d parameters returning a [GRA]\n// The inverse function is [Uneitherize%d]\n", i, i, i, i)
|
||||
fmt.Fprintf(fg, "func Eitherize%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 F) func(")
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(fg, ", ")
|
||||
}
|
||||
fmt.Fprintf(fg, "T%d", j)
|
||||
}
|
||||
fmt.Fprintf(fg, ") GRA {\n")
|
||||
fmt.Fprintf(fg, " return RE.Eitherize%d[GRA](f)\n", i)
|
||||
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 nonGenericContextReaderIOEither(param string) string {
|
||||
return fmt.Sprintf("ReaderIOEither[%s]", param)
|
||||
}
|
||||
|
||||
var extrasContextReaderIOEither = A.Empty[string]()
|
||||
|
||||
func generateContextReaderIOEitherSequenceT(f *os.File, i int) {
|
||||
generateGenericSequenceT("", nonGenericContextReaderIOEither, extrasContextReaderIOEither)(f, i)
|
||||
generateGenericSequenceT("Seq", nonGenericContextReaderIOEither, extrasContextReaderIOEither)(f, i)
|
||||
generateGenericSequenceT("Par", nonGenericContextReaderIOEither, extrasContextReaderIOEither)(f, i)
|
||||
}
|
||||
|
||||
func generateContextReaderIOEitherSequenceTuple(f *os.File, i int) {
|
||||
generateGenericSequenceTuple("", nonGenericContextReaderIOEither, extrasContextReaderIOEither)(f, i)
|
||||
generateGenericSequenceTuple("Seq", nonGenericContextReaderIOEither, extrasContextReaderIOEither)(f, i)
|
||||
generateGenericSequenceTuple("Par", nonGenericContextReaderIOEither, extrasContextReaderIOEither)(f, i)
|
||||
}
|
||||
|
||||
func generateContextReaderIOEitherTraverseTuple(f *os.File, i int) {
|
||||
generateGenericTraverseTuple("", nonGenericContextReaderIOEither, extrasContextReaderIOEither)(f, i)
|
||||
generateGenericTraverseTuple("Seq", nonGenericContextReaderIOEither, extrasContextReaderIOEither)(f, i)
|
||||
generateGenericTraverseTuple("Par", nonGenericContextReaderIOEither, extrasContextReaderIOEither)(f, i)
|
||||
}
|
||||
|
||||
func generateContextReaderIOEitherHelpers(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()
|
||||
// construct subdirectory
|
||||
genFilename := filepath.Join("generic", filename)
|
||||
err = os.MkdirAll("generic", os.ModePerm)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fg, err := os.Create(filepath.Clean(genFilename))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer fg.Close()
|
||||
|
||||
// log
|
||||
log.Printf("Generating code in [%s] for package [%s] with [%d] repetitions ...", filename, pkg, count)
|
||||
|
||||
writePackage(f, pkg)
|
||||
|
||||
fmt.Fprintf(f, `
|
||||
import (
|
||||
"context"
|
||||
|
||||
G "github.com/IBM/fp-go/v2/context/%s/generic"
|
||||
"github.com/IBM/fp-go/v2/internal/apply"
|
||||
"github.com/IBM/fp-go/v2/tuple"
|
||||
)
|
||||
`, pkg)
|
||||
|
||||
writePackage(fg, "generic")
|
||||
|
||||
fmt.Fprintf(fg, `
|
||||
import (
|
||||
"context"
|
||||
|
||||
E "github.com/IBM/fp-go/v2/either"
|
||||
RE "github.com/IBM/fp-go/v2/readerioeither/generic"
|
||||
)
|
||||
`)
|
||||
|
||||
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, i)
|
||||
// sequenceTuple
|
||||
generateContextReaderIOEitherSequenceTuple(f, i)
|
||||
// traverseTuple
|
||||
generateContextReaderIOEitherTraverseTuple(f, i)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func ContextReaderIOEitherCommand() *C.Command {
|
||||
return &C.Command{
|
||||
Name: "contextreaderioeither",
|
||||
Usage: "generate code for ContextReaderIOEither",
|
||||
Flags: []C.Flag{
|
||||
flagCount,
|
||||
flagFilename,
|
||||
},
|
||||
Action: func(ctx *C.Context) error {
|
||||
return generateContextReaderIOEitherHelpers(
|
||||
ctx.String(keyFilename),
|
||||
ctx.Int(keyCount),
|
||||
)
|
||||
},
|
||||
}
|
||||
}
|
231
v2/cli/di.go
Normal file
231
v2/cli/di.go
Normal file
@@ -0,0 +1,231 @@
|
||||
// Copyright (c) 2023 IBM Corp.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package cli
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
C "github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
func generateMakeProvider(f *os.File, i int) {
|
||||
// non generic version
|
||||
fmt.Fprintf(f, "\n// MakeProvider%d creates a [DIE.Provider] for an [InjectionToken] from a function with %d dependencies\n", i, i)
|
||||
fmt.Fprintf(f, "func MakeProvider%d[", i)
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "T%d", j+1)
|
||||
}
|
||||
fmt.Fprintf(f, " any, R any](\n")
|
||||
fmt.Fprintf(f, " token InjectionToken[R],\n")
|
||||
for j := 0; j < i; j++ {
|
||||
fmt.Fprintf(f, " d%d Dependency[T%d],\n", j+1, j+1)
|
||||
}
|
||||
fmt.Fprintf(f, " f func(")
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "T%d", j+1)
|
||||
}
|
||||
fmt.Fprintf(f, ") IOE.IOEither[error, R],\n")
|
||||
fmt.Fprintf(f, ") DIE.Provider {\n")
|
||||
fmt.Fprint(f, " return DIE.MakeProvider(\n")
|
||||
fmt.Fprint(f, " token,\n")
|
||||
fmt.Fprintf(f, " MakeProviderFactory%d(\n", i)
|
||||
for j := 0; j < i; j++ {
|
||||
fmt.Fprintf(f, " d%d,\n", j+1)
|
||||
}
|
||||
fmt.Fprint(f, " f,\n")
|
||||
fmt.Fprint(f, " ))\n")
|
||||
fmt.Fprintf(f, "}\n")
|
||||
}
|
||||
|
||||
func generateMakeTokenWithDefault(f *os.File, i int) {
|
||||
// non generic version
|
||||
fmt.Fprintf(f, "\n// MakeTokenWithDefault%d creates an [InjectionToken] with a default implementation with %d dependencies\n", i, i)
|
||||
fmt.Fprintf(f, "func MakeTokenWithDefault%d[", i)
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "T%d", j+1)
|
||||
}
|
||||
fmt.Fprintf(f, " any, R any](\n")
|
||||
fmt.Fprintf(f, " name string,\n")
|
||||
for j := 0; j < i; j++ {
|
||||
fmt.Fprintf(f, " d%d Dependency[T%d],\n", j+1, j+1)
|
||||
}
|
||||
fmt.Fprintf(f, " f func(")
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "T%d", j+1)
|
||||
}
|
||||
fmt.Fprintf(f, ") IOE.IOEither[error, R],\n")
|
||||
fmt.Fprintf(f, ") InjectionToken[R] {\n")
|
||||
fmt.Fprintf(f, " return MakeTokenWithDefault[R](name, MakeProviderFactory%d(\n", i)
|
||||
for j := 0; j < i; j++ {
|
||||
fmt.Fprintf(f, " d%d,\n", j+1)
|
||||
}
|
||||
fmt.Fprint(f, " f,\n")
|
||||
fmt.Fprint(f, " ))\n")
|
||||
fmt.Fprintf(f, "}\n")
|
||||
}
|
||||
|
||||
func generateMakeProviderFactory(f *os.File, i int) {
|
||||
// non generic version
|
||||
fmt.Fprintf(f, "\n// MakeProviderFactory%d creates a [DIE.ProviderFactory] from a function with %d arguments and %d dependencies\n", i, i, i)
|
||||
fmt.Fprintf(f, "func MakeProviderFactory%d[", i)
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "T%d", j+1)
|
||||
}
|
||||
fmt.Fprintf(f, " any, R any](\n")
|
||||
for j := 0; j < i; j++ {
|
||||
fmt.Fprintf(f, " d%d Dependency[T%d],\n", j+1, j+1)
|
||||
}
|
||||
fmt.Fprintf(f, " f func(")
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "T%d", j+1)
|
||||
}
|
||||
fmt.Fprintf(f, ") IOE.IOEither[error, R],\n")
|
||||
fmt.Fprintf(f, ") DIE.ProviderFactory {\n")
|
||||
fmt.Fprint(f, " return DIE.MakeProviderFactory(\n")
|
||||
fmt.Fprint(f, " A.From[DIE.Dependency](\n")
|
||||
for j := 0; j < i; j++ {
|
||||
fmt.Fprintf(f, " d%d,\n", j+1)
|
||||
}
|
||||
fmt.Fprint(f, " ),\n")
|
||||
fmt.Fprintf(f, " eraseProviderFactory%d(\n", i)
|
||||
for j := 0; j < i; j++ {
|
||||
fmt.Fprintf(f, " d%d,\n", j+1)
|
||||
}
|
||||
fmt.Fprint(f, " f,\n")
|
||||
fmt.Fprint(f, " ),\n")
|
||||
fmt.Fprint(f, " )\n")
|
||||
fmt.Fprintf(f, "}\n")
|
||||
}
|
||||
|
||||
func generateEraseProviderFactory(f *os.File, i int) {
|
||||
// non generic version
|
||||
fmt.Fprintf(f, "\n// eraseProviderFactory%d creates a function that takes a variadic number of untyped arguments and from a function of %d strongly typed arguments and %d dependencies\n", i, i, i)
|
||||
fmt.Fprintf(f, "func eraseProviderFactory%d[", i)
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "T%d", j+1)
|
||||
}
|
||||
fmt.Fprintf(f, " any, R any](\n")
|
||||
for j := 0; j < i; j++ {
|
||||
fmt.Fprintf(f, " d%d Dependency[T%d],\n", j+1, j+1)
|
||||
}
|
||||
fmt.Fprintf(f, " f func(")
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "T%d", j+1)
|
||||
}
|
||||
fmt.Fprintf(f, ") IOE.IOEither[error, R]) func(params ...any) IOE.IOEither[error, any] {\n")
|
||||
fmt.Fprintf(f, " ft := eraseTuple(T.Tupled%d(f))\n", i)
|
||||
for j := 0; j < i; j++ {
|
||||
fmt.Fprintf(f, " t%d := lookupAt[T%d](%d, d%d)\n", j+1, j+1, j, j+1)
|
||||
}
|
||||
fmt.Fprint(f, " return func(params ...any) IOE.IOEither[error, any] {\n")
|
||||
fmt.Fprintf(f, " return ft(E.SequenceT%d(\n", i)
|
||||
for j := 0; j < i; j++ {
|
||||
fmt.Fprintf(f, " t%d(params),\n", j+1)
|
||||
}
|
||||
fmt.Fprint(f, " ))\n")
|
||||
fmt.Fprint(f, " }\n")
|
||||
fmt.Fprintf(f, "}\n")
|
||||
}
|
||||
|
||||
func generateDIHelpers(filename string, count int) error {
|
||||
dir, err := os.Getwd()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
absDir, err := filepath.Abs(dir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pkg := filepath.Base(absDir)
|
||||
f, err := os.Create(filepath.Clean(filename))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
// log
|
||||
log.Printf("Generating code in [%s] for package [%s] with [%d] repetitions ...", filename, pkg, count)
|
||||
|
||||
// some header
|
||||
fmt.Fprintln(f, "// Code generated by go generate; DO NOT EDIT.")
|
||||
fmt.Fprintln(f, "// This file was generated by robots at")
|
||||
fmt.Fprintf(f, "// %s\n\n", time.Now())
|
||||
|
||||
fmt.Fprintf(f, "package %s\n\n", pkg)
|
||||
|
||||
fmt.Fprint(f, `
|
||||
import (
|
||||
E "github.com/IBM/fp-go/v2/either"
|
||||
IOE "github.com/IBM/fp-go/v2/ioeither"
|
||||
T "github.com/IBM/fp-go/v2/tuple"
|
||||
A "github.com/IBM/fp-go/v2/array"
|
||||
DIE "github.com/IBM/fp-go/v2/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),
|
||||
)
|
||||
},
|
||||
}
|
||||
}
|
200
v2/cli/either.go
Normal file
200
v2/cli/either.go
Normal file
@@ -0,0 +1,200 @@
|
||||
// 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 eitherHKT(typeE string) func(typeA string) string {
|
||||
return func(typeA string) string {
|
||||
return fmt.Sprintf("Either[%s, %s]", typeE, typeA)
|
||||
}
|
||||
}
|
||||
|
||||
func generateEitherTraverseTuple(f *os.File, i int) {
|
||||
generateTraverseTuple1(eitherHKT("E"), "E")(f, i)
|
||||
}
|
||||
|
||||
func generateEitherSequenceTuple(f *os.File, i int) {
|
||||
generateSequenceTuple1(eitherHKT("E"), "E")(f, i)
|
||||
}
|
||||
|
||||
func generateEitherSequenceT(f *os.File, i int) {
|
||||
generateSequenceT1(eitherHKT("E"), "E")(f, i)
|
||||
}
|
||||
|
||||
func generateUneitherize(f *os.File, i int) {
|
||||
// Create the optionize version
|
||||
fmt.Fprintf(f, "\n// Uneitherize%d converts a function with %d parameters returning an Either into a function with %d parameters returning a tuple\n// The inverse function is [Eitherize%d]\n", i, i, i, 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, ") Either[error, R]")
|
||||
for j := 0; j < i; j++ {
|
||||
fmt.Fprintf(f, ", T%d", j)
|
||||
}
|
||||
fmt.Fprintf(f, ", R any](f F) func(")
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "T%d", j)
|
||||
}
|
||||
fmt.Fprintf(f, ") (R, error) {\n")
|
||||
fmt.Fprintf(f, " return func(")
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "t%d T%d", j, j)
|
||||
}
|
||||
fmt.Fprintf(f, ") (R, error) {\n")
|
||||
fmt.Fprintf(f, " return UnwrapError(f(")
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "t%d", j)
|
||||
}
|
||||
fmt.Fprintln(f, "))")
|
||||
fmt.Fprintln(f, " }")
|
||||
fmt.Fprintln(f, "}")
|
||||
}
|
||||
|
||||
func generateEitherize(f *os.File, i int) {
|
||||
// Create the optionize version
|
||||
fmt.Fprintf(f, "\n// Eitherize%d converts a function with %d parameters returning a tuple into a function with %d parameters returning an Either\n// The inverse function is [Uneitherize%d]\n", i, i, i, i)
|
||||
fmt.Fprintf(f, "func Eitherize%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, ") (R, error)")
|
||||
for j := 0; j < i; j++ {
|
||||
fmt.Fprintf(f, ", T%d", j)
|
||||
}
|
||||
fmt.Fprintf(f, ", R any](f F) func(")
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "T%d", j)
|
||||
}
|
||||
fmt.Fprintf(f, ") Either[error, R] {\n")
|
||||
fmt.Fprintf(f, " return func(")
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "t%d T%d", j, j)
|
||||
}
|
||||
fmt.Fprintf(f, ") Either[error, R] {\n")
|
||||
fmt.Fprintf(f, " return TryCatchError(f(")
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "t%d", j)
|
||||
}
|
||||
fmt.Fprintln(f, "))")
|
||||
fmt.Fprintln(f, " }")
|
||||
fmt.Fprintln(f, "}")
|
||||
}
|
||||
|
||||
func generateEitherHelpers(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.Fprintf(f, `
|
||||
import (
|
||||
A "github.com/IBM/fp-go/v2/internal/apply"
|
||||
T "github.com/IBM/fp-go/v2/tuple"
|
||||
)
|
||||
`)
|
||||
|
||||
// zero level functions
|
||||
|
||||
// optionize
|
||||
generateEitherize(f, 0)
|
||||
// unoptionize
|
||||
generateUneitherize(f, 0)
|
||||
|
||||
for i := 1; i <= count; i++ {
|
||||
// optionize
|
||||
generateEitherize(f, i)
|
||||
// unoptionize
|
||||
generateUneitherize(f, i)
|
||||
// sequenceT
|
||||
generateEitherSequenceT(f, i)
|
||||
// sequenceTuple
|
||||
generateEitherSequenceTuple(f, i)
|
||||
// traverseTuple
|
||||
generateEitherTraverseTuple(f, i)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func EitherCommand() *C.Command {
|
||||
return &C.Command{
|
||||
Name: "either",
|
||||
Usage: "generate code for Either",
|
||||
Flags: []C.Flag{
|
||||
flagCount,
|
||||
flagFilename,
|
||||
},
|
||||
Action: func(ctx *C.Context) error {
|
||||
return generateEitherHelpers(
|
||||
ctx.String(keyFilename),
|
||||
ctx.Int(keyCount),
|
||||
)
|
||||
},
|
||||
}
|
||||
}
|
31
v2/cli/header.go
Normal file
31
v2/cli/header.go
Normal file
@@ -0,0 +1,31 @@
|
||||
// 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"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
func writePackage(f *os.File, pkg string) {
|
||||
// print package
|
||||
fmt.Fprintf(f, "package %s\n\n", pkg)
|
||||
// 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())
|
||||
}
|
103
v2/cli/identity.go
Normal file
103
v2/cli/identity.go
Normal file
@@ -0,0 +1,103 @@
|
||||
// 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 identityHKT(typeA string) string {
|
||||
return typeA
|
||||
}
|
||||
|
||||
func generateIdentityTraverseTuple(f *os.File, i int) {
|
||||
generateTraverseTuple1(identityHKT, "")(f, i)
|
||||
}
|
||||
|
||||
func generateIdentitySequenceTuple(f *os.File, i int) {
|
||||
generateSequenceTuple1(identityHKT, "")(f, i)
|
||||
}
|
||||
|
||||
func generateIdentitySequenceT(f *os.File, i int) {
|
||||
generateSequenceT1(identityHKT, "")(f, i)
|
||||
}
|
||||
|
||||
func generateIdentityHelpers(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.Fprintf(f, `
|
||||
import (
|
||||
A "github.com/IBM/fp-go/v2/internal/apply"
|
||||
T "github.com/IBM/fp-go/v2/tuple"
|
||||
)
|
||||
`)
|
||||
|
||||
for i := 1; i <= count; i++ {
|
||||
// sequenceT
|
||||
generateIdentitySequenceT(f, i)
|
||||
// sequenceTuple
|
||||
generateIdentitySequenceTuple(f, i)
|
||||
// traverseTuple
|
||||
generateIdentityTraverseTuple(f, i)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func IdentityCommand() *C.Command {
|
||||
return &C.Command{
|
||||
Name: "identity",
|
||||
Usage: "generate code for Identity",
|
||||
Flags: []C.Flag{
|
||||
flagCount,
|
||||
flagFilename,
|
||||
},
|
||||
Action: func(ctx *C.Context) error {
|
||||
return generateIdentityHelpers(
|
||||
ctx.String(keyFilename),
|
||||
ctx.Int(keyCount),
|
||||
)
|
||||
},
|
||||
}
|
||||
}
|
112
v2/cli/io.go
Normal file
112
v2/cli/io.go
Normal file
@@ -0,0 +1,112 @@
|
||||
// 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"
|
||||
|
||||
A "github.com/IBM/fp-go/v2/array"
|
||||
C "github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
func nonGenericIO(param string) string {
|
||||
return fmt.Sprintf("IO[%s]", param)
|
||||
}
|
||||
|
||||
var extrasIO = A.Empty[string]()
|
||||
|
||||
func generateIOSequenceT(f *os.File, i int) {
|
||||
generateGenericSequenceT("", nonGenericIO, extrasIO)(f, i)
|
||||
generateGenericSequenceT("Seq", nonGenericIO, extrasIO)(f, i)
|
||||
generateGenericSequenceT("Par", nonGenericIO, extrasIO)(f, i)
|
||||
}
|
||||
|
||||
func generateIOSequenceTuple(f *os.File, i int) {
|
||||
generateGenericSequenceTuple("", nonGenericIO, extrasIO)(f, i)
|
||||
generateGenericSequenceTuple("Seq", nonGenericIO, extrasIO)(f, i)
|
||||
generateGenericSequenceTuple("Par", nonGenericIO, extrasIO)(f, i)
|
||||
}
|
||||
|
||||
func generateIOTraverseTuple(f *os.File, i int) {
|
||||
generateGenericTraverseTuple("", nonGenericIO, extrasIO)(f, i)
|
||||
generateGenericTraverseTuple("Seq", nonGenericIO, extrasIO)(f, i)
|
||||
generateGenericTraverseTuple("Par", nonGenericIO, extrasIO)(f, i)
|
||||
}
|
||||
|
||||
func generateIOHelpers(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.Fprintf(f, `
|
||||
import (
|
||||
"github.com/IBM/fp-go/v2/tuple"
|
||||
"github.com/IBM/fp-go/v2/internal/apply"
|
||||
)
|
||||
`)
|
||||
|
||||
for i := 1; i <= count; i++ {
|
||||
// sequenceT
|
||||
generateIOSequenceT(f, i)
|
||||
// sequenceTuple
|
||||
generateIOSequenceTuple(f, i)
|
||||
// traverseTuple
|
||||
generateIOTraverseTuple(f, i)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func IOCommand() *C.Command {
|
||||
return &C.Command{
|
||||
Name: "io",
|
||||
Usage: "generate code for IO",
|
||||
Flags: []C.Flag{
|
||||
flagCount,
|
||||
flagFilename,
|
||||
},
|
||||
Action: func(ctx *C.Context) error {
|
||||
return generateIOHelpers(
|
||||
ctx.String(keyFilename),
|
||||
ctx.Int(keyCount),
|
||||
)
|
||||
},
|
||||
}
|
||||
}
|
283
v2/cli/ioeither.go
Normal file
283
v2/cli/ioeither.go
Normal file
@@ -0,0 +1,283 @@
|
||||
// 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"
|
||||
|
||||
A "github.com/IBM/fp-go/v2/array"
|
||||
C "github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
// [GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], GTAB ~func() ET.Either[E, T.Tuple2[A, B]], E, A, B any](a GA, b GB) GTAB {
|
||||
|
||||
func nonGenericIOEither(param string) string {
|
||||
return fmt.Sprintf("IOEither[E, %s]", param)
|
||||
}
|
||||
|
||||
var extrasIOEither = A.From("E")
|
||||
|
||||
func generateIOEitherSequenceT(f, fg *os.File, i int) {
|
||||
generateGenericSequenceT("", nonGenericIOEither, extrasIOEither)(f, i)
|
||||
generateGenericSequenceT("Seq", nonGenericIOEither, extrasIOEither)(f, i)
|
||||
generateGenericSequenceT("Par", nonGenericIOEither, extrasIOEither)(f, i)
|
||||
}
|
||||
|
||||
func generateIOEitherSequenceTuple(f, fg *os.File, i int) {
|
||||
generateGenericSequenceTuple("", nonGenericIOEither, extrasIOEither)(f, i)
|
||||
generateGenericSequenceTuple("Seq", nonGenericIOEither, extrasIOEither)(f, i)
|
||||
generateGenericSequenceTuple("Par", nonGenericIOEither, extrasIOEither)(f, i)
|
||||
}
|
||||
|
||||
func generateIOEitherTraverseTuple(f, fg *os.File, i int) {
|
||||
generateGenericTraverseTuple("", nonGenericIOEither, extrasIOEither)(f, i)
|
||||
generateGenericTraverseTuple("Seq", nonGenericIOEither, extrasIOEither)(f, i)
|
||||
generateGenericTraverseTuple("Par", nonGenericIOEither, extrasIOEither)(f, i)
|
||||
}
|
||||
|
||||
func generateIOEitherUneitherize(f, fg *os.File, i int) {
|
||||
// non generic version
|
||||
fmt.Fprintf(f, "\n// Uneitherize%d converts a function with %d parameters returning a tuple into a function with %d parameters returning a [IOEither[error, R]]\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+1)
|
||||
}
|
||||
fmt.Fprintf(f, ") IOEither[error, R]")
|
||||
for j := 0; j < i; j++ {
|
||||
fmt.Fprintf(f, ", T%d", j+1)
|
||||
}
|
||||
fmt.Fprintf(f, ", R any](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, ") (R, error) {\n")
|
||||
fmt.Fprintf(f, " return G.Uneitherize%d[IOEither[error, R]](f)\n", i)
|
||||
fmt.Fprintln(f, "}")
|
||||
|
||||
// generic version
|
||||
fmt.Fprintf(fg, "\n// Uneitherize%d converts a function with %d parameters returning a tuple into a function with %d parameters returning a [GIOA]\n", i, i, i)
|
||||
fmt.Fprintf(fg, "func Uneitherize%d[GIOA ~func() ET.Either[error, R], GTA ~func(", i)
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(fg, ", ")
|
||||
}
|
||||
fmt.Fprintf(fg, "T%d", j+1)
|
||||
}
|
||||
fmt.Fprintf(fg, ") GIOA")
|
||||
for j := 0; j < i; j++ {
|
||||
fmt.Fprintf(fg, ", T%d", j+1)
|
||||
}
|
||||
fmt.Fprintf(fg, ", R any](f GTA) func(")
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(fg, ", ")
|
||||
}
|
||||
fmt.Fprintf(fg, "T%d", j+1)
|
||||
}
|
||||
fmt.Fprintf(fg, ") (R, error) {\n")
|
||||
fmt.Fprintf(fg, " return func(")
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(fg, ", ")
|
||||
}
|
||||
fmt.Fprintf(fg, "t%d T%d", j+1, j+1)
|
||||
}
|
||||
fmt.Fprintf(fg, ") (R, error) {\n")
|
||||
fmt.Fprintf(fg, " return ET.Unwrap(f(")
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(fg, ", ")
|
||||
}
|
||||
fmt.Fprintf(fg, "t%d", j+1)
|
||||
}
|
||||
fmt.Fprintf(fg, ")())\n")
|
||||
fmt.Fprintf(fg, " }\n")
|
||||
fmt.Fprintf(fg, "}\n")
|
||||
}
|
||||
|
||||
func generateIOEitherEitherize(f, fg *os.File, i int) {
|
||||
// non generic version
|
||||
fmt.Fprintf(f, "\n// Eitherize%d converts a function with %d parameters returning a tuple into a function with %d parameters returning a [IOEither[error, R]]\n", i, i+1, i)
|
||||
fmt.Fprintf(f, "func Eitherize%d[F ~func(", i)
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "T%d", j+1)
|
||||
}
|
||||
fmt.Fprintf(f, ") (R, error)")
|
||||
for j := 0; j < i; j++ {
|
||||
fmt.Fprintf(f, ", T%d", j+1)
|
||||
}
|
||||
fmt.Fprintf(f, ", R any](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, ") IOEither[error, R] {\n")
|
||||
fmt.Fprintf(f, " return G.Eitherize%d[IOEither[error, R]](f)\n", i)
|
||||
fmt.Fprintln(f, "}")
|
||||
|
||||
// generic version
|
||||
fmt.Fprintf(fg, "\n// Eitherize%d converts a function with %d parameters returning a tuple into a function with %d parameters returning a [GIOA]\n", i, i, i)
|
||||
fmt.Fprintf(fg, "func Eitherize%d[GIOA ~func() ET.Either[error, R], F ~func(", i)
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(fg, ", ")
|
||||
}
|
||||
fmt.Fprintf(fg, "T%d", j+1)
|
||||
}
|
||||
fmt.Fprintf(fg, ") (R, error)")
|
||||
for j := 0; j < i; j++ {
|
||||
fmt.Fprintf(fg, ", T%d", j+1)
|
||||
}
|
||||
fmt.Fprintf(fg, ", R any](f F) func(")
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(fg, ", ")
|
||||
}
|
||||
fmt.Fprintf(fg, "T%d", j+1)
|
||||
}
|
||||
fmt.Fprintf(fg, ") GIOA {\n")
|
||||
fmt.Fprintf(fg, " e := ET.Eitherize%d(f)\n", i)
|
||||
fmt.Fprintf(fg, " return func(")
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(fg, ", ")
|
||||
}
|
||||
fmt.Fprintf(fg, "t%d T%d", j+1, j+1)
|
||||
}
|
||||
fmt.Fprintf(fg, ") GIOA {\n")
|
||||
fmt.Fprintf(fg, " return func() ET.Either[error, R] {\n")
|
||||
fmt.Fprintf(fg, " return e(")
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(fg, ", ")
|
||||
}
|
||||
fmt.Fprintf(fg, "t%d", j+1)
|
||||
}
|
||||
fmt.Fprintf(fg, ")\n")
|
||||
fmt.Fprintf(fg, " }}\n")
|
||||
fmt.Fprintf(fg, "}\n")
|
||||
}
|
||||
|
||||
func generateIOEitherHelpers(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()
|
||||
// construct subdirectory
|
||||
genFilename := filepath.Join("generic", filename)
|
||||
err = os.MkdirAll("generic", os.ModePerm)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fg, err := os.Create(filepath.Clean(genFilename))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer fg.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.Fprintf(f, `
|
||||
import (
|
||||
G "github.com/IBM/fp-go/v2/%s/generic"
|
||||
"github.com/IBM/fp-go/v2/internal/apply"
|
||||
"github.com/IBM/fp-go/v2/tuple"
|
||||
)
|
||||
`, pkg)
|
||||
|
||||
// some header
|
||||
fmt.Fprintln(fg, "// Code generated by go generate; DO NOT EDIT.")
|
||||
fmt.Fprintln(fg, "// This file was generated by robots at")
|
||||
fmt.Fprintf(fg, "// %s\n", time.Now())
|
||||
|
||||
fmt.Fprintf(fg, "package generic\n\n")
|
||||
|
||||
fmt.Fprintf(fg, `
|
||||
import (
|
||||
ET "github.com/IBM/fp-go/v2/either"
|
||||
)
|
||||
`)
|
||||
|
||||
// eitherize
|
||||
generateIOEitherEitherize(f, fg, 0)
|
||||
// uneitherize
|
||||
generateIOEitherUneitherize(f, fg, 0)
|
||||
|
||||
for i := 1; i <= count; i++ {
|
||||
// eitherize
|
||||
generateIOEitherEitherize(f, fg, i)
|
||||
// uneitherize
|
||||
generateIOEitherUneitherize(f, fg, i)
|
||||
// sequenceT
|
||||
generateIOEitherSequenceT(f, fg, i)
|
||||
// sequenceTuple
|
||||
generateIOEitherSequenceTuple(f, fg, i)
|
||||
// traverseTuple
|
||||
generateIOEitherTraverseTuple(f, fg, i)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func IOEitherCommand() *C.Command {
|
||||
return &C.Command{
|
||||
Name: "ioeither",
|
||||
Usage: "generate code for IOEither",
|
||||
Flags: []C.Flag{
|
||||
flagCount,
|
||||
flagFilename,
|
||||
},
|
||||
Action: func(ctx *C.Context) error {
|
||||
return generateIOEitherHelpers(
|
||||
ctx.String(keyFilename),
|
||||
ctx.Int(keyCount),
|
||||
)
|
||||
},
|
||||
}
|
||||
}
|
117
v2/cli/iooption.go
Normal file
117
v2/cli/iooption.go
Normal file
@@ -0,0 +1,117 @@
|
||||
// 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"
|
||||
|
||||
A "github.com/IBM/fp-go/v2/array"
|
||||
C "github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
func nonGenericIOOption(param string) string {
|
||||
return fmt.Sprintf("IOOption[%s]", param)
|
||||
}
|
||||
|
||||
func genericIOOption(param string) string {
|
||||
return fmt.Sprintf("func() O.Option[%s]", param)
|
||||
}
|
||||
|
||||
var extrasIOOption = A.Empty[string]()
|
||||
|
||||
func generateIOOptionSequenceT(f *os.File, i int) {
|
||||
generateGenericSequenceT("", nonGenericIOOption, extrasIOOption)(f, i)
|
||||
generateGenericSequenceT("Seq", nonGenericIOOption, extrasIOOption)(f, i)
|
||||
generateGenericSequenceT("Par", nonGenericIOOption, extrasIOOption)(f, i)
|
||||
}
|
||||
|
||||
func generateIOOptionSequenceTuple(f *os.File, i int) {
|
||||
generateGenericSequenceTuple("", nonGenericIOOption, extrasIOOption)(f, i)
|
||||
generateGenericSequenceTuple("Seq", nonGenericIOOption, extrasIOOption)(f, i)
|
||||
generateGenericSequenceTuple("Par", nonGenericIOOption, extrasIOOption)(f, i)
|
||||
}
|
||||
|
||||
func generateIOOptionTraverseTuple(f *os.File, i int) {
|
||||
generateGenericTraverseTuple("", nonGenericIOOption, extrasIOOption)(f, i)
|
||||
generateGenericTraverseTuple("Seq", nonGenericIOOption, extrasIOOption)(f, i)
|
||||
generateGenericTraverseTuple("Par", nonGenericIOOption, extrasIOOption)(f, i)
|
||||
}
|
||||
|
||||
func generateIOOptionHelpers(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.Fprintf(f, `
|
||||
import (
|
||||
"github.com/IBM/fp-go/v2/tuple"
|
||||
"github.com/IBM/fp-go/v2/internal/apply"
|
||||
)
|
||||
`)
|
||||
|
||||
for i := 1; i <= count; i++ {
|
||||
// sequenceT
|
||||
generateIOOptionSequenceT(f, i)
|
||||
// sequenceTuple
|
||||
generateIOOptionSequenceTuple(f, i)
|
||||
// traverseTuple
|
||||
generateIOOptionTraverseTuple(f, i)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func IOOptionCommand() *C.Command {
|
||||
return &C.Command{
|
||||
Name: "iooption",
|
||||
Usage: "generate code for IOOption",
|
||||
Flags: []C.Flag{
|
||||
flagCount,
|
||||
flagFilename,
|
||||
},
|
||||
Action: func(ctx *C.Context) error {
|
||||
return generateIOOptionHelpers(
|
||||
ctx.String(keyFilename),
|
||||
ctx.Int(keyCount),
|
||||
)
|
||||
},
|
||||
}
|
||||
}
|
376
v2/cli/monad.go
Normal file
376
v2/cli/monad.go
Normal file
@@ -0,0 +1,376 @@
|
||||
// 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"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Deprecated:
|
||||
func tupleType(name string) func(i int) string {
|
||||
return func(i int) string {
|
||||
var buf strings.Builder
|
||||
buf.WriteString(fmt.Sprintf("T.Tuple%d[", i))
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
buf.WriteString(", ")
|
||||
}
|
||||
buf.WriteString(fmt.Sprintf("%s%d", name, j+1))
|
||||
}
|
||||
buf.WriteString("]")
|
||||
|
||||
return buf.String()
|
||||
}
|
||||
}
|
||||
|
||||
func tupleTypePlain(name string) func(i int) string {
|
||||
return func(i int) string {
|
||||
var buf strings.Builder
|
||||
buf.WriteString(fmt.Sprintf("tuple.Tuple%d[", i))
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
buf.WriteString(", ")
|
||||
}
|
||||
buf.WriteString(fmt.Sprintf("%s%d", name, j+1))
|
||||
}
|
||||
buf.WriteString("]")
|
||||
|
||||
return buf.String()
|
||||
}
|
||||
}
|
||||
|
||||
func monadGenerateSequenceTNonGeneric(
|
||||
hkt func(string) string,
|
||||
fmap func(string, string) string,
|
||||
fap func(string, string) string,
|
||||
) func(f *os.File, i int) {
|
||||
return func(f *os.File, i int) {
|
||||
|
||||
tuple := tupleType("T")(i)
|
||||
|
||||
fmt.Fprintf(f, "SequenceT%d[", i)
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "T%d", j+1)
|
||||
}
|
||||
fmt.Fprintf(f, "](")
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "t%d %s", j+1, hkt(fmt.Sprintf("T%d", j+1)))
|
||||
}
|
||||
fmt.Fprintf(f, ") %s {", hkt(tuple))
|
||||
// the actual apply callback
|
||||
fmt.Fprintf(f, " return apply.SequenceT%d(\n", i)
|
||||
// map callback
|
||||
|
||||
curried := func(count int) string {
|
||||
var buf strings.Builder
|
||||
for j := count; j < i; j++ {
|
||||
buf.WriteString(fmt.Sprintf("func(T%d)", j+1))
|
||||
}
|
||||
buf.WriteString(tuple)
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
fmt.Fprintf(f, " %s,\n", fmap("T1", curried(1)))
|
||||
for j := 1; j < i; j++ {
|
||||
fmt.Fprintf(f, " %s,\n", fap(curried(j+1), fmt.Sprintf("T%d", j)))
|
||||
}
|
||||
|
||||
for j := 0; j < i; j++ {
|
||||
fmt.Fprintf(f, " T%d,\n", j+1)
|
||||
}
|
||||
|
||||
fmt.Fprintf(f, " )\n")
|
||||
|
||||
fmt.Fprintf(f, "}\n")
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func monadGenerateSequenceTGeneric(
|
||||
hkt func(string) string,
|
||||
fmap func(string, string) string,
|
||||
fap func(string, string) string,
|
||||
) func(f *os.File, i int) {
|
||||
return func(f *os.File, i int) {
|
||||
|
||||
tuple := tupleType("T")(i)
|
||||
|
||||
fmt.Fprintf(f, "SequenceT%d[", i)
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "T%d", j+1)
|
||||
}
|
||||
fmt.Fprintf(f, "](")
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "t%d %s", j+1, hkt(fmt.Sprintf("T%d", j+1)))
|
||||
}
|
||||
fmt.Fprintf(f, ") %s {", hkt(tuple))
|
||||
// the actual apply callback
|
||||
fmt.Fprintf(f, " return apply.SequenceT%d(\n", i)
|
||||
// map callback
|
||||
|
||||
curried := func(count int) string {
|
||||
var buf strings.Builder
|
||||
for j := count; j < i; j++ {
|
||||
buf.WriteString(fmt.Sprintf("func(T%d)", j+1))
|
||||
}
|
||||
buf.WriteString(tuple)
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
fmt.Fprintf(f, " %s,\n", fmap("T1", curried(1)))
|
||||
for j := 1; j < i; j++ {
|
||||
fmt.Fprintf(f, " %s,\n", fap(curried(j+1), fmt.Sprintf("T%d", j)))
|
||||
}
|
||||
|
||||
for j := 0; j < i; j++ {
|
||||
fmt.Fprintf(f, " T%d,\n", j+1)
|
||||
}
|
||||
|
||||
fmt.Fprintf(f, " )\n")
|
||||
|
||||
fmt.Fprintf(f, "}\n")
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func generateTraverseTuple1(
|
||||
hkt func(string) string,
|
||||
infix string) func(f *os.File, i int) {
|
||||
|
||||
return func(f *os.File, i int) {
|
||||
tuple := tupleType("T")(i)
|
||||
|
||||
fmt.Fprintf(f, "\n// TraverseTuple%d converts a [Tuple%d] of [A] via transformation functions transforming [A] to [%s] into a [%s].\n", i, i, hkt("A"), hkt(fmt.Sprintf("Tuple%d", i)))
|
||||
fmt.Fprintf(f, "func TraverseTuple%d[", i)
|
||||
// functions
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "F%d ~func(A%d) %s", j+1, j+1, hkt(fmt.Sprintf("T%d", j+1)))
|
||||
}
|
||||
if infix != "" {
|
||||
fmt.Fprintf(f, ", %s", infix)
|
||||
}
|
||||
// types
|
||||
for j := 0; j < i; j++ {
|
||||
fmt.Fprintf(f, ", A%d, T%d", j+1, j+1)
|
||||
}
|
||||
fmt.Fprintf(f, " any](")
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "f%d F%d", j+1, j+1)
|
||||
}
|
||||
fmt.Fprintf(f, ") func (T.Tuple%d[", i)
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "A%d", j+1)
|
||||
}
|
||||
fmt.Fprintf(f, "]) %s {\n", hkt(tuple))
|
||||
fmt.Fprintf(f, " return func(t T.Tuple%d[", i)
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "A%d", j+1)
|
||||
}
|
||||
fmt.Fprintf(f, "]) %s {\n", hkt(tuple))
|
||||
fmt.Fprintf(f, " return A.TraverseTuple%d(\n", i)
|
||||
// map
|
||||
fmt.Fprintf(f, " Map[")
|
||||
if infix != "" {
|
||||
fmt.Fprintf(f, "%s, T1,", infix)
|
||||
} else {
|
||||
fmt.Fprintf(f, "T1,")
|
||||
}
|
||||
for j := 1; j < i; j++ {
|
||||
fmt.Fprintf(f, " func(T%d)", j+1)
|
||||
}
|
||||
fmt.Fprintf(f, " %s],\n", tuple)
|
||||
// applicatives
|
||||
for j := 1; j < i; j++ {
|
||||
fmt.Fprintf(f, " Ap[")
|
||||
for k := j + 1; k < i; k++ {
|
||||
if k > j+1 {
|
||||
fmt.Fprintf(f, " ")
|
||||
}
|
||||
fmt.Fprintf(f, "func(T%d)", k+1)
|
||||
}
|
||||
if j < i-1 {
|
||||
fmt.Fprintf(f, " ")
|
||||
}
|
||||
fmt.Fprintf(f, "%s", tuple)
|
||||
if infix != "" {
|
||||
fmt.Fprintf(f, ", %s", infix)
|
||||
}
|
||||
fmt.Fprintf(f, ", T%d],\n", j+1)
|
||||
}
|
||||
for j := 0; j < i; j++ {
|
||||
fmt.Fprintf(f, " f%d,\n", j+1)
|
||||
}
|
||||
fmt.Fprintf(f, " t,\n")
|
||||
fmt.Fprintf(f, " )\n")
|
||||
fmt.Fprintf(f, " }\n")
|
||||
fmt.Fprintf(f, "}\n")
|
||||
}
|
||||
}
|
||||
|
||||
func generateSequenceTuple1(
|
||||
hkt func(string) string,
|
||||
infix string) func(f *os.File, i int) {
|
||||
|
||||
return func(f *os.File, i int) {
|
||||
|
||||
tuple := tupleType("T")(i)
|
||||
|
||||
fmt.Fprintf(f, "\n// SequenceTuple%d converts a [Tuple%d] of [%s] into an [%s].\n", i, i, hkt("T"), hkt(fmt.Sprintf("Tuple%d", i)))
|
||||
fmt.Fprintf(f, "func SequenceTuple%d[", i)
|
||||
if infix != "" {
|
||||
fmt.Fprintf(f, "%s", infix)
|
||||
}
|
||||
for j := 0; j < i; j++ {
|
||||
if infix != "" || j > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "T%d", j+1)
|
||||
}
|
||||
fmt.Fprintf(f, " any](t T.Tuple%d[", i)
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "%s", hkt(fmt.Sprintf("T%d", j+1)))
|
||||
}
|
||||
fmt.Fprintf(f, "]) %s {\n", hkt(tuple))
|
||||
fmt.Fprintf(f, " return A.SequenceTuple%d(\n", i)
|
||||
// map
|
||||
fmt.Fprintf(f, " Map[")
|
||||
if infix != "" {
|
||||
fmt.Fprintf(f, "%s, T1,", infix)
|
||||
} else {
|
||||
fmt.Fprintf(f, "T1,")
|
||||
}
|
||||
for j := 1; j < i; j++ {
|
||||
fmt.Fprintf(f, " func(T%d)", j+1)
|
||||
}
|
||||
fmt.Fprintf(f, " %s],\n", tuple)
|
||||
// applicatives
|
||||
for j := 1; j < i; j++ {
|
||||
fmt.Fprintf(f, " Ap[")
|
||||
for k := j + 1; k < i; k++ {
|
||||
if k > j+1 {
|
||||
fmt.Fprintf(f, " ")
|
||||
}
|
||||
fmt.Fprintf(f, "func(T%d)", k+1)
|
||||
}
|
||||
if j < i-1 {
|
||||
fmt.Fprintf(f, " ")
|
||||
}
|
||||
fmt.Fprintf(f, "%s", tuple)
|
||||
if infix != "" {
|
||||
fmt.Fprintf(f, ", %s", infix)
|
||||
}
|
||||
fmt.Fprintf(f, ", T%d],\n", j+1)
|
||||
}
|
||||
fmt.Fprintf(f, " t,\n")
|
||||
fmt.Fprintf(f, " )\n")
|
||||
fmt.Fprintf(f, "}\n")
|
||||
}
|
||||
}
|
||||
|
||||
func generateSequenceT1(
|
||||
hkt func(string) string,
|
||||
infix string) func(f *os.File, i int) {
|
||||
|
||||
return func(f *os.File, i int) {
|
||||
|
||||
tuple := tupleType("T")(i)
|
||||
|
||||
fmt.Fprintf(f, "\n// SequenceT%d converts %d parameters of [%s] into a [%s].\n", i, i, hkt("T"), hkt(fmt.Sprintf("Tuple%d", i)))
|
||||
fmt.Fprintf(f, "func SequenceT%d[", i)
|
||||
if infix != "" {
|
||||
fmt.Fprintf(f, "%s", infix)
|
||||
}
|
||||
for j := 0; j < i; j++ {
|
||||
if infix != "" || j > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "T%d", j+1)
|
||||
}
|
||||
fmt.Fprintf(f, " any](")
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "t%d %s", j+1, hkt(fmt.Sprintf("T%d", j+1)))
|
||||
}
|
||||
fmt.Fprintf(f, ") %s {\n", hkt(tuple))
|
||||
fmt.Fprintf(f, " return A.SequenceT%d(\n", i)
|
||||
// map
|
||||
fmt.Fprintf(f, " Map[")
|
||||
if infix != "" {
|
||||
fmt.Fprintf(f, "%s, T1,", infix)
|
||||
} else {
|
||||
fmt.Fprintf(f, "T1,")
|
||||
}
|
||||
for j := 1; j < i; j++ {
|
||||
fmt.Fprintf(f, " func(T%d)", j+1)
|
||||
}
|
||||
fmt.Fprintf(f, " %s],\n", tuple)
|
||||
// applicatives
|
||||
for j := 1; j < i; j++ {
|
||||
fmt.Fprintf(f, " Ap[")
|
||||
for k := j + 1; k < i; k++ {
|
||||
if k > j+1 {
|
||||
fmt.Fprintf(f, " ")
|
||||
}
|
||||
fmt.Fprintf(f, "func(T%d)", k+1)
|
||||
}
|
||||
if j < i-1 {
|
||||
fmt.Fprintf(f, " ")
|
||||
}
|
||||
fmt.Fprintf(f, "%s", tuple)
|
||||
if infix != "" {
|
||||
fmt.Fprintf(f, ", %s", infix)
|
||||
}
|
||||
fmt.Fprintf(f, ", T%d],\n", j+1)
|
||||
}
|
||||
for j := 0; j < i; j++ {
|
||||
fmt.Fprintf(f, " t%d,\n", j+1)
|
||||
}
|
||||
fmt.Fprintf(f, " )\n")
|
||||
fmt.Fprintf(f, "}\n")
|
||||
}
|
||||
|
||||
}
|
413
v2/cli/monad2.go
Normal file
413
v2/cli/monad2.go
Normal file
@@ -0,0 +1,413 @@
|
||||
// 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"
|
||||
"os"
|
||||
|
||||
A "github.com/IBM/fp-go/v2/array"
|
||||
F "github.com/IBM/fp-go/v2/function"
|
||||
N "github.com/IBM/fp-go/v2/number"
|
||||
S "github.com/IBM/fp-go/v2/string"
|
||||
)
|
||||
|
||||
var (
|
||||
concStrgs = A.Monoid[string]().Concat
|
||||
intercalStrgs = A.Intercalate(S.Monoid)
|
||||
concAllStrgs = A.ConcatAll(A.Monoid[string]())
|
||||
)
|
||||
|
||||
func joinAll(middle string) func(all ...[]string) string {
|
||||
ic := intercalStrgs(middle)
|
||||
return func(all ...[]string) string {
|
||||
return ic(concAllStrgs(all))
|
||||
}
|
||||
}
|
||||
|
||||
// Deprecated:
|
||||
func deprecatedGenerateGenericSequenceT(
|
||||
nonGenericType func(string) string,
|
||||
genericType func(string) string,
|
||||
extra []string,
|
||||
) func(f, fg *os.File, i int) {
|
||||
return func(f, fg *os.File, i int) {
|
||||
// tuple
|
||||
tuple := tupleType("T")(i)
|
||||
// all types T
|
||||
typesT := A.MakeBy(i, F.Flow2(
|
||||
N.Inc[int],
|
||||
S.Format[int]("T%d"),
|
||||
))
|
||||
// non generic version
|
||||
fmt.Fprintf(f, "\n// SequenceT%d converts %d [%s] into a [%s]\n", i, i, nonGenericType("T"), nonGenericType(tuple))
|
||||
fmt.Fprintf(f, "func SequenceT%d[%s any](\n", i, joinAll(", ")(extra, typesT))
|
||||
for j := 0; j < i; j++ {
|
||||
fmt.Fprintf(f, " t%d %s,\n", j+1, nonGenericType(fmt.Sprintf("T%d", j+1)))
|
||||
}
|
||||
fmt.Fprintf(f, ") %s {\n", nonGenericType(tuple))
|
||||
fmt.Fprintf(f, " return G.SequenceT%d[\n", i)
|
||||
fmt.Fprintf(f, " %s,\n", nonGenericType(tuple))
|
||||
for j := 0; j < i; j++ {
|
||||
fmt.Fprintf(f, " %s,\n", nonGenericType(fmt.Sprintf("T%d", j+1)))
|
||||
}
|
||||
fmt.Fprintf(f, " ](")
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "t%d", j+1)
|
||||
}
|
||||
fmt.Fprintf(f, ")\n")
|
||||
fmt.Fprintf(f, "}\n")
|
||||
|
||||
// generic version
|
||||
fmt.Fprintf(fg, "\n// SequenceT%d converts %d [%s] into a [%s]\n", i, i, genericType("T"), genericType(tuple))
|
||||
fmt.Fprintf(fg, "func SequenceT%d[\n", i)
|
||||
fmt.Fprintf(fg, " G_TUPLE%d ~%s,\n", i, genericType(tuple))
|
||||
for j := 0; j < i; j++ {
|
||||
fmt.Fprintf(fg, " G_T%d ~%s, \n", j+1, genericType(fmt.Sprintf("T%d", j+1)))
|
||||
}
|
||||
fmt.Fprintf(fg, " %s any](\n", joinAll(", ")(extra, typesT))
|
||||
for j := 0; j < i; j++ {
|
||||
fmt.Fprintf(fg, " t%d G_T%d,\n", j+1, j+1)
|
||||
}
|
||||
fmt.Fprintf(fg, ") G_TUPLE%d {\n", i)
|
||||
fmt.Fprintf(fg, " return A.SequenceT%d(\n", i)
|
||||
// map call
|
||||
var cio string
|
||||
cb := generateNestedCallbacks(1, i)
|
||||
if i > 1 {
|
||||
cio = genericType(cb)
|
||||
} else {
|
||||
cio = fmt.Sprintf("G_TUPLE%d", i)
|
||||
}
|
||||
fmt.Fprintf(fg, " Map[%s],\n", joinAll(", ")(A.From("G_T1", cio), extra, A.From("T1", cb)))
|
||||
// the apply calls
|
||||
for j := 1; j < i; j++ {
|
||||
if j < i-1 {
|
||||
cb := generateNestedCallbacks(j+1, i)
|
||||
cio = genericType(cb)
|
||||
} else {
|
||||
cio = fmt.Sprintf("G_TUPLE%d", i)
|
||||
}
|
||||
fmt.Fprintf(fg, " Ap[%s, %s, G_T%d],\n", cio, genericType(generateNestedCallbacks(j, i)), j+1)
|
||||
}
|
||||
// function parameters
|
||||
for j := 0; j < i; j++ {
|
||||
fmt.Fprintf(fg, " t%d,\n", j+1)
|
||||
}
|
||||
|
||||
fmt.Fprintf(fg, " )\n")
|
||||
fmt.Fprintf(fg, "}\n")
|
||||
}
|
||||
}
|
||||
|
||||
// Deprecated:
|
||||
func deprecatedGenerateGenericSequenceTuple(
|
||||
nonGenericType func(string) string,
|
||||
genericType func(string) string,
|
||||
extra []string,
|
||||
) func(f, fg *os.File, i int) {
|
||||
return func(f, fg *os.File, i int) {
|
||||
// tuple
|
||||
tuple := tupleType("T")(i)
|
||||
// all types T
|
||||
typesT := A.MakeBy(i, F.Flow2(
|
||||
N.Inc[int],
|
||||
S.Format[int]("T%d"),
|
||||
))
|
||||
// non generic version
|
||||
fmt.Fprintf(f, "\n// SequenceTuple%d converts a [T.Tuple%d[%s]] into a [%s]\n", i, i, nonGenericType("T"), nonGenericType(tuple))
|
||||
fmt.Fprintf(f, "func SequenceTuple%d[%s any](t T.Tuple%d[", i, joinAll(", ")(extra, typesT), i)
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "%s", nonGenericType(fmt.Sprintf("T%d", j+1)))
|
||||
}
|
||||
fmt.Fprintf(f, "]) %s {\n", nonGenericType(tuple))
|
||||
fmt.Fprintf(f, " return G.SequenceTuple%d[\n", i)
|
||||
fmt.Fprintf(f, " %s,\n", nonGenericType(tuple))
|
||||
for j := 0; j < i; j++ {
|
||||
fmt.Fprintf(f, " %s,\n", nonGenericType(fmt.Sprintf("T%d", j+1)))
|
||||
}
|
||||
fmt.Fprintf(f, " ](t)\n")
|
||||
fmt.Fprintf(f, "}\n")
|
||||
|
||||
// generic version
|
||||
fmt.Fprintf(fg, "\n// SequenceTuple%d converts a [T.Tuple%d[%s]] into a [%s]\n", i, i, genericType("T"), genericType(tuple))
|
||||
fmt.Fprintf(fg, "func SequenceTuple%d[\n", i)
|
||||
fmt.Fprintf(fg, " G_TUPLE%d ~%s,\n", i, genericType(tuple))
|
||||
for j := 0; j < i; j++ {
|
||||
fmt.Fprintf(fg, " G_T%d ~%s, \n", j+1, genericType(fmt.Sprintf("T%d", j+1)))
|
||||
}
|
||||
fmt.Fprintf(fg, " %s any](t T.Tuple%d[", joinAll(", ")(extra, typesT), i)
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(fg, ", ")
|
||||
}
|
||||
fmt.Fprintf(fg, "G_T%d", j+1)
|
||||
}
|
||||
fmt.Fprintf(fg, "]) G_TUPLE%d {\n", i)
|
||||
fmt.Fprintf(fg, " return A.SequenceTuple%d(\n", i)
|
||||
// map call
|
||||
var cio string
|
||||
cb := generateNestedCallbacks(1, i)
|
||||
if i > 1 {
|
||||
cio = genericType(cb)
|
||||
} else {
|
||||
cio = fmt.Sprintf("G_TUPLE%d", i)
|
||||
}
|
||||
fmt.Fprintf(fg, " Map[%s],\n", joinAll(", ")(A.From("G_T1", cio), extra, A.From("T1", cb)))
|
||||
// the apply calls
|
||||
for j := 1; j < i; j++ {
|
||||
if j < i-1 {
|
||||
cb := generateNestedCallbacks(j+1, i)
|
||||
cio = genericType(cb)
|
||||
} else {
|
||||
cio = fmt.Sprintf("G_TUPLE%d", i)
|
||||
}
|
||||
fmt.Fprintf(fg, " Ap[%s, %s, G_T%d],\n", cio, genericType(generateNestedCallbacks(j, i)), j+1)
|
||||
}
|
||||
// function parameters
|
||||
fmt.Fprintf(fg, " t)\n")
|
||||
fmt.Fprintf(fg, "}\n")
|
||||
}
|
||||
}
|
||||
|
||||
// Deprecated:
|
||||
func deprecatedGenerateGenericTraverseTuple(
|
||||
nonGenericType func(string) string,
|
||||
genericType func(string) string,
|
||||
extra []string,
|
||||
) func(f, fg *os.File, i int) {
|
||||
return func(f, fg *os.File, i int) {
|
||||
// tuple
|
||||
tupleT := tupleType("T")(i)
|
||||
tupleA := tupleType("A")(i)
|
||||
// all types T
|
||||
typesT := A.MakeBy(i, F.Flow2(
|
||||
N.Inc[int],
|
||||
S.Format[int]("T%d"),
|
||||
))
|
||||
// all types A
|
||||
typesA := A.MakeBy(i, F.Flow2(
|
||||
N.Inc[int],
|
||||
S.Format[int]("A%d"),
|
||||
))
|
||||
// all function types
|
||||
typesF := A.MakeBy(i, F.Flow2(
|
||||
N.Inc[int],
|
||||
func(j int) string {
|
||||
return fmt.Sprintf("F%d ~func(A%d) %s", j, j, nonGenericType(fmt.Sprintf("T%d", j)))
|
||||
},
|
||||
))
|
||||
// non generic version
|
||||
fmt.Fprintf(f, "\n// TraverseTuple%d converts a [T.Tuple%d[%s]] into a [%s]\n", i, i, nonGenericType("T"), nonGenericType(tupleT))
|
||||
fmt.Fprintf(f, "func TraverseTuple%d[%s any](", i, joinAll(", ")(typesF, extra, typesA, typesT))
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "f%d F%d", j+1, j+1)
|
||||
}
|
||||
fmt.Fprintf(f, ") func(%s) %s {\n", tupleA, nonGenericType(tupleT))
|
||||
fmt.Fprintf(f, " return G.TraverseTuple%d[%s](", i, nonGenericType(tupleT))
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "f%d", j+1)
|
||||
}
|
||||
fmt.Fprintf(f, ")\n")
|
||||
fmt.Fprintf(f, "}\n")
|
||||
|
||||
// generic version
|
||||
fmt.Fprintf(fg, "\n// TraverseTuple%d converts a [T.Tuple%d[%s]] into a [%s]\n", i, i, genericType("T"), genericType(tupleT))
|
||||
fmt.Fprintf(fg, "func TraverseTuple%d[\n", i)
|
||||
fmt.Fprintf(fg, " G_TUPLE%d ~%s,\n", i, genericType(tupleT))
|
||||
for j := 0; j < i; j++ {
|
||||
fmt.Fprintf(fg, " F%d ~func(A%d) G_T%d,\n", j+1, j+1, j+1)
|
||||
}
|
||||
for j := 0; j < i; j++ {
|
||||
fmt.Fprintf(fg, " G_T%d ~%s, \n", j+1, genericType(fmt.Sprintf("T%d", j+1)))
|
||||
}
|
||||
fmt.Fprintf(fg, " %s any](", joinAll(", ")(extra, typesA, typesT))
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(fg, ", ")
|
||||
}
|
||||
fmt.Fprintf(fg, "f%d F%d", j+1, j+1)
|
||||
}
|
||||
fmt.Fprintf(fg, ") func(%s) G_TUPLE%d {\n", tupleA, i)
|
||||
fmt.Fprintf(fg, " return func(t %s) G_TUPLE%d {\n", tupleA, i)
|
||||
fmt.Fprintf(fg, " return A.TraverseTuple%d(\n", i)
|
||||
// map call
|
||||
var cio string
|
||||
cb := generateNestedCallbacks(1, i)
|
||||
if i > 1 {
|
||||
cio = genericType(cb)
|
||||
} else {
|
||||
cio = fmt.Sprintf("G_TUPLE%d", i)
|
||||
}
|
||||
fmt.Fprintf(fg, " Map[%s],\n", joinAll(", ")(A.From("G_T1", cio), extra, A.From("T1", cb)))
|
||||
// the apply calls
|
||||
for j := 1; j < i; j++ {
|
||||
if j < i-1 {
|
||||
cb := generateNestedCallbacks(j+1, i)
|
||||
cio = genericType(cb)
|
||||
} else {
|
||||
cio = fmt.Sprintf("G_TUPLE%d", i)
|
||||
}
|
||||
fmt.Fprintf(fg, " Ap[%s, %s, G_T%d],\n", cio, genericType(generateNestedCallbacks(j, i)), j+1)
|
||||
}
|
||||
// function parameters
|
||||
for j := 0; j < i; j++ {
|
||||
fmt.Fprintf(fg, " f%d,\n", j+1)
|
||||
}
|
||||
// tuple parameter
|
||||
fmt.Fprintf(fg, " t)\n")
|
||||
fmt.Fprintf(fg, " }\n")
|
||||
fmt.Fprintf(fg, "}\n")
|
||||
}
|
||||
}
|
||||
|
||||
func generateGenericSequenceT(
|
||||
suffix string,
|
||||
nonGenericType func(string) string,
|
||||
extra []string,
|
||||
) func(f *os.File, i int) {
|
||||
return func(f *os.File, i int) {
|
||||
// tuple
|
||||
tuple := tupleTypePlain("T")(i)
|
||||
// all types T
|
||||
typesT := A.MakeBy(i, F.Flow2(
|
||||
N.Inc[int],
|
||||
S.Format[int]("T%d"),
|
||||
))
|
||||
// non generic version
|
||||
fmt.Fprintf(f, "\n// Sequence%sT%d converts %d [%s] into a [%s]\n", suffix, i, i, nonGenericType("T"), nonGenericType(tuple))
|
||||
fmt.Fprintf(f, "func Sequence%sT%d[%s any](\n", suffix, i, joinAll(", ")(extra, typesT))
|
||||
for j := 0; j < i; j++ {
|
||||
fmt.Fprintf(f, " t%d %s,\n", j+1, nonGenericType(fmt.Sprintf("T%d", j+1)))
|
||||
}
|
||||
fmt.Fprintf(f, ") %s {\n", nonGenericType(tuple))
|
||||
fmt.Fprintf(f, " return apply.SequenceT%d(\n", i)
|
||||
fmt.Fprintf(f, " Map[%s],\n", joinAll(", ")(extra, A.From("T1", generateNestedCallbacksPlain(1, i))))
|
||||
|
||||
// the apply calls
|
||||
for j := 2; j <= i; j++ {
|
||||
fmt.Fprintf(f, " Ap%s[%s],\n", suffix, joinAll(", ")(A.Of(generateNestedCallbacksPlain(j, i)), extra, A.Of(fmt.Sprintf("T%d", j))))
|
||||
}
|
||||
// function parameters
|
||||
for j := 1; j <= i; j++ {
|
||||
fmt.Fprintf(f, " t%d,\n", j)
|
||||
}
|
||||
|
||||
fmt.Fprintf(f, " )\n")
|
||||
fmt.Fprintf(f, "}\n")
|
||||
}
|
||||
}
|
||||
|
||||
func generateGenericSequenceTuple(
|
||||
suffix string,
|
||||
nonGenericType func(string) string,
|
||||
extra []string,
|
||||
) func(f *os.File, i int) {
|
||||
return func(f *os.File, i int) {
|
||||
// tuple
|
||||
tuple := tupleTypePlain("T")(i)
|
||||
// all types T
|
||||
typesT := A.MakeBy(i, F.Flow2(
|
||||
N.Inc[int],
|
||||
S.Format[int]("T%d"),
|
||||
))
|
||||
// non generic version
|
||||
fmt.Fprintf(f, "\n// Sequence%sTuple%d converts a [tuple.Tuple%d[%s]] into a [%s]\n", suffix, i, i, nonGenericType("T"), nonGenericType(tuple))
|
||||
fmt.Fprintf(f, "func Sequence%sTuple%d[%s any](t tuple.Tuple%d[", suffix, i, joinAll(", ")(extra, typesT), i)
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "%s", nonGenericType(fmt.Sprintf("T%d", j+1)))
|
||||
}
|
||||
fmt.Fprintf(f, "]) %s {\n", nonGenericType(tuple))
|
||||
fmt.Fprintf(f, " return apply.SequenceTuple%d(\n", i)
|
||||
fmt.Fprintf(f, " Map[%s],\n", joinAll(", ")(extra, A.From("T1", generateNestedCallbacksPlain(1, i))))
|
||||
|
||||
// the apply calls
|
||||
for j := 2; j <= i; j++ {
|
||||
fmt.Fprintf(f, " Ap%s[%s],\n", suffix, joinAll(", ")(A.Of(generateNestedCallbacksPlain(j, i)), extra, A.Of(fmt.Sprintf("T%d", j))))
|
||||
}
|
||||
|
||||
// function parameters
|
||||
fmt.Fprintf(f, " t,\n")
|
||||
// function parameters
|
||||
fmt.Fprintf(f, " )\n")
|
||||
fmt.Fprintf(f, "}\n")
|
||||
}
|
||||
}
|
||||
|
||||
func generateGenericTraverseTuple(
|
||||
suffix string,
|
||||
nonGenericType func(string) string,
|
||||
extra []string,
|
||||
) func(f *os.File, i int) {
|
||||
return func(f *os.File, i int) {
|
||||
// all types T
|
||||
typesT := A.MakeBy(i, F.Flow2(
|
||||
N.Inc[int],
|
||||
S.Format[int]("T%d"),
|
||||
))
|
||||
// all types A
|
||||
typesA := A.MakeBy(i, F.Flow2(
|
||||
N.Inc[int],
|
||||
S.Format[int]("A%d"),
|
||||
))
|
||||
// function types
|
||||
typesF := A.MakeBy(i, func(j int) string {
|
||||
return fmt.Sprintf("F%d ~func(A%d) %s", j+1, j+1, nonGenericType(fmt.Sprintf("T%d", j+1)))
|
||||
})
|
||||
paramF := A.MakeBy(i, func(j int) string {
|
||||
return fmt.Sprintf("f%d F%d", j+1, j+1)
|
||||
})
|
||||
// return type
|
||||
paramType := fmt.Sprintf("tuple.Tuple%d[%s]", i, joinAll(", ")(typesA))
|
||||
returnType := nonGenericType(fmt.Sprintf("tuple.Tuple%d[%s]", i, joinAll(", ")(typesT)))
|
||||
// non generic version
|
||||
fmt.Fprintf(f, "\n// Traverse%sTuple%d converts a [%s] into a [%s]\n", suffix, i, paramType, returnType)
|
||||
fmt.Fprintf(f, "func Traverse%sTuple%d[%s any](%s) func(%s) %s {\n", suffix, i, joinAll(", ")(extra, typesF, typesT, typesA), joinAll(", ")(paramF), paramType, returnType)
|
||||
fmt.Fprintf(f, " return func(t %s) %s {\n", paramType, returnType)
|
||||
fmt.Fprintf(f, " return apply.TraverseTuple%d(\n", i)
|
||||
fmt.Fprintf(f, " Map[%s],\n", joinAll(", ")(extra, A.From("T1", generateNestedCallbacksPlain(1, i))))
|
||||
|
||||
// the apply calls
|
||||
for j := 2; j <= i; j++ {
|
||||
fmt.Fprintf(f, " Ap%s[%s],\n", suffix, joinAll(", ")(A.Of(generateNestedCallbacksPlain(j, i)), extra, A.Of(fmt.Sprintf("T%d", j))))
|
||||
}
|
||||
// the function parameters
|
||||
for j := 1; j <= i; j++ {
|
||||
fmt.Fprintf(f, " f%d,\n", j)
|
||||
}
|
||||
// function parameters
|
||||
fmt.Fprintf(f, " t,\n")
|
||||
// function parameters
|
||||
fmt.Fprintf(f, " )\n")
|
||||
fmt.Fprintf(f, " }\n")
|
||||
fmt.Fprintf(f, "}\n")
|
||||
}
|
||||
}
|
210
v2/cli/option.go
Normal file
210
v2/cli/option.go
Normal file
@@ -0,0 +1,210 @@
|
||||
// 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 optionHKT(typeA string) string {
|
||||
return fmt.Sprintf("Option[%s]", typeA)
|
||||
}
|
||||
|
||||
func generateOptionTraverseTuple(f *os.File, i int) {
|
||||
generateTraverseTuple1(optionHKT, "")(f, i)
|
||||
}
|
||||
|
||||
func generateOptionSequenceTuple(f *os.File, i int) {
|
||||
generateSequenceTuple1(optionHKT, "")(f, i)
|
||||
}
|
||||
|
||||
func generateOptionSequenceT(f *os.File, i int) {
|
||||
generateSequenceT1(optionHKT, "")(f, i)
|
||||
}
|
||||
|
||||
func generateOptionize(f *os.File, i int) {
|
||||
// Create the optionize version
|
||||
fmt.Fprintf(f, "\n// Optionize%d converts a function with %d parameters returning a tuple of a return value R and a boolean into a function with %d parameters returning an Option[R]\n", i, i, i)
|
||||
fmt.Fprintf(f, "func Optionize%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, ") (R, bool)")
|
||||
for j := 0; j < i; j++ {
|
||||
fmt.Fprintf(f, ", T%d", j)
|
||||
}
|
||||
fmt.Fprintf(f, ", R any](f F) func(")
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "T%d", j)
|
||||
}
|
||||
fmt.Fprintf(f, ") Option[R] {\n")
|
||||
fmt.Fprintf(f, " return func(")
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "t%d T%d", j, j)
|
||||
}
|
||||
fmt.Fprintf(f, ") Option[R] {\n")
|
||||
fmt.Fprintf(f, " return optionize(func() (R, bool) {\n")
|
||||
fmt.Fprintf(f, " return f(")
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "t%d", j)
|
||||
}
|
||||
fmt.Fprintln(f, ")")
|
||||
fmt.Fprintln(f, " })")
|
||||
fmt.Fprintln(f, " }")
|
||||
fmt.Fprintln(f, "}")
|
||||
}
|
||||
|
||||
func generateUnoptionize(f *os.File, i int) {
|
||||
// Create the optionize version
|
||||
fmt.Fprintf(f, "\n// Unoptionize%d converts a function with %d parameters returning a tuple of a return value R and a boolean into a function with %d parameters returning an Option[R]\n", i, i, i)
|
||||
fmt.Fprintf(f, "func Unoptionize%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, ") Option[R]")
|
||||
for j := 0; j < i; j++ {
|
||||
fmt.Fprintf(f, ", T%d", j)
|
||||
}
|
||||
fmt.Fprintf(f, ", R any](f F) func(")
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "T%d", j)
|
||||
}
|
||||
fmt.Fprintf(f, ") (R, bool) {\n")
|
||||
fmt.Fprintf(f, " return func(")
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "t%d T%d", j, j)
|
||||
}
|
||||
fmt.Fprintf(f, ") (R, bool) {\n")
|
||||
fmt.Fprintf(f, " return Unwrap(f(")
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "t%d", j)
|
||||
}
|
||||
fmt.Fprintln(f, "))")
|
||||
fmt.Fprintln(f, " }")
|
||||
fmt.Fprintln(f, "}")
|
||||
}
|
||||
|
||||
func generateOptionHelpers(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.Fprintf(f, `
|
||||
import (
|
||||
A "github.com/IBM/fp-go/v2/internal/apply"
|
||||
T "github.com/IBM/fp-go/v2/tuple"
|
||||
)
|
||||
`)
|
||||
|
||||
// print out some helpers
|
||||
fmt.Fprintf(f, `// optionize converts a nullary function to an option
|
||||
func optionize[R any](f func() (R, bool)) Option[R] {
|
||||
if r, ok := f(); ok {
|
||||
return Some(r)
|
||||
}
|
||||
return None[R]()
|
||||
}
|
||||
`)
|
||||
|
||||
// zero level functions
|
||||
|
||||
// optionize
|
||||
generateOptionize(f, 0)
|
||||
// unoptionize
|
||||
generateUnoptionize(f, 0)
|
||||
|
||||
for i := 1; i <= count; i++ {
|
||||
// optionize
|
||||
generateOptionize(f, i)
|
||||
// unoptionize
|
||||
generateUnoptionize(f, i)
|
||||
// sequenceT
|
||||
generateOptionSequenceT(f, i)
|
||||
// sequenceTuple
|
||||
generateOptionSequenceTuple(f, i)
|
||||
// traverseTuple
|
||||
generateOptionTraverseTuple(f, i)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func OptionCommand() *C.Command {
|
||||
return &C.Command{
|
||||
Name: "option",
|
||||
Usage: "generate code for Option",
|
||||
Flags: []C.Flag{
|
||||
flagCount,
|
||||
flagFilename,
|
||||
},
|
||||
Action: func(ctx *C.Context) error {
|
||||
return generateOptionHelpers(
|
||||
ctx.String(keyFilename),
|
||||
ctx.Int(keyCount),
|
||||
)
|
||||
},
|
||||
}
|
||||
}
|
433
v2/cli/pipe.go
Normal file
433
v2/cli/pipe.go
Normal file
@@ -0,0 +1,433 @@
|
||||
// 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 generateUnsliced(f *os.File, i int) {
|
||||
// Create the optionize version
|
||||
fmt.Fprintf(f, "\n// Unsliced%d converts a function taking a slice parameter into a function with %d parameters\n", i, i)
|
||||
fmt.Fprintf(f, "func Unsliced%d[F ~func([]T) R, T, R any](f F) func(", i)
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "T")
|
||||
}
|
||||
fmt.Fprintf(f, ") R {\n")
|
||||
fmt.Fprintf(f, " return func(")
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "t%d", j+1)
|
||||
}
|
||||
if i > 0 {
|
||||
fmt.Fprintf(f, " T")
|
||||
}
|
||||
fmt.Fprintf(f, ") R {\n")
|
||||
fmt.Fprintf(f, " return f([]T{")
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "t%d", j+1)
|
||||
}
|
||||
fmt.Fprintln(f, "})")
|
||||
fmt.Fprintln(f, " }")
|
||||
fmt.Fprintln(f, "}")
|
||||
}
|
||||
|
||||
func generateVariadic(f *os.File, i int) {
|
||||
// Create the nullary version
|
||||
fmt.Fprintf(f, "\n// Variadic%d converts a function taking %d parameters and a final slice into a function with %d parameters but a final variadic argument\n", i, i, i)
|
||||
fmt.Fprintf(f, "func Variadic%d[", i)
|
||||
for j := 1; j <= i; j++ {
|
||||
if j > 1 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "T%d", j)
|
||||
}
|
||||
if i > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "V, R any](f func(")
|
||||
for j := 1; j <= i; j++ {
|
||||
if j > 1 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "T%d", j)
|
||||
}
|
||||
if i > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "[]V) R) func(")
|
||||
for j := 1; j <= i; j++ {
|
||||
if j > 1 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "T%d", j)
|
||||
}
|
||||
if i > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "...V) R {\n")
|
||||
fmt.Fprintf(f, " return func(")
|
||||
for j := 1; j <= i; j++ {
|
||||
if j > 1 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "t%d T%d", j, j)
|
||||
}
|
||||
if i > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "v ...V) R {\n")
|
||||
fmt.Fprintf(f, " return f(")
|
||||
for j := 1; j <= i; j++ {
|
||||
if j > 1 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "t%d", j)
|
||||
}
|
||||
if i > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "v)\n")
|
||||
fmt.Fprintf(f, " }\n")
|
||||
|
||||
fmt.Fprintf(f, "}\n")
|
||||
}
|
||||
|
||||
func generateUnvariadic(f *os.File, i int) {
|
||||
// Create the nullary version
|
||||
fmt.Fprintf(f, "\n// Unvariadic%d converts a function taking %d parameters and a final variadic argument into a function with %d parameters but a final slice argument\n", i, i, i)
|
||||
fmt.Fprintf(f, "func Unvariadic%d[", i)
|
||||
for j := 1; j <= i; j++ {
|
||||
if j > 1 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "T%d", j)
|
||||
}
|
||||
if i > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "V, R any](f func(")
|
||||
for j := 1; j <= i; j++ {
|
||||
if j > 1 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "T%d", j)
|
||||
}
|
||||
if i > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "...V) R) func(")
|
||||
for j := 1; j <= i; j++ {
|
||||
if j > 1 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "T%d", j)
|
||||
}
|
||||
if i > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "[]V) R {\n")
|
||||
fmt.Fprintf(f, " return func(")
|
||||
for j := 1; j <= i; j++ {
|
||||
if j > 1 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "t%d T%d", j, j)
|
||||
}
|
||||
if i > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "v []V) R {\n")
|
||||
fmt.Fprintf(f, " return f(")
|
||||
for j := 1; j <= i; j++ {
|
||||
if j > 1 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "t%d", j)
|
||||
}
|
||||
if i > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "v...)\n")
|
||||
fmt.Fprintf(f, " }\n")
|
||||
|
||||
fmt.Fprintf(f, "}\n")
|
||||
}
|
||||
|
||||
func generateNullary(f *os.File, i int) {
|
||||
// Create the nullary version
|
||||
fmt.Fprintf(f, "\n// Nullary%d creates a parameter less function from a parameter less function and %d functions. When executed the first parameter less function gets executed and then the result is piped through the remaining functions\n", i, i-1)
|
||||
fmt.Fprintf(f, "func Nullary%d[F1 ~func() T1", i)
|
||||
for j := 2; j <= i; j++ {
|
||||
fmt.Fprintf(f, ", F%d ~func(T%d) T%d", j, j-1, j)
|
||||
}
|
||||
for j := 1; j <= i; j++ {
|
||||
fmt.Fprintf(f, ", T%d", j)
|
||||
}
|
||||
fmt.Fprintf(f, " any](f1 F1")
|
||||
for j := 2; j <= i; j++ {
|
||||
fmt.Fprintf(f, ", f%d F%d", j, j)
|
||||
}
|
||||
fmt.Fprintf(f, ") func() T%d {\n", i)
|
||||
fmt.Fprintf(f, " return func() T%d {\n", i)
|
||||
fmt.Fprintf(f, " return Pipe%d(f1()", i-1)
|
||||
for j := 2; j <= i; j++ {
|
||||
fmt.Fprintf(f, ", f%d", j)
|
||||
}
|
||||
fmt.Fprintf(f, ")\n")
|
||||
fmt.Fprintln(f, " }")
|
||||
|
||||
fmt.Fprintln(f, "}")
|
||||
}
|
||||
|
||||
func generateFlow(f *os.File, i int) {
|
||||
// Create the flow version
|
||||
fmt.Fprintf(f, "\n// Flow%d creates a function that takes an initial value t0 and successively applies %d functions where the input of a function is the return value of the previous function\n// The final return value is the result of the last function application\n", i, i)
|
||||
fmt.Fprintf(f, "func Flow%d[", i)
|
||||
for j := 1; j <= i; j++ {
|
||||
if j > 1 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "F%d ~func(T%d) T%d", j, j-1, j)
|
||||
}
|
||||
for j := 0; j <= i; j++ {
|
||||
fmt.Fprintf(f, ", T%d", j)
|
||||
}
|
||||
fmt.Fprintf(f, " any](")
|
||||
for j := 1; j <= i; j++ {
|
||||
if j > 1 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "f%d F%d", j, j)
|
||||
}
|
||||
fmt.Fprintf(f, ") func(T0) T%d {\n", i)
|
||||
fmt.Fprintf(f, " return func(t0 T0) T%d {\n", i)
|
||||
fmt.Fprintf(f, " return Pipe%d(t0", i)
|
||||
for j := 1; j <= i; j++ {
|
||||
fmt.Fprintf(f, ", f%d", j)
|
||||
}
|
||||
fmt.Fprintf(f, ")\n")
|
||||
fmt.Fprintln(f, " }")
|
||||
|
||||
fmt.Fprintln(f, "}")
|
||||
|
||||
}
|
||||
|
||||
func generatePipe(f *os.File, i int) {
|
||||
// Create the pipe version
|
||||
fmt.Fprintf(f, "\n// Pipe%d takes an initial value t0 and successively applies %d functions where the input of a function is the return value of the previous function\n// The final return value is the result of the last function application\n", i, i)
|
||||
fmt.Fprintf(f, "func Pipe%d[", i)
|
||||
for j := 1; j <= i; j++ {
|
||||
if j > 1 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "F%d ~func(T%d) T%d", j, j-1, j)
|
||||
}
|
||||
if i > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
for j := 0; j <= i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "T%d", j)
|
||||
}
|
||||
|
||||
fmt.Fprintf(f, " any](t0 T0")
|
||||
for j := 1; j <= i; j++ {
|
||||
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, "\n")
|
||||
fmt.Fprintln(f, "}")
|
||||
}
|
||||
|
||||
func recurseCurry(f *os.File, indent string, total, count int) {
|
||||
if count == 1 {
|
||||
fmt.Fprintf(f, "%sreturn func(t%d T%d) T%d {\n", indent, total-1, total-1, total)
|
||||
fmt.Fprintf(f, "%s return f(t0", indent)
|
||||
for i := 1; i < total; i++ {
|
||||
fmt.Fprintf(f, ", t%d", i)
|
||||
}
|
||||
fmt.Fprintf(f, ")\n")
|
||||
fmt.Fprintf(f, "%s}\n", indent)
|
||||
} else {
|
||||
fmt.Fprintf(f, "%sreturn", indent)
|
||||
for i := total - count + 1; i <= total; i++ {
|
||||
fmt.Fprintf(f, " func(t%d T%d)", i-1, i-1)
|
||||
}
|
||||
fmt.Fprintf(f, " T%d {\n", total)
|
||||
recurseCurry(f, fmt.Sprintf(" %s", indent), total, count-1)
|
||||
fmt.Fprintf(f, "%s}\n", indent)
|
||||
}
|
||||
}
|
||||
|
||||
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, ", 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 FCT) func(T0)")
|
||||
for j := 2; j <= i; j++ {
|
||||
fmt.Fprintf(f, " func(T%d)", j-1)
|
||||
}
|
||||
fmt.Fprintf(f, " T%d {\n", i)
|
||||
recurseCurry(f, " ", i, i)
|
||||
fmt.Fprintf(f, "}\n")
|
||||
}
|
||||
|
||||
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, ", T%d", j)
|
||||
}
|
||||
fmt.Fprintf(f, " any](f FCT) func(")
|
||||
for j := 1; j <= i; j++ {
|
||||
if j > 1 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "T%d", j-1)
|
||||
}
|
||||
fmt.Fprintf(f, ") T%d {\n", i)
|
||||
fmt.Fprintf(f, " return func(")
|
||||
for j := 1; j <= i; j++ {
|
||||
if j > 1 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "t%d T%d", j-1, j-1)
|
||||
}
|
||||
fmt.Fprintf(f, ") T%d {\n", i)
|
||||
fmt.Fprintf(f, " return f")
|
||||
for j := 1; j <= i; j++ {
|
||||
fmt.Fprintf(f, "(t%d)", j-1)
|
||||
}
|
||||
fmt.Fprintln(f)
|
||||
|
||||
fmt.Fprintf(f, " }\n")
|
||||
|
||||
fmt.Fprintf(f, "}\n")
|
||||
}
|
||||
|
||||
func generatePipeHelpers(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", pkg)
|
||||
|
||||
// pipe
|
||||
generatePipe(f, 0)
|
||||
// variadic
|
||||
generateVariadic(f, 0)
|
||||
// unvariadic
|
||||
generateUnvariadic(f, 0)
|
||||
// unsliced
|
||||
generateUnsliced(f, 0)
|
||||
|
||||
for i := 1; i <= count; i++ {
|
||||
|
||||
// pipe
|
||||
generatePipe(f, i)
|
||||
// flow
|
||||
generateFlow(f, i)
|
||||
// nullary
|
||||
generateNullary(f, i)
|
||||
// curry
|
||||
generateCurry(f, i)
|
||||
// uncurry
|
||||
generateUncurry(f, i)
|
||||
// variadic
|
||||
generateVariadic(f, i)
|
||||
// unvariadic
|
||||
generateUnvariadic(f, i)
|
||||
// unsliced
|
||||
generateUnsliced(f, i)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func PipeCommand() *C.Command {
|
||||
return &C.Command{
|
||||
Name: "pipe",
|
||||
Usage: "generate code for pipe, flow, curry, etc",
|
||||
Description: "Code generation for pipe, flow, curry, etc",
|
||||
Flags: []C.Flag{
|
||||
flagCount,
|
||||
flagFilename,
|
||||
},
|
||||
Action: func(ctx *C.Context) error {
|
||||
return generatePipeHelpers(
|
||||
ctx.String(keyFilename),
|
||||
ctx.Int(keyCount),
|
||||
)
|
||||
},
|
||||
}
|
||||
}
|
164
v2/cli/reader.go
Normal file
164
v2/cli/reader.go
Normal file
@@ -0,0 +1,164 @@
|
||||
// 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 generateReaderFrom(f, fg *os.File, i int) {
|
||||
// non generic version
|
||||
fmt.Fprintf(f, "\n// From%d converts a function with %d parameters returning a [R] into a function with %d parameters returning a [Reader[C, R]]\n// The first parameter is considered to be the context [C] of the reader\n", i, i+1, i)
|
||||
fmt.Fprintf(f, "func From%d[F ~func(C", i)
|
||||
for j := 0; j < i; j++ {
|
||||
fmt.Fprintf(f, ", T%d", j)
|
||||
}
|
||||
fmt.Fprintf(f, ") R")
|
||||
for j := 0; j < i; j++ {
|
||||
fmt.Fprintf(f, ", T%d", j)
|
||||
}
|
||||
fmt.Fprintf(f, ", C, R any](f F) func(")
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "T%d", j)
|
||||
}
|
||||
fmt.Fprintf(f, ") Reader[C, R] {\n")
|
||||
fmt.Fprintf(f, " return G.From%d[Reader[C, R]](f)\n", i)
|
||||
fmt.Fprintln(f, "}")
|
||||
|
||||
// generic version
|
||||
fmt.Fprintf(fg, "\n// From%d converts a function with %d parameters returning a [R] into a function with %d parameters returning a [GRA]\n// The first parameter is considered to be the context [C].\n", i, i+1, i)
|
||||
fmt.Fprintf(fg, "func From%d[GRA ~func(C) R, F ~func(C", i)
|
||||
for j := 0; j < i; j++ {
|
||||
fmt.Fprintf(fg, ", T%d", j)
|
||||
}
|
||||
fmt.Fprintf(fg, ") R")
|
||||
for j := 0; j < i; j++ {
|
||||
fmt.Fprintf(fg, ", T%d", j)
|
||||
}
|
||||
fmt.Fprintf(fg, ", C, R any](f F) func(")
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(fg, ", ")
|
||||
}
|
||||
fmt.Fprintf(fg, "T%d", j)
|
||||
}
|
||||
fmt.Fprintf(fg, ") GRA {\n")
|
||||
|
||||
fmt.Fprintf(fg, " return func(")
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(fg, ", ")
|
||||
}
|
||||
fmt.Fprintf(fg, "t%d T%d", j, j)
|
||||
}
|
||||
fmt.Fprintf(fg, ") GRA {\n")
|
||||
fmt.Fprintf(fg, " return MakeReader[GRA](func(r C) R {\n")
|
||||
fmt.Fprintf(fg, " return f(r")
|
||||
for j := 0; j < i; j++ {
|
||||
fmt.Fprintf(fg, ", t%d", j)
|
||||
}
|
||||
fmt.Fprintf(fg, ")\n")
|
||||
fmt.Fprintf(fg, " })\n")
|
||||
fmt.Fprintf(fg, " }\n")
|
||||
fmt.Fprintf(fg, "}\n")
|
||||
}
|
||||
|
||||
func generateReaderHelpers(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()
|
||||
// construct subdirectory
|
||||
genFilename := filepath.Join("generic", filename)
|
||||
err = os.MkdirAll("generic", os.ModePerm)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fg, err := os.Create(filepath.Clean(genFilename))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer fg.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.Fprintf(f, `
|
||||
import (
|
||||
G "github.com/IBM/fp-go/v2/%s/generic"
|
||||
)
|
||||
`, pkg)
|
||||
|
||||
// some header
|
||||
fmt.Fprintln(fg, "// Code generated by go generate; DO NOT EDIT.")
|
||||
fmt.Fprintln(fg, "// This file was generated by robots at")
|
||||
fmt.Fprintf(fg, "// %s\n", time.Now())
|
||||
|
||||
fmt.Fprintf(fg, "package generic\n\n")
|
||||
|
||||
// from
|
||||
generateReaderFrom(f, fg, 0)
|
||||
|
||||
for i := 1; i <= count; i++ {
|
||||
// from
|
||||
generateReaderFrom(f, fg, i)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func ReaderCommand() *C.Command {
|
||||
return &C.Command{
|
||||
Name: "reader",
|
||||
Usage: "generate code for Reader",
|
||||
Flags: []C.Flag{
|
||||
flagCount,
|
||||
flagFilename,
|
||||
},
|
||||
Action: func(ctx *C.Context) error {
|
||||
return generateReaderHelpers(
|
||||
ctx.String(keyFilename),
|
||||
ctx.Int(keyCount),
|
||||
)
|
||||
},
|
||||
}
|
||||
}
|
294
v2/cli/readerioeither.go
Normal file
294
v2/cli/readerioeither.go
Normal file
@@ -0,0 +1,294 @@
|
||||
// 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 generateReaderIOEitherFrom(f, fg *os.File, i int) {
|
||||
// non generic version
|
||||
fmt.Fprintf(f, "\n// From%d converts a function with %d parameters returning a tuple into a function with %d parameters returning a [ReaderIOEither[R]]\n// The first parameter is considered to be the context [C].\n", i, i+1, i)
|
||||
fmt.Fprintf(f, "func From%d[F ~func(C", i)
|
||||
for j := 0; j < i; j++ {
|
||||
fmt.Fprintf(f, ", T%d", j)
|
||||
}
|
||||
fmt.Fprintf(f, ") func() (R, error)")
|
||||
for j := 0; j < i; j++ {
|
||||
fmt.Fprintf(f, ", T%d", j)
|
||||
}
|
||||
fmt.Fprintf(f, ", C, R any](f F) func(")
|
||||
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] {\n")
|
||||
fmt.Fprintf(f, " return G.From%d[ReaderIOEither[C, error, R]](f)\n", i)
|
||||
fmt.Fprintln(f, "}")
|
||||
|
||||
// generic version
|
||||
fmt.Fprintf(fg, "\n// From%d converts a function with %d parameters returning a tuple into a function with %d parameters returning a [GRA]\n// The first parameter is considerd to be the context [C].\n", i, i+1, i)
|
||||
fmt.Fprintf(fg, "func From%d[GRA ~func(C) GIOA, F ~func(C", i)
|
||||
for j := 0; j < i; j++ {
|
||||
fmt.Fprintf(fg, ", T%d", j)
|
||||
}
|
||||
fmt.Fprintf(fg, ") func() (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 F) func(")
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(fg, ", ")
|
||||
}
|
||||
fmt.Fprintf(fg, "T%d", j)
|
||||
}
|
||||
fmt.Fprintf(fg, ") GRA {\n")
|
||||
|
||||
fmt.Fprintf(fg, " return RD.From%d[GRA](func(r C", i)
|
||||
for j := 0; j < i; j++ {
|
||||
fmt.Fprintf(fg, ", t%d T%d", j, j)
|
||||
}
|
||||
fmt.Fprintf(fg, ") GIOA {\n")
|
||||
fmt.Fprintf(fg, " return E.Eitherize0(f(r")
|
||||
for j := 0; j < i; j++ {
|
||||
fmt.Fprintf(fg, ", t%d", j)
|
||||
}
|
||||
fmt.Fprintf(fg, "))\n")
|
||||
fmt.Fprintf(fg, " })\n")
|
||||
fmt.Fprintf(fg, "}\n")
|
||||
}
|
||||
|
||||
func generateReaderIOEitherEitherize(f, fg *os.File, i int) {
|
||||
// non generic version
|
||||
fmt.Fprintf(f, "\n// Eitherize%d converts a function with %d parameters returning a tuple into a function with %d parameters returning a [ReaderIOEither[C, error, R]]\n// The first parameter is considered to be the context [C].\n", i, i+1, i)
|
||||
fmt.Fprintf(f, "func Eitherize%d[F ~func(C", i)
|
||||
for j := 0; j < i; j++ {
|
||||
fmt.Fprintf(f, ", T%d", j)
|
||||
}
|
||||
fmt.Fprintf(f, ") (R, error)")
|
||||
for j := 0; j < i; j++ {
|
||||
fmt.Fprintf(f, ", T%d", j)
|
||||
}
|
||||
fmt.Fprintf(f, ", C, R any](f F) func(")
|
||||
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] {\n")
|
||||
fmt.Fprintf(f, " return G.Eitherize%d[ReaderIOEither[C, error, R]](f)\n", i)
|
||||
fmt.Fprintln(f, "}")
|
||||
|
||||
// generic version
|
||||
fmt.Fprintf(fg, "\n// Eitherize%d converts a function with %d parameters returning a tuple into a function with %d parameters returning a [GRA]\n// The first parameter is considered to be the context [C].\n", i, i, i)
|
||||
fmt.Fprintf(fg, "func Eitherize%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 F) func(")
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(fg, ", ")
|
||||
}
|
||||
fmt.Fprintf(fg, "T%d", j)
|
||||
}
|
||||
fmt.Fprintf(fg, ") GRA {\n")
|
||||
|
||||
fmt.Fprintf(fg, " return From%d[GRA](func(r C", i)
|
||||
for j := 0; j < i; j++ {
|
||||
fmt.Fprintf(fg, ", t%d T%d", j, j)
|
||||
}
|
||||
fmt.Fprintf(fg, ") func() (R, error) {\n")
|
||||
fmt.Fprintf(fg, " return func() (R, error) {\n")
|
||||
fmt.Fprintf(fg, " return f(r")
|
||||
for j := 0; j < i; j++ {
|
||||
fmt.Fprintf(fg, ", t%d", j)
|
||||
}
|
||||
fmt.Fprintf(fg, ")\n")
|
||||
fmt.Fprintf(fg, " }})\n")
|
||||
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 {
|
||||
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()
|
||||
// construct subdirectory
|
||||
genFilename := filepath.Join("generic", filename)
|
||||
err = os.MkdirAll("generic", os.ModePerm)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fg, err := os.Create(filepath.Clean(genFilename))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer fg.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.Fprintf(f, `
|
||||
import (
|
||||
G "github.com/IBM/fp-go/v2/%s/generic"
|
||||
)
|
||||
`, pkg)
|
||||
|
||||
// some header
|
||||
fmt.Fprintln(fg, "// Code generated by go generate; DO NOT EDIT.")
|
||||
fmt.Fprintln(fg, "// This file was generated by robots at")
|
||||
fmt.Fprintf(fg, "// %s\n", time.Now())
|
||||
|
||||
fmt.Fprintf(fg, "package generic\n\n")
|
||||
|
||||
fmt.Fprintf(fg, `
|
||||
import (
|
||||
E "github.com/IBM/fp-go/v2/either"
|
||||
RD "github.com/IBM/fp-go/v2/reader/generic"
|
||||
)
|
||||
`)
|
||||
|
||||
// from
|
||||
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
|
||||
}
|
||||
|
||||
func ReaderIOEitherCommand() *C.Command {
|
||||
return &C.Command{
|
||||
Name: "readerioeither",
|
||||
Usage: "generate code for ReaderIOEither",
|
||||
Flags: []C.Flag{
|
||||
flagCount,
|
||||
flagFilename,
|
||||
},
|
||||
Action: func(ctx *C.Context) error {
|
||||
return generateReaderIOEitherHelpers(
|
||||
ctx.String(keyFilename),
|
||||
ctx.Int(keyCount),
|
||||
)
|
||||
},
|
||||
}
|
||||
}
|
15
v2/cli/templates/functions.go
Normal file
15
v2/cli/templates/functions.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package templates
|
||||
|
||||
import (
|
||||
"text/template"
|
||||
|
||||
E "github.com/IBM/fp-go/v2/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))
|
||||
}
|
625
v2/cli/tuple.go
Normal file
625
v2/cli/tuple.go
Normal file
@@ -0,0 +1,625 @@
|
||||
// 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"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
C "github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
func writeTupleType(f *os.File, symbol string, i int) {
|
||||
fmt.Fprintf(f, "Tuple%d[", i)
|
||||
for j := 1; j <= i; j++ {
|
||||
if j > 1 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "%s%d", symbol, j)
|
||||
}
|
||||
fmt.Fprintf(f, "]")
|
||||
}
|
||||
|
||||
func makeTupleType(name string) func(i int) string {
|
||||
return func(i int) string {
|
||||
var buf strings.Builder
|
||||
buf.WriteString(fmt.Sprintf("Tuple%d[", i))
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
buf.WriteString(", ")
|
||||
}
|
||||
buf.WriteString(fmt.Sprintf("%s%d", name, j+1))
|
||||
}
|
||||
buf.WriteString("]")
|
||||
|
||||
return buf.String()
|
||||
}
|
||||
}
|
||||
|
||||
func generatePush(f *os.File, i int) {
|
||||
tuple1 := makeTupleType("T")(i)
|
||||
tuple2 := makeTupleType("T")(i + 1)
|
||||
// Create the replicate version
|
||||
fmt.Fprintf(f, "\n// Push%d creates a [Tuple%d] from a [Tuple%d] by appending a constant value\n", i, i+1, i)
|
||||
fmt.Fprintf(f, "func Push%d[", i)
|
||||
// function prototypes
|
||||
for j := 0; j <= i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "T%d", j+1)
|
||||
}
|
||||
fmt.Fprintf(f, " any](value T%d) func(%s) %s {\n", i+1, tuple1, tuple2)
|
||||
fmt.Fprintf(f, " return func(t %s) %s {\n", tuple1, tuple2)
|
||||
fmt.Fprintf(f, " return MakeTuple%d(", i+1)
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "t.F%d", j+1)
|
||||
}
|
||||
fmt.Fprintf(f, ", value)\n")
|
||||
fmt.Fprintf(f, " }\n")
|
||||
fmt.Fprintf(f, "}\n")
|
||||
}
|
||||
|
||||
func generateReplicate(f *os.File, i int) {
|
||||
// Create the replicate version
|
||||
fmt.Fprintf(f, "\n// Replicate%d creates a [Tuple%d] with all fields set to the input value `t`\n", i, i)
|
||||
fmt.Fprintf(f, "func Replicate%d[T any](t T) Tuple%d[", i, i)
|
||||
for j := 1; j <= i; j++ {
|
||||
if j > 1 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "T")
|
||||
}
|
||||
fmt.Fprintf(f, "] {\n")
|
||||
// execute the mapping
|
||||
fmt.Fprintf(f, " return MakeTuple%d(", i)
|
||||
for j := 1; j <= i; j++ {
|
||||
if j > 1 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "t")
|
||||
}
|
||||
fmt.Fprintf(f, ")\n")
|
||||
fmt.Fprintf(f, "}\n")
|
||||
}
|
||||
|
||||
func generateMap(f *os.File, i int) {
|
||||
// Create the optionize version
|
||||
fmt.Fprintf(f, "\n// Map%d maps each value of a [Tuple%d] via a mapping function\n", i, i)
|
||||
fmt.Fprintf(f, "func Map%d[", i)
|
||||
// function prototypes
|
||||
for j := 1; j <= i; j++ {
|
||||
if j > 1 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "F%d ~func(T%d) R%d", j, j, j)
|
||||
}
|
||||
for j := 1; j <= i; j++ {
|
||||
fmt.Fprintf(f, ", T%d, R%d", j, j)
|
||||
}
|
||||
fmt.Fprintf(f, " any](")
|
||||
for j := 1; j <= i; j++ {
|
||||
if j > 1 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "f%d F%d", j, j)
|
||||
}
|
||||
fmt.Fprintf(f, ") func(")
|
||||
writeTupleType(f, "T", i)
|
||||
fmt.Fprintf(f, ") ")
|
||||
writeTupleType(f, "R", i)
|
||||
fmt.Fprintf(f, " {\n")
|
||||
|
||||
fmt.Fprintf(f, " return func(t ")
|
||||
writeTupleType(f, "T", i)
|
||||
fmt.Fprintf(f, ") ")
|
||||
writeTupleType(f, "R", i)
|
||||
fmt.Fprintf(f, " {\n")
|
||||
|
||||
// execute the mapping
|
||||
fmt.Fprintf(f, " return MakeTuple%d(\n", i)
|
||||
for j := 1; j <= i; j++ {
|
||||
fmt.Fprintf(f, " f%d(t.F%d),\n", j, j)
|
||||
}
|
||||
fmt.Fprintf(f, " )\n")
|
||||
|
||||
fmt.Fprintf(f, " }\n")
|
||||
fmt.Fprintf(f, "}\n")
|
||||
}
|
||||
|
||||
func generateMonoid(f *os.File, i int) {
|
||||
// Create the optionize version
|
||||
fmt.Fprintf(f, "\n// Monoid%d creates a [Monoid] for a [Tuple%d] based on %d monoids for the contained types\n", i, i, i)
|
||||
fmt.Fprintf(f, "func Monoid%d[", i)
|
||||
for j := 1; j <= i; j++ {
|
||||
if j > 1 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "T%d", j)
|
||||
}
|
||||
fmt.Fprintf(f, " any](")
|
||||
for j := 1; j <= i; j++ {
|
||||
if j > 1 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "m%d M.Monoid[T%d]", j, j)
|
||||
}
|
||||
fmt.Fprintf(f, ") M.Monoid[")
|
||||
writeTupleType(f, "T", i)
|
||||
fmt.Fprintf(f, "] {\n")
|
||||
|
||||
fmt.Fprintf(f, " return M.MakeMonoid(func(l, r ")
|
||||
writeTupleType(f, "T", i)
|
||||
fmt.Fprintf(f, ") ")
|
||||
writeTupleType(f, "T", i)
|
||||
fmt.Fprintf(f, "{\n")
|
||||
|
||||
fmt.Fprintf(f, " return MakeTuple%d(", i)
|
||||
for j := 1; j <= i; j++ {
|
||||
if j > 1 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "m%d.Concat(l.F%d, r.F%d)", j, j, j)
|
||||
}
|
||||
fmt.Fprintf(f, ")\n")
|
||||
fmt.Fprintf(f, " }, MakeTuple%d(", i)
|
||||
for j := 1; j <= i; j++ {
|
||||
if j > 1 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "m%d.Empty()", j)
|
||||
}
|
||||
fmt.Fprintf(f, "))\n")
|
||||
|
||||
fmt.Fprintf(f, "}\n")
|
||||
}
|
||||
|
||||
func generateOrd(f *os.File, i int) {
|
||||
// Create the optionize version
|
||||
fmt.Fprintf(f, "\n// Ord%d creates n [Ord] for a [Tuple%d] based on %d [Ord]s for the contained types\n", i, i, i)
|
||||
fmt.Fprintf(f, "func Ord%d[", i)
|
||||
for j := 1; j <= i; j++ {
|
||||
if j > 1 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "T%d", j)
|
||||
}
|
||||
fmt.Fprintf(f, " any](")
|
||||
for j := 1; j <= i; j++ {
|
||||
if j > 1 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "o%d O.Ord[T%d]", j, j)
|
||||
}
|
||||
fmt.Fprintf(f, ") O.Ord[")
|
||||
writeTupleType(f, "T", i)
|
||||
fmt.Fprintf(f, "] {\n")
|
||||
|
||||
fmt.Fprintf(f, " return O.MakeOrd(func(l, r ")
|
||||
writeTupleType(f, "T", i)
|
||||
fmt.Fprintf(f, ") int {\n")
|
||||
|
||||
for j := 1; j <= i; j++ {
|
||||
fmt.Fprintf(f, " if c:= o%d.Compare(l.F%d, r.F%d); c != 0 {return c}\n", j, j, j)
|
||||
}
|
||||
fmt.Fprintf(f, " return 0\n")
|
||||
fmt.Fprintf(f, " }, func(l, r ")
|
||||
writeTupleType(f, "T", i)
|
||||
fmt.Fprintf(f, ") bool {\n")
|
||||
fmt.Fprintf(f, " return ")
|
||||
for j := 1; j <= i; j++ {
|
||||
if j > 1 {
|
||||
fmt.Fprintf(f, " && ")
|
||||
}
|
||||
fmt.Fprintf(f, "o%d.Equals(l.F%d, r.F%d)", j, j, j)
|
||||
}
|
||||
fmt.Fprintf(f, "\n")
|
||||
fmt.Fprintf(f, " })\n")
|
||||
|
||||
fmt.Fprintf(f, "}\n")
|
||||
}
|
||||
|
||||
func generateTupleType(f *os.File, i int) {
|
||||
// Create the optionize version
|
||||
fmt.Fprintf(f, "\n// Tuple%d is a struct that carries %d independently typed values\n", i, i)
|
||||
fmt.Fprintf(f, "type Tuple%d[", i)
|
||||
for j := 1; j <= i; j++ {
|
||||
if j > 1 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "T%d", j)
|
||||
}
|
||||
fmt.Fprintf(f, " any] struct {\n")
|
||||
for j := 1; j <= i; j++ {
|
||||
fmt.Fprintf(f, " F%d T%d\n", j, j)
|
||||
}
|
||||
fmt.Fprintf(f, "}\n")
|
||||
}
|
||||
|
||||
func generateMakeTupleType(f *os.File, i int) {
|
||||
// Create the optionize version
|
||||
fmt.Fprintf(f, "\n// MakeTuple%d is a function that converts its %d parameters into a [Tuple%d]\n", i, i, i)
|
||||
fmt.Fprintf(f, "func MakeTuple%d[", i)
|
||||
for j := 1; j <= i; j++ {
|
||||
if j > 1 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "T%d", j)
|
||||
}
|
||||
fmt.Fprintf(f, " any](")
|
||||
for j := 1; j <= i; j++ {
|
||||
if j > 1 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "t%d T%d", j, j)
|
||||
}
|
||||
fmt.Fprintf(f, ") ")
|
||||
writeTupleType(f, "T", i)
|
||||
fmt.Fprintf(f, " {\n")
|
||||
fmt.Fprintf(f, " return Tuple%d[", i)
|
||||
for j := 1; j <= i; j++ {
|
||||
if j > 1 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "T%d", j)
|
||||
}
|
||||
fmt.Fprintf(f, "]{")
|
||||
for j := 1; j <= i; j++ {
|
||||
if j > 1 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "t%d", j)
|
||||
}
|
||||
fmt.Fprintf(f, "}\n")
|
||||
fmt.Fprintf(f, "}\n")
|
||||
}
|
||||
|
||||
func generateUntupled(f *os.File, i int) {
|
||||
// Create the optionize version
|
||||
fmt.Fprintf(f, "\n// Untupled%d converts a function with a [Tuple%d] parameter into a function with %d parameters\n// The inverse function is [Tupled%d]\n", i, i, i, i)
|
||||
fmt.Fprintf(f, "func Untupled%d[F ~func(Tuple%d[", i, i)
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "T%d", j+1)
|
||||
}
|
||||
fmt.Fprintf(f, "]) R")
|
||||
for j := 0; j < i; j++ {
|
||||
fmt.Fprintf(f, ", T%d", j+1)
|
||||
}
|
||||
fmt.Fprintf(f, ", R any](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, ") R {\n")
|
||||
fmt.Fprintf(f, " return func(")
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "t%d T%d", j+1, j+1)
|
||||
}
|
||||
fmt.Fprintf(f, ") R {\n")
|
||||
fmt.Fprintf(f, " return f(MakeTuple%d(", i)
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "t%d", j+1)
|
||||
}
|
||||
fmt.Fprintln(f, "))")
|
||||
fmt.Fprintln(f, " }")
|
||||
fmt.Fprintln(f, "}")
|
||||
}
|
||||
|
||||
func generateTupled(f *os.File, i int) {
|
||||
// Create the optionize version
|
||||
fmt.Fprintf(f, "\n// Tupled%d converts a function with %d parameters into a function taking a Tuple%d\n// The inverse function is [Untupled%d]\n", i, i, i, i)
|
||||
fmt.Fprintf(f, "func Tupled%d[F ~func(", i)
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "T%d", j+1)
|
||||
}
|
||||
fmt.Fprintf(f, ") R")
|
||||
for j := 0; j < i; j++ {
|
||||
fmt.Fprintf(f, ", T%d", j+1)
|
||||
}
|
||||
fmt.Fprintf(f, ", R any](f F) func(Tuple%d[", i)
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "T%d", j+1)
|
||||
}
|
||||
fmt.Fprintf(f, "]) R {\n")
|
||||
fmt.Fprintf(f, " return func(t Tuple%d[", i)
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "T%d", j+1)
|
||||
}
|
||||
fmt.Fprintf(f, "]) R {\n")
|
||||
fmt.Fprintf(f, " return f(")
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "t.F%d", j+1)
|
||||
}
|
||||
fmt.Fprintf(f, ")\n")
|
||||
fmt.Fprintf(f, " }\n")
|
||||
fmt.Fprintln(f, "}")
|
||||
}
|
||||
|
||||
func generateTupleHelpers(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.Fprintf(f, `
|
||||
import (
|
||||
M "github.com/IBM/fp-go/v2/monoid"
|
||||
O "github.com/IBM/fp-go/v2/ord"
|
||||
)
|
||||
`)
|
||||
|
||||
for i := 1; i <= count; i++ {
|
||||
// tuple type
|
||||
generateTupleType(f, i)
|
||||
}
|
||||
|
||||
for i := 1; i <= count; i++ {
|
||||
// tuple generator
|
||||
generateMakeTupleType(f, i)
|
||||
// tupled wrapper
|
||||
generateTupled(f, i)
|
||||
// untupled wrapper
|
||||
generateUntupled(f, i)
|
||||
// monoid
|
||||
generateMonoid(f, i)
|
||||
// generate order
|
||||
generateOrd(f, i)
|
||||
// generate map
|
||||
generateMap(f, i)
|
||||
// generate replicate
|
||||
generateReplicate(f, i)
|
||||
// generate tuple functions such as string and fmt
|
||||
generateTupleString(f, i)
|
||||
// generate json support
|
||||
generateTupleMarshal(f, i)
|
||||
// generate json support
|
||||
generateTupleUnmarshal(f, i)
|
||||
// generate toArray
|
||||
generateToArray(f, i)
|
||||
// generate fromArray
|
||||
generateFromArray(f, i)
|
||||
// generate push
|
||||
if i < count {
|
||||
generatePush(f, i)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func generateTupleMarshal(f *os.File, i int) {
|
||||
// Create the stringify version
|
||||
fmt.Fprintf(f, "\n// MarshalJSON marshals the [Tuple%d] into a JSON array\n", i)
|
||||
fmt.Fprintf(f, "func (t ")
|
||||
writeTupleType(f, "T", i)
|
||||
fmt.Fprintf(f, ") MarshalJSON() ([]byte, error) {\n")
|
||||
fmt.Fprintf(f, " return tupleMarshalJSON(")
|
||||
// function prototypes
|
||||
for j := 1; j <= i; j++ {
|
||||
if j > 1 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "t.F%d", j)
|
||||
}
|
||||
fmt.Fprintf(f, ")\n")
|
||||
fmt.Fprintf(f, "}\n")
|
||||
}
|
||||
|
||||
func generateTupleUnmarshal(f *os.File, i int) {
|
||||
// Create the stringify version
|
||||
fmt.Fprintf(f, "\n// UnmarshalJSON unmarshals a JSON array into a [Tuple%d]\n", i)
|
||||
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
|
||||
for j := 1; j <= i; j++ {
|
||||
fmt.Fprintf(f, ", &t.F%d", j)
|
||||
}
|
||||
fmt.Fprintf(f, ")\n")
|
||||
fmt.Fprintf(f, "}\n")
|
||||
}
|
||||
|
||||
func generateToArray(f *os.File, i int) {
|
||||
// Create the stringify version
|
||||
fmt.Fprintf(f, "\n// ToArray converts the [Tuple%d] into an array of type [R] using %d transformation functions from [T] to [R]\n// The inverse function is [FromArray%d]\n", i, i, i)
|
||||
fmt.Fprintf(f, "func ToArray%d[", i)
|
||||
// function prototypes
|
||||
for j := 1; j <= i; j++ {
|
||||
if j > 1 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "F%d ~func(T%d) R", j, j)
|
||||
}
|
||||
for j := 1; j <= i; j++ {
|
||||
fmt.Fprintf(f, ", T%d", j)
|
||||
}
|
||||
fmt.Fprintf(f, ", R any](")
|
||||
for j := 1; j <= i; j++ {
|
||||
if j > 1 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "f%d F%d", j, j)
|
||||
}
|
||||
fmt.Fprintf(f, ") func(t ")
|
||||
writeTupleType(f, "T", i)
|
||||
fmt.Fprintf(f, ") []R {\n")
|
||||
fmt.Fprintf(f, " return func(t ")
|
||||
writeTupleType(f, "T", i)
|
||||
fmt.Fprintf(f, ") []R {\n")
|
||||
fmt.Fprintf(f, " return []R{\n")
|
||||
for j := 1; j <= i; j++ {
|
||||
fmt.Fprintf(f, " f%d(t.F%d),\n", j, j)
|
||||
}
|
||||
fmt.Fprintf(f, " }\n")
|
||||
fmt.Fprintf(f, " }\n")
|
||||
fmt.Fprintf(f, "}\n")
|
||||
}
|
||||
|
||||
func generateFromArray(f *os.File, i int) {
|
||||
// Create the stringify version
|
||||
fmt.Fprintf(f, "\n// FromArray converts an array of [R] into a [Tuple%d] using %d functions from [R] to [T]\n// The inverse function is [ToArray%d]\n", i, i, i)
|
||||
fmt.Fprintf(f, "func FromArray%d[", i)
|
||||
// function prototypes
|
||||
for j := 1; j <= i; j++ {
|
||||
if j > 1 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "F%d ~func(R) T%d", j, j)
|
||||
}
|
||||
for j := 1; j <= i; j++ {
|
||||
fmt.Fprintf(f, ", T%d", j)
|
||||
}
|
||||
fmt.Fprintf(f, ", R any](")
|
||||
for j := 1; j <= i; j++ {
|
||||
if j > 1 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "f%d F%d", j, j)
|
||||
}
|
||||
fmt.Fprintf(f, ") func(r []R) ")
|
||||
writeTupleType(f, "T", i)
|
||||
fmt.Fprintf(f, " {\n")
|
||||
fmt.Fprintf(f, " return func(r []R) ")
|
||||
writeTupleType(f, "T", i)
|
||||
fmt.Fprintf(f, " {\n")
|
||||
fmt.Fprintf(f, " return MakeTuple%d(\n", i)
|
||||
for j := 1; j <= i; j++ {
|
||||
fmt.Fprintf(f, " f%d(r[%d]),\n", j, j-1)
|
||||
}
|
||||
fmt.Fprintf(f, " )\n")
|
||||
fmt.Fprintf(f, " }\n")
|
||||
fmt.Fprintf(f, "}\n")
|
||||
}
|
||||
|
||||
func generateTupleString(f *os.File, i int) {
|
||||
// Create the stringify version
|
||||
fmt.Fprintf(f, "\n// String prints some debug info for the [Tuple%d]\n", i)
|
||||
fmt.Fprintf(f, "func (t ")
|
||||
writeTupleType(f, "T", i)
|
||||
fmt.Fprintf(f, ") String() string {\n")
|
||||
// convert to string
|
||||
fmt.Fprint(f, " return tupleString(")
|
||||
for j := 1; j <= i; j++ {
|
||||
if j > 1 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "t.F%d", j)
|
||||
}
|
||||
fmt.Fprintf(f, ")\n")
|
||||
fmt.Fprintf(f, "}\n")
|
||||
}
|
||||
|
||||
// func generateTupleJson(f *os.File, i int) {
|
||||
// // Create the stringify version
|
||||
// fmt.Fprintf(f, "\n// MarshalJSON converts the [Tuple%d] into a JSON byte stream\n", i)
|
||||
// fmt.Fprintf(f, "func (t ")
|
||||
// writeTupleType(f, "T", i)
|
||||
// fmt.Fprintf(f, ") MarshalJSON() ([]byte, error) {\n")
|
||||
// // convert to string
|
||||
// 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")
|
||||
// }
|
||||
|
||||
func TupleCommand() *C.Command {
|
||||
return &C.Command{
|
||||
Name: "tuple",
|
||||
Usage: "generate code for Tuple",
|
||||
Flags: []C.Flag{
|
||||
flagCount,
|
||||
flagFilename,
|
||||
},
|
||||
Action: func(ctx *C.Context) error {
|
||||
return generateTupleHelpers(
|
||||
ctx.String(keyFilename),
|
||||
ctx.Int(keyCount),
|
||||
)
|
||||
},
|
||||
}
|
||||
}
|
59
v2/constant/const.go
Normal file
59
v2/constant/const.go
Normal file
@@ -0,0 +1,59 @@
|
||||
// Copyright (c) 2023 IBM Corp.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package constant
|
||||
|
||||
import (
|
||||
F "github.com/IBM/fp-go/v2/function"
|
||||
M "github.com/IBM/fp-go/v2/monoid"
|
||||
S "github.com/IBM/fp-go/v2/semigroup"
|
||||
)
|
||||
|
||||
type Const[E, A any] struct {
|
||||
value E
|
||||
}
|
||||
|
||||
func Make[E, A any](e E) Const[E, A] {
|
||||
return Const[E, A]{value: e}
|
||||
}
|
||||
|
||||
func Unwrap[E, A any](c Const[E, A]) E {
|
||||
return c.value
|
||||
}
|
||||
|
||||
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] {
|
||||
return Make[E, B](fa.value)
|
||||
}
|
||||
|
||||
func MonadAp[E, A, B any](s S.Semigroup[E]) func(fab Const[E, func(A) B], fa Const[E, A]) Const[E, B] {
|
||||
return func(fab Const[E, func(A) B], fa Const[E, A]) Const[E, B] {
|
||||
return Make[E, B](s.Concat(fab.value, fa.value))
|
||||
}
|
||||
}
|
||||
|
||||
func Map[E, A, B any](f func(A) B) func(fa Const[E, A]) Const[E, B] {
|
||||
return F.Bind2nd(MonadMap[E, A, B], f)
|
||||
}
|
||||
|
||||
func Ap[E, A, B any](s S.Semigroup[E]) func(fa Const[E, A]) func(fab Const[E, func(A) B]) Const[E, B] {
|
||||
monadap := MonadAp[E, A, B](s)
|
||||
return func(fa Const[E, A]) func(fab Const[E, func(A) B]) Const[E, B] {
|
||||
return F.Bind2nd(monadap, fa)
|
||||
}
|
||||
}
|
40
v2/constant/const_test.go
Normal file
40
v2/constant/const_test.go
Normal file
@@ -0,0 +1,40 @@
|
||||
// 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 constant
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
F "github.com/IBM/fp-go/v2/function"
|
||||
"github.com/IBM/fp-go/v2/internal/utils"
|
||||
S "github.com/IBM/fp-go/v2/string"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestMap(t *testing.T) {
|
||||
fa := Make[string, int]("foo")
|
||||
assert.Equal(t, fa, F.Pipe1(fa, Map[string, int](utils.Double)))
|
||||
}
|
||||
|
||||
func TestOf(t *testing.T) {
|
||||
assert.Equal(t, Make[string, int](""), Of[string, int](S.Monoid)(1))
|
||||
}
|
||||
|
||||
func TestAp(t *testing.T) {
|
||||
fab := Make[string, int]("bar")
|
||||
assert.Equal(t, Make[string, int]("foobar"), Ap[string, int, int](S.Monoid)(fab)(Make[string, func(int) int]("foo")))
|
||||
}
|
40
v2/constraints/constraints.go
Normal file
40
v2/constraints/constraints.go
Normal file
@@ -0,0 +1,40 @@
|
||||
// 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 constraints
|
||||
|
||||
type Ordered interface {
|
||||
Integer | Float | ~string
|
||||
}
|
||||
|
||||
type Signed interface {
|
||||
~int | ~int8 | ~int16 | ~int32 | ~int64
|
||||
}
|
||||
|
||||
type Unsigned interface {
|
||||
~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr
|
||||
}
|
||||
|
||||
type Integer interface {
|
||||
Signed | Unsigned
|
||||
}
|
||||
|
||||
type Float interface {
|
||||
~float32 | ~float64
|
||||
}
|
||||
|
||||
type Complex interface {
|
||||
~complex64 | ~complex128
|
||||
}
|
17
v2/context/doc.go
Normal file
17
v2/context/doc.go
Normal file
@@ -0,0 +1,17 @@
|
||||
// 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 context contains versions of reader IO monads that work with a golang [context.Context]
|
||||
package context
|
33
v2/context/ioeither/generic/ioeither.go
Normal file
33
v2/context/ioeither/generic/ioeither.go
Normal file
@@ -0,0 +1,33 @@
|
||||
// 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"
|
||||
|
||||
E "github.com/IBM/fp-go/v2/either"
|
||||
IOE "github.com/IBM/fp-go/v2/ioeither/generic"
|
||||
)
|
||||
|
||||
// WithContext wraps an existing IOEither and performs a context check for cancellation before delegating
|
||||
func WithContext[GIO ~func() E.Either[error, A], A any](ctx context.Context, ma GIO) GIO {
|
||||
return IOE.MakeIO[GIO](func() E.Either[error, A] {
|
||||
if err := context.Cause(ctx); err != nil {
|
||||
return E.Left[A](err)
|
||||
}
|
||||
return ma()
|
||||
})
|
||||
}
|
33
v2/context/ioeither/ioeither.go
Normal file
33
v2/context/ioeither/ioeither.go
Normal file
@@ -0,0 +1,33 @@
|
||||
// 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 ioeither
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/IBM/fp-go/v2/either"
|
||||
IOE "github.com/IBM/fp-go/v2/ioeither"
|
||||
)
|
||||
|
||||
// withContext wraps an existing IOEither and performs a context check for cancellation before delegating
|
||||
func WithContext[A any](ctx context.Context, ma IOE.IOEither[error, A]) IOE.IOEither[error, A] {
|
||||
return func() either.Either[error, A] {
|
||||
if err := context.Cause(ctx); err != nil {
|
||||
return either.Left[A](err)
|
||||
}
|
||||
return ma()
|
||||
}
|
||||
}
|
33
v2/context/readereither/array.go
Normal file
33
v2/context/readereither/array.go
Normal file
@@ -0,0 +1,33 @@
|
||||
// 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 "github.com/IBM/fp-go/v2/readereither"
|
||||
|
||||
// TraverseArray transforms an array
|
||||
func TraverseArray[A, B any](f func(A) ReaderEither[B]) func([]A) ReaderEither[[]B] {
|
||||
return readereither.TraverseArray(f)
|
||||
}
|
||||
|
||||
// TraverseArrayWithIndex transforms an array
|
||||
func TraverseArrayWithIndex[A, B any](f func(int, A) ReaderEither[B]) func([]A) ReaderEither[[]B] {
|
||||
return readereither.TraverseArrayWithIndex(f)
|
||||
}
|
||||
|
||||
// SequenceArray converts a homogeneous sequence of either into an either of sequence
|
||||
func SequenceArray[A any](ma []ReaderEither[A]) ReaderEither[[]A] {
|
||||
return readereither.SequenceArray(ma)
|
||||
}
|
68
v2/context/readereither/bind.go
Normal file
68
v2/context/readereither/bind.go
Normal file
@@ -0,0 +1,68 @@
|
||||
// Copyright (c) 2023 IBM Corp.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package readereither
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
G "github.com/IBM/fp-go/v2/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)
|
||||
}
|
58
v2/context/readereither/bind_test.go
Normal file
58
v2/context/readereither/bind_test.go
Normal file
@@ -0,0 +1,58 @@
|
||||
// Copyright (c) 2023 IBM Corp.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package readereither
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
E "github.com/IBM/fp-go/v2/either"
|
||||
F "github.com/IBM/fp-go/v2/function"
|
||||
"github.com/IBM/fp-go/v2/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"))
|
||||
}
|
32
v2/context/readereither/cancel.go
Normal file
32
v2/context/readereither/cancel.go
Normal file
@@ -0,0 +1,32 @@
|
||||
// Copyright (c) 2023 IBM Corp.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package readereither
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
E "github.com/IBM/fp-go/v2/either"
|
||||
)
|
||||
|
||||
// withContext wraps an existing ReaderEither and performs a context check for cancellation before deletating
|
||||
func WithContext[A any](ma ReaderEither[A]) ReaderEither[A] {
|
||||
return func(ctx context.Context) E.Either[error, A] {
|
||||
if err := context.Cause(ctx); err != nil {
|
||||
return E.Left[A](err)
|
||||
}
|
||||
return ma(ctx)
|
||||
}
|
||||
}
|
53
v2/context/readereither/curry.go
Normal file
53
v2/context/readereither/curry.go
Normal file
@@ -0,0 +1,53 @@
|
||||
// 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"
|
||||
|
||||
"github.com/IBM/fp-go/v2/readereither"
|
||||
)
|
||||
|
||||
// these functions curry a golang function with the context as the firsr parameter into a either reader with the context as the last parameter
|
||||
// this goes back to the advice in https://pkg.go.dev/context to put the context as a first parameter as a convention
|
||||
|
||||
func Curry0[A any](f func(context.Context) (A, error)) ReaderEither[A] {
|
||||
return readereither.Curry0(f)
|
||||
}
|
||||
|
||||
func Curry1[T1, A any](f func(context.Context, T1) (A, error)) func(T1) ReaderEither[A] {
|
||||
return readereither.Curry1(f)
|
||||
}
|
||||
|
||||
func Curry2[T1, T2, A any](f func(context.Context, T1, T2) (A, error)) func(T1) func(T2) ReaderEither[A] {
|
||||
return readereither.Curry2(f)
|
||||
}
|
||||
|
||||
func Curry3[T1, T2, T3, A any](f func(context.Context, T1, T2, T3) (A, error)) func(T1) func(T2) func(T3) ReaderEither[A] {
|
||||
return readereither.Curry3(f)
|
||||
}
|
||||
|
||||
func Uncurry1[T1, A any](f func(T1) ReaderEither[A]) func(context.Context, T1) (A, error) {
|
||||
return readereither.Uncurry1(f)
|
||||
}
|
||||
|
||||
func Uncurry2[T1, T2, A any](f func(T1) func(T2) ReaderEither[A]) func(context.Context, T1, T2) (A, error) {
|
||||
return readereither.Uncurry2(f)
|
||||
}
|
||||
|
||||
func Uncurry3[T1, T2, T3, A any](f func(T1) func(T2) func(T3) ReaderEither[A]) func(context.Context, T1, T2, T3) (A, error) {
|
||||
return readereither.Uncurry3(f)
|
||||
}
|
39
v2/context/readereither/exec/exec.go
Normal file
39
v2/context/readereither/exec/exec.go
Normal file
@@ -0,0 +1,39 @@
|
||||
// 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 exec
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/IBM/fp-go/v2/context/readereither"
|
||||
"github.com/IBM/fp-go/v2/either"
|
||||
"github.com/IBM/fp-go/v2/exec"
|
||||
"github.com/IBM/fp-go/v2/function"
|
||||
INTE "github.com/IBM/fp-go/v2/internal/exec"
|
||||
)
|
||||
|
||||
var (
|
||||
// Command executes a command
|
||||
// use this version if the command does not produce any side effect, i.e. if the output is uniquely determined by by the input
|
||||
// typically you'd rather use the ReaderIOEither version of the command
|
||||
Command = function.Curry3(command)
|
||||
)
|
||||
|
||||
func command(name string, args []string, in []byte) readereither.ReaderEither[exec.CommandOutput] {
|
||||
return func(ctx context.Context) either.Either[error, exec.CommandOutput] {
|
||||
return either.TryCatchError(INTE.Exec(ctx, name, args, in))
|
||||
}
|
||||
}
|
41
v2/context/readereither/from.go
Normal file
41
v2/context/readereither/from.go
Normal file
@@ -0,0 +1,41 @@
|
||||
// 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"
|
||||
|
||||
"github.com/IBM/fp-go/v2/readereither"
|
||||
)
|
||||
|
||||
// these functions curry a golang function with the context as the firsr parameter into a either reader with the context as the last parameter
|
||||
// this goes back to the advice in https://pkg.go.dev/context to put the context as a first parameter as a convention
|
||||
|
||||
func From0[A any](f func(context.Context) (A, error)) func() ReaderEither[A] {
|
||||
return readereither.From0(f)
|
||||
}
|
||||
|
||||
func From1[T1, A any](f func(context.Context, T1) (A, error)) func(T1) ReaderEither[A] {
|
||||
return readereither.From1(f)
|
||||
}
|
||||
|
||||
func From2[T1, T2, A any](f func(context.Context, T1, T2) (A, error)) func(T1, T2) ReaderEither[A] {
|
||||
return readereither.From2(f)
|
||||
}
|
||||
|
||||
func From3[T1, T2, T3, A any](f func(context.Context, T1, T2, T3) (A, error)) func(T1, T2, T3) ReaderEither[A] {
|
||||
return readereither.From3(f)
|
||||
}
|
94
v2/context/readereither/reader.go
Normal file
94
v2/context/readereither/reader.go
Normal file
@@ -0,0 +1,94 @@
|
||||
// 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"
|
||||
|
||||
"github.com/IBM/fp-go/v2/readereither"
|
||||
)
|
||||
|
||||
func FromEither[A any](e Either[A]) ReaderEither[A] {
|
||||
return readereither.FromEither[context.Context](e)
|
||||
}
|
||||
|
||||
func Left[A any](l error) ReaderEither[A] {
|
||||
return readereither.Left[context.Context, A](l)
|
||||
}
|
||||
|
||||
func Right[A any](r A) ReaderEither[A] {
|
||||
return readereither.Right[context.Context, error](r)
|
||||
}
|
||||
|
||||
func MonadMap[A, B any](fa ReaderEither[A], f func(A) B) ReaderEither[B] {
|
||||
return readereither.MonadMap(fa, f)
|
||||
}
|
||||
|
||||
func Map[A, B any](f func(A) B) Operator[A, B] {
|
||||
return readereither.Map[context.Context, error](f)
|
||||
}
|
||||
|
||||
func MonadChain[A, B any](ma ReaderEither[A], f func(A) ReaderEither[B]) ReaderEither[B] {
|
||||
return readereither.MonadChain(ma, f)
|
||||
}
|
||||
|
||||
func Chain[A, B any](f func(A) ReaderEither[B]) Operator[A, B] {
|
||||
return readereither.Chain(f)
|
||||
}
|
||||
|
||||
func Of[A any](a A) ReaderEither[A] {
|
||||
return readereither.Of[context.Context, error](a)
|
||||
}
|
||||
|
||||
func MonadAp[A, B any](fab ReaderEither[func(A) B], fa ReaderEither[A]) ReaderEither[B] {
|
||||
return readereither.MonadAp(fab, fa)
|
||||
}
|
||||
|
||||
func Ap[A, B any](fa ReaderEither[A]) func(ReaderEither[func(A) B]) ReaderEither[B] {
|
||||
return readereither.Ap[B](fa)
|
||||
}
|
||||
|
||||
func FromPredicate[A any](pred func(A) bool, onFalse func(A) error) func(A) ReaderEither[A] {
|
||||
return readereither.FromPredicate[context.Context](pred, onFalse)
|
||||
}
|
||||
|
||||
func OrElse[A any](onLeft func(error) ReaderEither[A]) func(ReaderEither[A]) ReaderEither[A] {
|
||||
return readereither.OrElse(onLeft)
|
||||
}
|
||||
|
||||
func Ask() ReaderEither[context.Context] {
|
||||
return readereither.Ask[context.Context, error]()
|
||||
}
|
||||
|
||||
func MonadChainEitherK[A, B any](ma ReaderEither[A], f func(A) Either[B]) ReaderEither[B] {
|
||||
return readereither.MonadChainEitherK(ma, f)
|
||||
}
|
||||
|
||||
func ChainEitherK[A, B any](f func(A) Either[B]) func(ma ReaderEither[A]) ReaderEither[B] {
|
||||
return readereither.ChainEitherK[context.Context](f)
|
||||
}
|
||||
|
||||
func ChainOptionK[A, B any](onNone func() error) func(func(A) Option[B]) Operator[A, B] {
|
||||
return readereither.ChainOptionK[context.Context, A, B](onNone)
|
||||
}
|
||||
|
||||
func MonadFlap[B, A any](fab ReaderEither[func(A) B], a A) ReaderEither[B] {
|
||||
return readereither.MonadFlap(fab, a)
|
||||
}
|
||||
|
||||
func Flap[B, A any](a A) Operator[func(A) B, B] {
|
||||
return readereither.Flap[context.Context, error, B](a)
|
||||
}
|
39
v2/context/readereither/sequence.go
Normal file
39
v2/context/readereither/sequence.go
Normal file
@@ -0,0 +1,39 @@
|
||||
// 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 (
|
||||
"github.com/IBM/fp-go/v2/readereither"
|
||||
"github.com/IBM/fp-go/v2/tuple"
|
||||
)
|
||||
|
||||
// SequenceT converts n inputs of higher kinded types into a higher kinded types of n strongly typed values, represented as a tuple
|
||||
|
||||
func SequenceT1[A any](a ReaderEither[A]) ReaderEither[tuple.Tuple1[A]] {
|
||||
return readereither.SequenceT1(a)
|
||||
}
|
||||
|
||||
func SequenceT2[A, B any](a ReaderEither[A], b ReaderEither[B]) ReaderEither[tuple.Tuple2[A, B]] {
|
||||
return readereither.SequenceT2(a, b)
|
||||
}
|
||||
|
||||
func SequenceT3[A, B, C any](a ReaderEither[A], b ReaderEither[B], c ReaderEither[C]) ReaderEither[tuple.Tuple3[A, B, C]] {
|
||||
return readereither.SequenceT3(a, b, c)
|
||||
}
|
||||
|
||||
func SequenceT4[A, B, C, D any](a ReaderEither[A], b ReaderEither[B], c ReaderEither[C], d ReaderEither[D]) ReaderEither[tuple.Tuple4[A, B, C, D]] {
|
||||
return readereither.SequenceT4(a, b, c, d)
|
||||
}
|
35
v2/context/readereither/type.go
Normal file
35
v2/context/readereither/type.go
Normal file
@@ -0,0 +1,35 @@
|
||||
// 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 implements a specialization of the Reader monad assuming a golang context as the context of the monad and a standard golang error
|
||||
package readereither
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/IBM/fp-go/v2/either"
|
||||
"github.com/IBM/fp-go/v2/option"
|
||||
"github.com/IBM/fp-go/v2/reader"
|
||||
"github.com/IBM/fp-go/v2/readereither"
|
||||
)
|
||||
|
||||
type (
|
||||
Option[A any] = option.Option[A]
|
||||
Either[A any] = either.Either[error, A]
|
||||
// ReaderEither is a specialization of the Reader monad for the typical golang scenario
|
||||
ReaderEither[A any] = readereither.ReaderEither[context.Context, error, A]
|
||||
|
||||
Operator[A, B any] = reader.Reader[ReaderEither[A], ReaderEither[B]]
|
||||
)
|
89
v2/context/readerioeither/bind.go
Normal file
89
v2/context/readerioeither/bind.go
Normal file
@@ -0,0 +1,89 @@
|
||||
// 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 (
|
||||
"github.com/IBM/fp-go/v2/internal/apply"
|
||||
"github.com/IBM/fp-go/v2/internal/chain"
|
||||
"github.com/IBM/fp-go/v2/internal/functor"
|
||||
)
|
||||
|
||||
// Bind creates an empty context of type [S] to be used with the [Bind] operation
|
||||
func Do[S any](
|
||||
empty S,
|
||||
) ReaderIOEither[S] {
|
||||
return Of(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 chain.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](
|
||||
setter func(T) func(S1) S2,
|
||||
f func(S1) T,
|
||||
) func(ReaderIOEither[S1]) ReaderIOEither[S2] {
|
||||
return functor.Let(
|
||||
Map[S1, S2],
|
||||
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 functor.LetTo(
|
||||
Map[S1, S2],
|
||||
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 chain.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 ReaderIOEither[T],
|
||||
) func(ReaderIOEither[S1]) ReaderIOEither[S2] {
|
||||
return apply.ApS(
|
||||
Ap[S2, T],
|
||||
Map[S1, func(T) S2],
|
||||
setter,
|
||||
fa,
|
||||
)
|
||||
}
|
58
v2/context/readerioeither/bind_test.go
Normal file
58
v2/context/readerioeither/bind_test.go
Normal file
@@ -0,0 +1,58 @@
|
||||
// Copyright (c) 2023 IBM Corp.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package readerioeither
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
E "github.com/IBM/fp-go/v2/either"
|
||||
F "github.com/IBM/fp-go/v2/function"
|
||||
"github.com/IBM/fp-go/v2/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"))
|
||||
}
|
44
v2/context/readerioeither/bracket.go
Normal file
44
v2/context/readerioeither/bracket.go
Normal file
@@ -0,0 +1,44 @@
|
||||
// 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"
|
||||
|
||||
"github.com/IBM/fp-go/v2/internal/bracket"
|
||||
"github.com/IBM/fp-go/v2/readerio"
|
||||
)
|
||||
|
||||
// Bracket makes sure that a resource is cleaned up in the event of an error. The release action is called regardless of
|
||||
// whether the body action returns and error or not.
|
||||
func Bracket[
|
||||
A, B, ANY any](
|
||||
|
||||
acquire ReaderIOEither[A],
|
||||
use func(A) ReaderIOEither[B],
|
||||
release func(A, Either[B]) ReaderIOEither[ANY],
|
||||
) ReaderIOEither[B] {
|
||||
return bracket.Bracket[ReaderIOEither[A], ReaderIOEither[B], ReaderIOEither[ANY], Either[B], A, B](
|
||||
readerio.Of[context.Context, Either[B]],
|
||||
MonadChain[A, B],
|
||||
readerio.MonadChain[context.Context, Either[B], Either[B]],
|
||||
MonadChain[ANY, B],
|
||||
|
||||
acquire,
|
||||
use,
|
||||
release,
|
||||
)
|
||||
}
|
33
v2/context/readerioeither/cancel.go
Normal file
33
v2/context/readerioeither/cancel.go
Normal file
@@ -0,0 +1,33 @@
|
||||
// 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"
|
||||
|
||||
CIOE "github.com/IBM/fp-go/v2/context/ioeither"
|
||||
"github.com/IBM/fp-go/v2/ioeither"
|
||||
)
|
||||
|
||||
// WithContext wraps an existing [ReaderIOEither] and performs a context check for cancellation before delegating
|
||||
func WithContext[A any](ma ReaderIOEither[A]) ReaderIOEither[A] {
|
||||
return func(ctx context.Context) IOEither[A] {
|
||||
if err := context.Cause(ctx); err != nil {
|
||||
return ioeither.Left[A](err)
|
||||
}
|
||||
return CIOE.WithContext(ctx, ma(ctx))
|
||||
}
|
||||
}
|
1
v2/context/readerioeither/data/file.txt
Normal file
1
v2/context/readerioeither/data/file.txt
Normal file
@@ -0,0 +1 @@
|
||||
Carsten
|
19
v2/context/readerioeither/doc.go
Normal file
19
v2/context/readerioeither/doc.go
Normal file
@@ -0,0 +1,19 @@
|
||||
// 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 contains a version of [ReaderIOEither] that takes a golang [context.Context] as its context and that assumes the standard go error
|
||||
package readerioeither
|
||||
|
||||
//go:generate go run ../.. contextreaderioeither --count 10 --filename gen.go
|
28
v2/context/readerioeither/eq.go
Normal file
28
v2/context/readerioeither/eq.go
Normal file
@@ -0,0 +1,28 @@
|
||||
// Copyright (c) 2023 IBM Corp.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package readerioeither
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/IBM/fp-go/v2/eq"
|
||||
RIOE "github.com/IBM/fp-go/v2/readerioeither"
|
||||
)
|
||||
|
||||
// Eq implements the equals predicate for values contained in the [ReaderIOEither] monad
|
||||
func Eq[A any](eq eq.Eq[Either[A]]) func(context.Context) eq.Eq[ReaderIOEither[A]] {
|
||||
return RIOE.Eq[context.Context](eq)
|
||||
}
|
39
v2/context/readerioeither/exec/exec.go
Normal file
39
v2/context/readerioeither/exec/exec.go
Normal file
@@ -0,0 +1,39 @@
|
||||
// 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 exec
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
RIOE "github.com/IBM/fp-go/v2/context/readerioeither"
|
||||
"github.com/IBM/fp-go/v2/exec"
|
||||
F "github.com/IBM/fp-go/v2/function"
|
||||
GE "github.com/IBM/fp-go/v2/internal/exec"
|
||||
IOE "github.com/IBM/fp-go/v2/ioeither"
|
||||
)
|
||||
|
||||
var (
|
||||
// Command executes a cancelable command
|
||||
Command = F.Curry3(command)
|
||||
)
|
||||
|
||||
func command(name string, args []string, in []byte) RIOE.ReaderIOEither[exec.CommandOutput] {
|
||||
return func(ctx context.Context) IOE.IOEither[error, exec.CommandOutput] {
|
||||
return IOE.TryCatchError(func() (exec.CommandOutput, error) {
|
||||
return GE.Exec(ctx, name, args, in)
|
||||
})
|
||||
}
|
||||
}
|
3
v2/context/readerioeither/file/data/file.json
Normal file
3
v2/context/readerioeither/file/data/file.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"data": "Carsten"
|
||||
}
|
64
v2/context/readerioeither/file/file.go
Normal file
64
v2/context/readerioeither/file/file.go
Normal file
@@ -0,0 +1,64 @@
|
||||
// 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 file
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
RIOE "github.com/IBM/fp-go/v2/context/readerioeither"
|
||||
ET "github.com/IBM/fp-go/v2/either"
|
||||
F "github.com/IBM/fp-go/v2/function"
|
||||
"github.com/IBM/fp-go/v2/internal/file"
|
||||
IOE "github.com/IBM/fp-go/v2/ioeither"
|
||||
IOEF "github.com/IBM/fp-go/v2/ioeither/file"
|
||||
)
|
||||
|
||||
var (
|
||||
// Open opens a file for reading within the given context
|
||||
Open = F.Flow3(
|
||||
IOEF.Open,
|
||||
RIOE.FromIOEither[*os.File],
|
||||
RIOE.WithContext[*os.File],
|
||||
)
|
||||
|
||||
// Remove removes a file by name
|
||||
Remove = F.Flow2(
|
||||
IOEF.Remove,
|
||||
RIOE.FromIOEither[string],
|
||||
)
|
||||
)
|
||||
|
||||
// Close closes an object
|
||||
func Close[C io.Closer](c C) RIOE.ReaderIOEither[any] {
|
||||
return F.Pipe2(
|
||||
c,
|
||||
IOEF.Close[C],
|
||||
RIOE.FromIOEither[any],
|
||||
)
|
||||
}
|
||||
|
||||
// ReadFile reads a file in the scope of a context
|
||||
func ReadFile(path string) RIOE.ReaderIOEither[[]byte] {
|
||||
return RIOE.WithResource[[]byte](Open(path), Close[*os.File])(func(r *os.File) RIOE.ReaderIOEither[[]byte] {
|
||||
return func(ctx context.Context) IOE.IOEither[error, []byte] {
|
||||
return func() ET.Either[error, []byte] {
|
||||
return file.ReadAll(ctx, r)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
51
v2/context/readerioeither/file/file_test.go
Normal file
51
v2/context/readerioeither/file/file_test.go
Normal file
@@ -0,0 +1,51 @@
|
||||
// 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 file
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
R "github.com/IBM/fp-go/v2/context/readerioeither"
|
||||
F "github.com/IBM/fp-go/v2/function"
|
||||
"github.com/IBM/fp-go/v2/io"
|
||||
J "github.com/IBM/fp-go/v2/json"
|
||||
)
|
||||
|
||||
type RecordType struct {
|
||||
Data string `json:"data"`
|
||||
}
|
||||
|
||||
func getData(r RecordType) string {
|
||||
return r.Data
|
||||
}
|
||||
|
||||
func ExampleReadFile() {
|
||||
|
||||
data := F.Pipe3(
|
||||
ReadFile("./data/file.json"),
|
||||
R.ChainEitherK(J.Unmarshal[RecordType]),
|
||||
R.ChainFirstIOK(io.Logf[RecordType]("Log: %v")),
|
||||
R.Map(getData),
|
||||
)
|
||||
|
||||
result := data(context.Background())
|
||||
|
||||
fmt.Println(result())
|
||||
|
||||
// Output:
|
||||
// Right[string](Carsten)
|
||||
}
|
52
v2/context/readerioeither/file/tempfile.go
Normal file
52
v2/context/readerioeither/file/tempfile.go
Normal file
@@ -0,0 +1,52 @@
|
||||
// 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 file
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
RIOE "github.com/IBM/fp-go/v2/context/readerioeither"
|
||||
F "github.com/IBM/fp-go/v2/function"
|
||||
IO "github.com/IBM/fp-go/v2/io"
|
||||
IOF "github.com/IBM/fp-go/v2/io/file"
|
||||
IOEF "github.com/IBM/fp-go/v2/ioeither/file"
|
||||
)
|
||||
|
||||
var (
|
||||
// onCreateTempFile creates a temp file with sensible defaults
|
||||
onCreateTempFile = CreateTemp("", "*")
|
||||
// destroy handler
|
||||
onReleaseTempFile = F.Flow4(
|
||||
IOF.Close[*os.File],
|
||||
IO.Map((*os.File).Name),
|
||||
RIOE.FromIO[string],
|
||||
RIOE.Chain(Remove),
|
||||
)
|
||||
)
|
||||
|
||||
// CreateTemp created a temp file with proper parametrization
|
||||
func CreateTemp(dir, pattern string) RIOE.ReaderIOEither[*os.File] {
|
||||
return F.Pipe2(
|
||||
IOEF.CreateTemp(dir, pattern),
|
||||
RIOE.FromIOEither[*os.File],
|
||||
RIOE.WithContext[*os.File],
|
||||
)
|
||||
}
|
||||
|
||||
// WithTempFile creates a temporary file, then invokes a callback to create a resource based on the file, then close and remove the temp file
|
||||
func WithTempFile[A any](f func(*os.File) RIOE.ReaderIOEither[A]) RIOE.ReaderIOEither[A] {
|
||||
return RIOE.WithResource[A](onCreateTempFile, onReleaseTempFile)(f)
|
||||
}
|
47
v2/context/readerioeither/file/tempfile_test.go
Normal file
47
v2/context/readerioeither/file/tempfile_test.go
Normal file
@@ -0,0 +1,47 @@
|
||||
// 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 file
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
RIOE "github.com/IBM/fp-go/v2/context/readerioeither"
|
||||
E "github.com/IBM/fp-go/v2/either"
|
||||
F "github.com/IBM/fp-go/v2/function"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestWithTempFile(t *testing.T) {
|
||||
|
||||
res := WithTempFile(onWriteAll[*os.File]([]byte("Carsten")))
|
||||
|
||||
assert.Equal(t, E.Of[error]([]byte("Carsten")), res(context.Background())())
|
||||
}
|
||||
|
||||
func TestWithTempFileOnClosedFile(t *testing.T) {
|
||||
|
||||
res := WithTempFile(func(f *os.File) RIOE.ReaderIOEither[[]byte] {
|
||||
return F.Pipe2(
|
||||
f,
|
||||
onWriteAll[*os.File]([]byte("Carsten")),
|
||||
RIOE.ChainFirst(F.Constant1[[]byte](Close(f))),
|
||||
)
|
||||
})
|
||||
|
||||
assert.Equal(t, E.Of[error]([]byte("Carsten")), res(context.Background())())
|
||||
}
|
57
v2/context/readerioeither/file/write.go
Normal file
57
v2/context/readerioeither/file/write.go
Normal file
@@ -0,0 +1,57 @@
|
||||
// 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 file
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
|
||||
RIOE "github.com/IBM/fp-go/v2/context/readerioeither"
|
||||
F "github.com/IBM/fp-go/v2/function"
|
||||
)
|
||||
|
||||
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) {
|
||||
return func() ([]byte, error) {
|
||||
_, err := w.Write(data)
|
||||
return data, err
|
||||
}
|
||||
}),
|
||||
RIOE.WithContext[[]byte],
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// WriteAll uses a generator function to create a stream, writes data to it and closes it
|
||||
func WriteAll[W io.WriteCloser](data []byte) func(acquire RIOE.ReaderIOEither[W]) RIOE.ReaderIOEither[[]byte] {
|
||||
onWrite := onWriteAll[W](data)
|
||||
return func(onCreate RIOE.ReaderIOEither[W]) RIOE.ReaderIOEither[[]byte] {
|
||||
return RIOE.WithResource[[]byte](
|
||||
onCreate,
|
||||
Close[W])(
|
||||
onWrite,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Write uses a generator function to create a stream, writes data to it and closes it
|
||||
func Write[R any, W io.WriteCloser](acquire RIOE.ReaderIOEither[W]) func(use func(W) RIOE.ReaderIOEither[R]) RIOE.ReaderIOEither[R] {
|
||||
return RIOE.WithResource[R](
|
||||
acquire,
|
||||
Close[W])
|
||||
}
|
1826
v2/context/readerioeither/gen.go
Normal file
1826
v2/context/readerioeither/gen.go
Normal file
File diff suppressed because it is too large
Load Diff
167
v2/context/readerioeither/generic/gen.go
Normal file
167
v2/context/readerioeither/generic/gen.go
Normal file
@@ -0,0 +1,167 @@
|
||||
package generic
|
||||
|
||||
// Code generated by go generate; DO NOT EDIT.
|
||||
// This file was generated by robots at
|
||||
// 2025-03-09 23:52:48.5677388 +0100 CET m=+0.002067301
|
||||
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
E "github.com/IBM/fp-go/v2/either"
|
||||
RE "github.com/IBM/fp-go/v2/readerioeither/generic"
|
||||
)
|
||||
|
||||
// Eitherize0 converts a function with 0 parameters returning a tuple into a function with 0 parameters returning a [GRA]
|
||||
// The inverse function is [Uneitherize0]
|
||||
func Eitherize0[GRA ~func(context.Context) GIOA, F ~func(context.Context) (R, error), GIOA ~func() E.Either[error, R], R any](f F) func() GRA {
|
||||
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)())
|
||||
}
|
||||
}
|
||||
|
||||
// Eitherize2 converts a function with 2 parameters returning a tuple into a function with 2 parameters returning a [GRA]
|
||||
// The inverse function is [Uneitherize2]
|
||||
func Eitherize2[GRA ~func(context.Context) GIOA, F ~func(context.Context, T0, T1) (R, error), GIOA ~func() E.Either[error, R], T0, T1, R any](f F) func(T0, T1) GRA {
|
||||
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)())
|
||||
}
|
||||
}
|
||||
|
||||
// Eitherize3 converts a function with 3 parameters returning a tuple into a function with 3 parameters returning a [GRA]
|
||||
// The inverse function is [Uneitherize3]
|
||||
func Eitherize3[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 F) func(T0, T1, T2) GRA {
|
||||
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)())
|
||||
}
|
||||
}
|
||||
|
||||
// Eitherize4 converts a function with 4 parameters returning a tuple into a function with 4 parameters returning a [GRA]
|
||||
// The inverse function is [Uneitherize4]
|
||||
func Eitherize4[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 F) func(T0, T1, T2, T3) GRA {
|
||||
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)())
|
||||
}
|
||||
}
|
||||
|
||||
// Eitherize5 converts a function with 5 parameters returning a tuple into a function with 5 parameters returning a [GRA]
|
||||
// The inverse function is [Uneitherize5]
|
||||
func Eitherize5[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 F) func(T0, T1, T2, T3, T4) GRA {
|
||||
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)())
|
||||
}
|
||||
}
|
||||
|
||||
// Eitherize6 converts a function with 6 parameters returning a tuple into a function with 6 parameters returning a [GRA]
|
||||
// The inverse function is [Uneitherize6]
|
||||
func Eitherize6[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 F) func(T0, T1, T2, T3, T4, T5) GRA {
|
||||
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)())
|
||||
}
|
||||
}
|
||||
|
||||
// Eitherize7 converts a function with 7 parameters returning a tuple into a function with 7 parameters returning a [GRA]
|
||||
// The inverse function is [Uneitherize7]
|
||||
func Eitherize7[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 F) func(T0, T1, T2, T3, T4, T5, T6) GRA {
|
||||
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)())
|
||||
}
|
||||
}
|
||||
|
||||
// Eitherize8 converts a function with 8 parameters returning a tuple into a function with 8 parameters returning a [GRA]
|
||||
// The inverse function is [Uneitherize8]
|
||||
func Eitherize8[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 F) func(T0, T1, T2, T3, T4, T5, T6, T7) GRA {
|
||||
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)())
|
||||
}
|
||||
}
|
||||
|
||||
// Eitherize9 converts a function with 9 parameters returning a tuple into a function with 9 parameters returning a [GRA]
|
||||
// The inverse function is [Uneitherize9]
|
||||
func Eitherize9[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 F) func(T0, T1, T2, T3, T4, T5, T6, T7, T8) GRA {
|
||||
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)())
|
||||
}
|
||||
}
|
||||
|
||||
// Eitherize10 converts a function with 10 parameters returning a tuple into a function with 10 parameters returning a [GRA]
|
||||
// The inverse function is [Uneitherize10]
|
||||
func Eitherize10[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 F) func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9) GRA {
|
||||
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)())
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user