mirror of
https://github.com/IBM/fp-go.git
synced 2025-08-28 19:49:07 +02:00
Compare commits
12 Commits
v1.0.19
...
cleue-most
Author | SHA1 | Date | |
---|---|---|---|
|
fb3b1f115c | ||
|
ce66cf2295 | ||
|
80e579dd0b | ||
|
ddafd1ee57 | ||
|
b5f077da71 | ||
|
1a0c40b419 | ||
|
d5d89b1853 | ||
|
0f061a5099 | ||
|
45e05f25ff | ||
|
a390d53451 | ||
|
1346b9378a | ||
|
befd4f471e |
@@ -73,7 +73,7 @@ This library aims to provide a set of data types and functions that make it easy
|
||||
|
||||
The library itself also comprises many small functions, but it's admittedly harder to maintain than code that uses it. However this asymmetry is intended because it offloads complexity from users into a central component.
|
||||
|
||||
## Comparation to Idiomatic Go
|
||||
## Comparison to Idiomatic Go
|
||||
|
||||
In this section we discuss how the functional APIs differ from idiomatic go function signatures and how to convert back and forth.
|
||||
|
||||
@@ -181,7 +181,7 @@ The `Map` operation for `ReaderIOEither` is defined as:
|
||||
func Map[R, E, A, B any](f func(A) B) func(fa ReaderIOEither[R, E, A]) ReaderIOEither[R, E, B]
|
||||
```
|
||||
|
||||
and in fact the equivalent operations for all other mondas follow the same pattern, we could try to introduce a new type for `ReaderIOEither` (without a parameter) as a HKT, e.g. like so (made-up syntax, does not work in go):
|
||||
and in fact the equivalent operations for all other monads follow the same pattern, we could try to introduce a new type for `ReaderIOEither` (without a parameter) as a HKT, e.g. like so (made-up syntax, does not work in go):
|
||||
|
||||
```go
|
||||
func Map[HKT, R, E, A, B any](f func(A) B) func(HKT[R, E, A]) HKT[R, E, B]
|
||||
|
@@ -304,3 +304,7 @@ func FoldMap[A, B any](m M.Monoid[B]) func(func(A) B) func([]A) B {
|
||||
func Fold[A any](m M.Monoid[A]) func([]A) A {
|
||||
return G.Fold[[]A](m)
|
||||
}
|
||||
|
||||
func Push[A any](a A) func([]A) []A {
|
||||
return G.Push[[]A](a)
|
||||
}
|
||||
|
@@ -28,6 +28,14 @@ func Of[GA ~[]A, A any](value A) GA {
|
||||
return GA{value}
|
||||
}
|
||||
|
||||
func Reduce[GA ~[]A, A, B any](fa GA, f func(B, A) B, initial B) B {
|
||||
return array.Reduce(fa, f, initial)
|
||||
}
|
||||
|
||||
func ReduceWithIndex[GA ~[]A, A, B any](fa GA, f func(int, B, A) B, initial B) B {
|
||||
return array.ReduceWithIndex(fa, f, initial)
|
||||
}
|
||||
|
||||
// From constructs an array from a set of variadic arguments
|
||||
func From[GA ~[]A, A any](data ...A) GA {
|
||||
return data
|
||||
@@ -105,6 +113,10 @@ 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 F.Bind2nd(MonadMap[GA, GB, A, B], f)
|
||||
}
|
||||
|
||||
func Size[GA ~[]A, A any](as GA) int {
|
||||
return len(as)
|
||||
}
|
||||
@@ -226,3 +238,7 @@ func Fold[AS ~[]A, A any](m M.Monoid[A]) func(AS) A {
|
||||
return array.Reduce(as, m.Concat, m.Empty())
|
||||
}
|
||||
}
|
||||
|
||||
func Push[GA ~[]A, A any](a A) func(GA) GA {
|
||||
return F.Bind2nd(array.Push[GA, A], a)
|
||||
}
|
||||
|
50
cli/tuple.go
50
cli/tuple.go
@@ -20,6 +20,7 @@ import (
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
C "github.com/urfave/cli/v2"
|
||||
@@ -36,8 +37,51 @@ func writeTupleType(f *os.File, symbol string, i int) {
|
||||
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 optionize version
|
||||
// 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++ {
|
||||
@@ -398,6 +442,10 @@ import (
|
||||
generateToArray(f, i)
|
||||
// generate fromArray
|
||||
generateFromArray(f, i)
|
||||
// generate push
|
||||
if i < count {
|
||||
generatePush(f, i)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@@ -2,7 +2,7 @@ package readerioeither
|
||||
|
||||
// Code generated by go generate; DO NOT EDIT.
|
||||
// This file was generated by robots at
|
||||
// 2023-08-11 11:37:34.0836986 +0200 CEST m=+0.009764601
|
||||
// 2023-08-17 22:58:56.457404 +0200 CEST m=+0.024265101
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
@@ -2,7 +2,7 @@ package generic
|
||||
|
||||
// Code generated by go generate; DO NOT EDIT.
|
||||
// This file was generated by robots at
|
||||
// 2023-08-11 11:37:34.0838811 +0200 CEST m=+0.009947101
|
||||
// 2023-08-17 22:58:56.457404 +0200 CEST m=+0.024265101
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
@@ -146,8 +146,8 @@ func FromOption[E, A any](onNone func() E) func(O.Option[A]) Either[E, A] {
|
||||
return O.Fold(F.Nullary2(onNone, Left[A, E]), Right[E, A])
|
||||
}
|
||||
|
||||
func ToOption[E, A any]() func(Either[E, A]) O.Option[A] {
|
||||
return Fold(F.Ignore1of1[E](O.None[A]), O.Some[A])
|
||||
func ToOption[E, A any](ma Either[E, A]) O.Option[A] {
|
||||
return MonadFold(ma, F.Ignore1of1[E](O.None[A]), O.Some[A])
|
||||
}
|
||||
|
||||
func FromError[A any](f func(a A) error) func(A) Either[error, A] {
|
||||
|
@@ -1,6 +1,6 @@
|
||||
// Code generated by go generate; DO NOT EDIT.
|
||||
// This file was generated by robots at
|
||||
// 2023-08-11 11:37:35.9608486 +0200 CEST m=+0.009664501
|
||||
// 2023-08-17 22:58:57.9925506 +0200 CEST m=+0.033401101
|
||||
|
||||
package either
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
// Code generated by go generate; DO NOT EDIT.
|
||||
// This file was generated by robots at
|
||||
// 2023-08-11 11:37:50.171038 +0200 CEST m=+0.031513801
|
||||
// 2023-08-17 22:59:01.9404821 +0200 CEST m=+0.161366801
|
||||
|
||||
package function
|
||||
|
||||
|
30
function/cache.go
Normal file
30
function/cache.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 function
|
||||
|
||||
import (
|
||||
G "github.com/IBM/fp-go/function/generic"
|
||||
)
|
||||
|
||||
// Cache converts a unary function into a unary function that caches the value depending on the parameter
|
||||
func Cache[K comparable, T any](f func(K) T) func(K) T {
|
||||
return G.Cache(f)
|
||||
}
|
||||
|
||||
// ContramapCache converts a unary function into a unary function that caches the value depending on the parameter
|
||||
func ContramapCache[A any, K comparable, T any](kf func(A) K) func(func(A) T) func(A) T {
|
||||
return G.ContramapCache[func(A) T](kf)
|
||||
}
|
50
function/cache_test.go
Normal file
50
function/cache_test.go
Normal file
@@ -0,0 +1,50 @@
|
||||
// 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 function
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestCache(t *testing.T) {
|
||||
var count int
|
||||
|
||||
withSideEffect := func(n int) int {
|
||||
count++
|
||||
return n
|
||||
}
|
||||
|
||||
cached := Cache(withSideEffect)
|
||||
|
||||
assert.Equal(t, 0, count)
|
||||
|
||||
assert.Equal(t, 10, cached(10))
|
||||
assert.Equal(t, 1, count)
|
||||
|
||||
assert.Equal(t, 10, cached(10))
|
||||
assert.Equal(t, 1, count)
|
||||
|
||||
assert.Equal(t, 20, cached(20))
|
||||
assert.Equal(t, 2, count)
|
||||
|
||||
assert.Equal(t, 20, cached(20))
|
||||
assert.Equal(t, 2, count)
|
||||
|
||||
assert.Equal(t, 10, cached(10))
|
||||
assert.Equal(t, 2, count)
|
||||
}
|
@@ -1,6 +1,6 @@
|
||||
// Code generated by go generate; DO NOT EDIT.
|
||||
// This file was generated by robots at
|
||||
// 2023-08-11 11:37:38.4916948 +0200 CEST m=+0.060448601
|
||||
// 2023-08-17 22:58:59.8663985 +0200 CEST m=+0.103744101
|
||||
|
||||
package function
|
||||
|
||||
|
65
function/generic/cache.go
Normal file
65
function/generic/cache.go
Normal file
@@ -0,0 +1,65 @@
|
||||
// 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 (
|
||||
"sync"
|
||||
|
||||
L "github.com/IBM/fp-go/internal/lazy"
|
||||
)
|
||||
|
||||
// Cache converts a unary function into a unary function that caches the value depending on the parameter
|
||||
func Cache[F ~func(K) T, K comparable, T any](f F) F {
|
||||
return ContramapCache[F](func(k K) K { return k })(f)
|
||||
}
|
||||
|
||||
// ContramapCache converts a unary function into a unary function that caches the value depending on the parameter
|
||||
func ContramapCache[F ~func(A) T, KF func(A) K, A any, K comparable, T any](kf KF) func(F) F {
|
||||
return CacheCallback[F](kf, getOrCreate[K, T]())
|
||||
}
|
||||
|
||||
// getOrCreate is a naive implementation of a cache, without bounds
|
||||
func getOrCreate[K comparable, T any]() func(K, func() func() T) func() T {
|
||||
cache := make(map[K]func() T)
|
||||
var l sync.Mutex
|
||||
|
||||
return func(k K, cb func() func() T) func() T {
|
||||
// only lock to access a lazy accessor to the value
|
||||
l.Lock()
|
||||
existing, ok := cache[k]
|
||||
if !ok {
|
||||
existing = cb()
|
||||
cache[k] = existing
|
||||
}
|
||||
l.Unlock()
|
||||
// compute the value outside of the lock
|
||||
return existing
|
||||
}
|
||||
}
|
||||
|
||||
// CacheCallback converts a unary function into a unary function that caches the value depending on the parameter
|
||||
func CacheCallback[F ~func(A) T, KF func(A) K, C ~func(K, func() func() T) func() T, A any, K comparable, T any](kf KF, getOrCreate C) func(F) F {
|
||||
return func(f F) F {
|
||||
return func(a A) T {
|
||||
// cache entry
|
||||
return getOrCreate(kf(a), func() func() T {
|
||||
return L.Memoize[func() T](func() T {
|
||||
return f(a)
|
||||
})
|
||||
})()
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,6 +1,6 @@
|
||||
// Code generated by go generate; DO NOT EDIT.
|
||||
// This file was generated by robots at
|
||||
// 2023-08-11 11:38:00.2678592 +0200 CEST m=+0.008890401
|
||||
// 2023-08-17 22:59:06.2987136 +0200 CEST m=+0.049156901
|
||||
|
||||
package identity
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
// Code generated by go generate; DO NOT EDIT.
|
||||
// This file was generated by robots at
|
||||
// 2023-08-11 11:38:01.6948567 +0200 CEST m=+0.013530301
|
||||
// 2023-08-17 22:59:08.1313362 +0200 CEST m=+0.111171801
|
||||
|
||||
package apply
|
||||
|
||||
|
@@ -42,10 +42,27 @@ func Reduce[GA ~[]A, A, B any](fa GA, f func(B, A) B, initial B) B {
|
||||
return current
|
||||
}
|
||||
|
||||
func ReduceWithIndex[GA ~[]A, A, B any](fa GA, f func(int, B, A) B, initial B) B {
|
||||
current := initial
|
||||
count := len(fa)
|
||||
for i := 0; i < count; i++ {
|
||||
current = f(i, current, fa[i])
|
||||
}
|
||||
return current
|
||||
}
|
||||
|
||||
func Append[GA ~[]A, A any](as GA, a A) GA {
|
||||
return append(as, a)
|
||||
}
|
||||
|
||||
func Push[GA ~[]A, A any](as GA, a A) GA {
|
||||
l := len(as)
|
||||
cpy := make(GA, l+1)
|
||||
copy(cpy, as)
|
||||
cpy[l] = a
|
||||
return cpy
|
||||
}
|
||||
|
||||
func Empty[GA ~[]A, A any]() GA {
|
||||
return make(GA, 0)
|
||||
}
|
||||
|
75
internal/bindt/bind.go
Normal file
75
internal/bindt/bind.go
Normal file
@@ -0,0 +1,75 @@
|
||||
// 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 bindt
|
||||
|
||||
import (
|
||||
F "github.com/IBM/fp-go/function"
|
||||
I "github.com/IBM/fp-go/identity"
|
||||
T "github.com/IBM/fp-go/tuple"
|
||||
)
|
||||
|
||||
func Bind[SET ~func(B) func(S1) S2, FCT ~func(S1) HKTB, S1, S2, B, HKTS1, HKTS2, HKTB any](
|
||||
mchain func(func(S1) HKTS2) func(HKTS1) HKTS2,
|
||||
mmap func(func(B) S2) func(HKTB) HKTS2,
|
||||
s SET,
|
||||
f FCT,
|
||||
) func(HKTS1) HKTS2 {
|
||||
return mchain(F.Flow3(
|
||||
T.Replicate2[S1],
|
||||
T.Map2(F.Flow2(
|
||||
I.Ap[S2, S1],
|
||||
F.Flow2(
|
||||
F.Bind1st(F.Flow2[SET, func(func(S1) S2) S2], s),
|
||||
mmap,
|
||||
)), f),
|
||||
T.Tupled2(I.MonadAp[HKTS2, HKTB]),
|
||||
))
|
||||
}
|
||||
|
||||
func BindTo[SET ~func(B) S2, S2, B, HKTS2, HKTB any](
|
||||
mmap func(func(B) S2) func(HKTB) HKTS2,
|
||||
s SET,
|
||||
) func(HKTB) HKTS2 {
|
||||
return mmap(s)
|
||||
}
|
||||
|
||||
func ApS[
|
||||
SET ~func(B) func(S1) S2,
|
||||
S1, S2, B, HKTS1S2, HKTS1, HKTS2, HKTB any,
|
||||
](
|
||||
ap func(HKTS1) func(HKTS1S2) HKTS2,
|
||||
mmap func(func(B) func(S1) S2) func(HKTB) HKTS1S2,
|
||||
s SET, fb HKTB) func(HKTS1) HKTS2 {
|
||||
|
||||
return F.Flow2(
|
||||
ap,
|
||||
I.Ap[HKTS2, HKTS1S2](mmap(s)(fb)),
|
||||
)
|
||||
}
|
||||
|
||||
func Let[SET ~func(B) func(S1) S2, FCT ~func(S1) B, S1, S2, B, HKTS1, HKTS2 any](
|
||||
mmap func(func(S1) S2) func(HKTS1) HKTS2,
|
||||
s SET,
|
||||
f FCT,
|
||||
) func(HKTS1) HKTS2 {
|
||||
return mmap(F.Flow3(
|
||||
T.Replicate2[S1],
|
||||
T.Map2(F.Flow2(
|
||||
I.Ap[S2, S1],
|
||||
F.Bind1st(F.Flow2[SET, func(func(S1) S2) S2], s)), f),
|
||||
T.Tupled2(I.MonadAp[S2, B]),
|
||||
))
|
||||
}
|
34
internal/lazy/memoize.go
Normal file
34
internal/lazy/memoize.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 lazy
|
||||
|
||||
import "sync"
|
||||
|
||||
// Memoize computes the value of the provided IO monad lazily but exactly once
|
||||
func Memoize[GA ~func() A, A any](ma GA) GA {
|
||||
// synchronization primitives
|
||||
var once sync.Once
|
||||
var result A
|
||||
// callback
|
||||
gen := func() {
|
||||
result = ma()
|
||||
}
|
||||
// returns our memoized wrapper
|
||||
return func() A {
|
||||
once.Do(gen)
|
||||
return result
|
||||
}
|
||||
}
|
@@ -1,6 +1,6 @@
|
||||
// Code generated by go generate; DO NOT EDIT.
|
||||
// This file was generated by robots at
|
||||
// 2023-08-11 11:38:07.3305497 +0200 CEST m=+0.014821301
|
||||
// 2023-08-17 22:59:10.1040409 +0200 CEST m=+0.089470201
|
||||
|
||||
package io
|
||||
|
||||
|
@@ -64,6 +64,28 @@ func MonadApFirst[GA ~func() A, GB ~func() B, GBA ~func() func(B) A, A, B any](f
|
||||
)
|
||||
}
|
||||
|
||||
// MonadApFirstPar combines two effectful actions, keeping only the result of the first.
|
||||
func MonadApFirstPar[GA ~func() A, GB ~func() B, GBA ~func() func(B) A, A, B any](first GA, second GB) GA {
|
||||
return G.MonadApFirst(
|
||||
MonadApPar[GB, GA, GBA, B, A],
|
||||
MonadMap[GA, GBA, A, func(B) A],
|
||||
|
||||
first,
|
||||
second,
|
||||
)
|
||||
}
|
||||
|
||||
// MonadApFirstSeq combines two effectful actions, keeping only the result of the first.
|
||||
func MonadApFirstSeq[GA ~func() A, GB ~func() B, GBA ~func() func(B) A, A, B any](first GA, second GB) GA {
|
||||
return G.MonadApFirst(
|
||||
MonadApSeq[GB, GA, GBA, B, A],
|
||||
MonadMap[GA, GBA, A, func(B) A],
|
||||
|
||||
first,
|
||||
second,
|
||||
)
|
||||
}
|
||||
|
||||
// ApFirst combines two effectful actions, keeping only the result of the first.
|
||||
func ApFirst[GA ~func() A, GB ~func() B, GBA ~func() func(B) A, A, B any](second GB) func(GA) GA {
|
||||
return G.ApFirst(
|
||||
@@ -74,6 +96,26 @@ func ApFirst[GA ~func() A, GB ~func() B, GBA ~func() func(B) A, A, B any](second
|
||||
)
|
||||
}
|
||||
|
||||
// ApFirstPar combines two effectful actions, keeping only the result of the first.
|
||||
func ApFirstPar[GA ~func() A, GB ~func() B, GBA ~func() func(B) A, A, B any](second GB) func(GA) GA {
|
||||
return G.ApFirst(
|
||||
MonadApPar[GB, GA, GBA, B, A],
|
||||
MonadMap[GA, GBA, A, func(B) A],
|
||||
|
||||
second,
|
||||
)
|
||||
}
|
||||
|
||||
// ApFirstSeq combines two effectful actions, keeping only the result of the first.
|
||||
func ApFirstSeq[GA ~func() A, GB ~func() B, GBA ~func() func(B) A, A, B any](second GB) func(GA) GA {
|
||||
return G.ApFirst(
|
||||
MonadApSeq[GB, GA, GBA, B, A],
|
||||
MonadMap[GA, GBA, A, func(B) A],
|
||||
|
||||
second,
|
||||
)
|
||||
}
|
||||
|
||||
// MonadApSecond combines two effectful actions, keeping only the result of the second.
|
||||
func MonadApSecond[GA ~func() A, GB ~func() B, GBB ~func() func(B) B, A, B any](first GA, second GB) GB {
|
||||
return G.MonadApSecond(
|
||||
|
@@ -1,6 +1,6 @@
|
||||
// Code generated by go generate; DO NOT EDIT.
|
||||
// This file was generated by robots at
|
||||
// 2023-08-11 11:38:07.3305497 +0200 CEST m=+0.014821301
|
||||
// 2023-08-17 22:59:10.1132645 +0200 CEST m=+0.098693801
|
||||
package generic
|
||||
|
||||
import (
|
||||
|
@@ -16,11 +16,11 @@
|
||||
package generic
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
F "github.com/IBM/fp-go/function"
|
||||
C "github.com/IBM/fp-go/internal/chain"
|
||||
L "github.com/IBM/fp-go/internal/lazy"
|
||||
)
|
||||
|
||||
// type IO[A any] = func() A
|
||||
@@ -119,18 +119,7 @@ func Flatten[GA ~func() A, GAA ~func() GA, A any](mma GAA) GA {
|
||||
|
||||
// Memoize computes the value of the provided IO monad lazily but exactly once
|
||||
func Memoize[GA ~func() A, A any](ma GA) GA {
|
||||
// synchronization primitives
|
||||
var once sync.Once
|
||||
var result A
|
||||
// callback
|
||||
gen := func() {
|
||||
result = ma()
|
||||
}
|
||||
// returns our memoized wrapper
|
||||
return func() A {
|
||||
once.Do(gen)
|
||||
return result
|
||||
}
|
||||
return L.Memoize[GA, A](ma)
|
||||
}
|
||||
|
||||
// Delay creates an operation that passes in the value after some delay
|
||||
|
44
ioeither/bind.go
Normal file
44
ioeither/bind.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 ioeither
|
||||
|
||||
import (
|
||||
G "github.com/IBM/fp-go/ioeither/generic"
|
||||
)
|
||||
|
||||
// Bind applies a function to an input state and merges the result into that state
|
||||
func Bind[E, A, S1, S2 any](s func(A) func(S1) S2, f func(S1) IOEither[E, A]) func(IOEither[E, S1]) IOEither[E, S2] {
|
||||
return G.Bind[IOEither[E, S1], IOEither[E, S2], IOEither[E, A], func(S1) IOEither[E, A]](s, f)
|
||||
}
|
||||
|
||||
// BindTo initializes some state based on a value
|
||||
func BindTo[
|
||||
E, A, S2 any](s func(A) S2) func(IOEither[E, A]) IOEither[E, S2] {
|
||||
return G.BindTo[IOEither[E, S2], IOEither[E, A]](s)
|
||||
}
|
||||
|
||||
func ApS[
|
||||
E, A, S1, S2 any,
|
||||
](s func(A) func(S1) S2, fa IOEither[E, A]) func(IOEither[E, S1]) IOEither[E, S2] {
|
||||
return G.ApS[IOEither[E, S1], IOEither[E, S2], IOEither[E, A], IOEither[E, func(S1) S2]](s, fa)
|
||||
}
|
||||
|
||||
func Let[E, A, S1, S2 any](
|
||||
s func(A) func(S1) S2,
|
||||
f func(S1) A,
|
||||
) func(IOEither[E, S1]) IOEither[E, S2] {
|
||||
return G.Let[IOEither[E, S1], IOEither[E, S2]](s, f)
|
||||
}
|
57
ioeither/examples_create_test.go
Normal file
57
ioeither/examples_create_test.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 ioeither
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
E "github.com/IBM/fp-go/either"
|
||||
)
|
||||
|
||||
func ExampleIOEither_creation() {
|
||||
// Build an IOEither
|
||||
leftValue := Left[string](fmt.Errorf("some error"))
|
||||
rightValue := Right[error]("value")
|
||||
|
||||
// Convert from Either
|
||||
eitherValue := E.Of[error](42)
|
||||
ioFromEither := FromEither(eitherValue)
|
||||
|
||||
// some predicate
|
||||
isEven := func(num int) (int, error) {
|
||||
if num%2 == 0 {
|
||||
return num, nil
|
||||
}
|
||||
return 0, fmt.Errorf("%d is an odd number", num)
|
||||
}
|
||||
fromEven := Eitherize1(isEven)
|
||||
leftFromPred := fromEven(3)
|
||||
rightFromPred := fromEven(4)
|
||||
|
||||
fmt.Println(leftValue())
|
||||
fmt.Println(rightValue())
|
||||
fmt.Println(ioFromEither())
|
||||
fmt.Println(leftFromPred())
|
||||
fmt.Println(rightFromPred())
|
||||
|
||||
// Output:
|
||||
// Left[*errors.errorString, string](some error)
|
||||
// Right[<nil>, string](value)
|
||||
// Right[<nil>, int](42)
|
||||
// Left[*errors.errorString, int](3 is an odd number)
|
||||
// Right[<nil>, int](4)
|
||||
|
||||
}
|
57
ioeither/examples_do_test.go
Normal file
57
ioeither/examples_do_test.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 ioeither
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
F "github.com/IBM/fp-go/function"
|
||||
IO "github.com/IBM/fp-go/io"
|
||||
T "github.com/IBM/fp-go/tuple"
|
||||
)
|
||||
|
||||
func ExampleIOEither_do() {
|
||||
foo := Of[error]("foo")
|
||||
bar := Of[error](1)
|
||||
|
||||
// quux consumes the state of three bindings and returns an [IO] instead of an [IOEither]
|
||||
quux := func(t T.Tuple3[string, int, string]) IO.IO[any] {
|
||||
return IO.FromImpure(func() {
|
||||
log.Printf("t1: %s, t2: %d, t3: %s", t.F1, t.F2, t.F3)
|
||||
})
|
||||
}
|
||||
|
||||
transform := func(t T.Tuple3[string, int, string]) int {
|
||||
return len(t.F1) + t.F2 + len(t.F3)
|
||||
}
|
||||
|
||||
b := F.Pipe5(
|
||||
foo,
|
||||
BindTo[error](T.Of[string]),
|
||||
ApS(T.Push1[string, int], bar),
|
||||
Bind(T.Push2[string, int, string], func(t T.Tuple2[string, int]) IOEither[error, string] {
|
||||
return Of[error](fmt.Sprintf("%s%d", t.F1, t.F2))
|
||||
}),
|
||||
ChainFirstIOK[error](quux),
|
||||
Map[error](transform),
|
||||
)
|
||||
|
||||
fmt.Println(b())
|
||||
|
||||
// Output:
|
||||
// Right[<nil>, int](8)
|
||||
}
|
45
ioeither/examples_extract_test.go
Normal file
45
ioeither/examples_extract_test.go
Normal file
@@ -0,0 +1,45 @@
|
||||
// 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 (
|
||||
"fmt"
|
||||
|
||||
E "github.com/IBM/fp-go/either"
|
||||
F "github.com/IBM/fp-go/function"
|
||||
IO "github.com/IBM/fp-go/io"
|
||||
)
|
||||
|
||||
func ExampleIOEither_extraction() {
|
||||
// IOEither
|
||||
someIOEither := Right[error](42)
|
||||
eitherValue := someIOEither() // E.Right(42)
|
||||
value := E.GetOrElse(F.Constant1[error](0))(eitherValue) // 42
|
||||
|
||||
// Or more directly
|
||||
infaillibleIO := GetOrElse(F.Constant1[error](IO.Of(0)))(someIOEither) // => IO.Right(42)
|
||||
valueFromIO := infaillibleIO() // => 42
|
||||
|
||||
fmt.Println(eitherValue)
|
||||
fmt.Println(value)
|
||||
fmt.Println(valueFromIO)
|
||||
|
||||
// Output:
|
||||
// Right[<nil>, int](42)
|
||||
// 42
|
||||
// 42
|
||||
|
||||
}
|
@@ -1,6 +1,6 @@
|
||||
// Code generated by go generate; DO NOT EDIT.
|
||||
// This file was generated by robots at
|
||||
// 2023-08-11 11:38:09.4187123 +0200 CEST m=+0.099620101
|
||||
// 2023-08-17 22:59:12.0033119 +0200 CEST m=+0.096740401
|
||||
|
||||
package ioeither
|
||||
|
||||
|
79
ioeither/generic/bind.go
Normal file
79
ioeither/generic/bind.go
Normal file
@@ -0,0 +1,79 @@
|
||||
// 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 (
|
||||
ET "github.com/IBM/fp-go/either"
|
||||
G "github.com/IBM/fp-go/internal/bindt"
|
||||
)
|
||||
|
||||
// Bind applies a function to an input state and merges the result into that state
|
||||
func Bind[
|
||||
GS1 ~func() ET.Either[E, S1],
|
||||
GS2 ~func() ET.Either[E, S2],
|
||||
GA ~func() ET.Either[E, A],
|
||||
FCT ~func(S1) GA,
|
||||
E any,
|
||||
SET ~func(A) func(S1) S2,
|
||||
A, S1, S2 any](s SET, f FCT) func(GS1) GS2 {
|
||||
return G.Bind(
|
||||
Chain[GS1, GS2, E, S1, S2],
|
||||
Map[GA, GS2, E, A, S2],
|
||||
s,
|
||||
f,
|
||||
)
|
||||
}
|
||||
|
||||
// BindTo initializes some state based on a value
|
||||
func BindTo[
|
||||
GS2 ~func() ET.Either[E, S2],
|
||||
GA ~func() ET.Either[E, A],
|
||||
E any,
|
||||
SET ~func(A) S2,
|
||||
A, S2 any](s SET) func(GA) GS2 {
|
||||
return G.BindTo(
|
||||
Map[GA, GS2, E, A, S2],
|
||||
s,
|
||||
)
|
||||
}
|
||||
|
||||
func ApS[
|
||||
GS1 ~func() ET.Either[E, S1],
|
||||
GS2 ~func() ET.Either[E, S2],
|
||||
GB ~func() ET.Either[E, B],
|
||||
GS1S2 ~func() ET.Either[E, func(S1) S2],
|
||||
SET ~func(B) func(S1) S2,
|
||||
E, S1, S2, B any,
|
||||
](s SET, fb GB) func(GS1) GS2 {
|
||||
return G.ApS[SET, S1, S2, B, GS1S2, GS1, GS2, GB](
|
||||
Ap[GS2, GS1S2, GS1, E, S1, S2],
|
||||
Map[GB, GS1S2, E, B, func(S1) S2],
|
||||
s,
|
||||
fb,
|
||||
)
|
||||
}
|
||||
|
||||
func Let[
|
||||
GS1 ~func() ET.Either[E, S1],
|
||||
GS2 ~func() ET.Either[E, S2],
|
||||
SET ~func(B) func(S1) S2,
|
||||
FCT ~func(S1) B,
|
||||
E, S1, S2, B any](
|
||||
s SET,
|
||||
f FCT,
|
||||
) func(GS1) GS2 {
|
||||
return G.Let[SET, FCT, S1, S2, B, GS1, GS2](Map[GS1, GS2, E, S1, S2], s, f)
|
||||
}
|
@@ -1,6 +1,6 @@
|
||||
// Code generated by go generate; DO NOT EDIT.
|
||||
// This file was generated by robots at
|
||||
// 2023-08-11 11:38:09.4489926 +0200 CEST m=+0.129900401
|
||||
// 2023-08-17 22:59:12.0246635 +0200 CEST m=+0.118092001
|
||||
package generic
|
||||
|
||||
import (
|
||||
|
@@ -1,6 +1,6 @@
|
||||
// Code generated by go generate; DO NOT EDIT.
|
||||
// This file was generated by robots at
|
||||
// 2023-08-11 11:38:12.1021634 +0200 CEST m=+0.041956701
|
||||
// 2023-08-17 22:59:14.0582736 +0200 CEST m=+0.248503201
|
||||
|
||||
package iooption
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
// Code generated by go generate; DO NOT EDIT.
|
||||
// This file was generated by robots at
|
||||
// 2023-08-11 11:38:12.1210201 +0200 CEST m=+0.060813401
|
||||
// 2023-08-17 22:59:14.0642289 +0200 CEST m=+0.254458501
|
||||
package generic
|
||||
|
||||
import (
|
||||
|
53
iterator/stateless/generic/reflect.go
Normal file
53
iterator/stateless/generic/reflect.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 generic
|
||||
|
||||
import (
|
||||
R "reflect"
|
||||
|
||||
F "github.com/IBM/fp-go/function"
|
||||
LG "github.com/IBM/fp-go/io/generic"
|
||||
L "github.com/IBM/fp-go/lazy"
|
||||
N "github.com/IBM/fp-go/number"
|
||||
I "github.com/IBM/fp-go/number/integer"
|
||||
O "github.com/IBM/fp-go/option"
|
||||
T "github.com/IBM/fp-go/tuple"
|
||||
)
|
||||
|
||||
func FromReflect[GR ~func() O.Option[T.Tuple2[GR, R.Value]]](val R.Value) GR {
|
||||
// recursive callback
|
||||
var recurse func(idx int) GR
|
||||
|
||||
// limits the index
|
||||
fromPred := O.FromPredicate(I.Between(0, val.Len()))
|
||||
|
||||
recurse = func(idx int) GR {
|
||||
return F.Pipe3(
|
||||
idx,
|
||||
L.Of[int],
|
||||
L.Map(fromPred),
|
||||
LG.Map[L.Lazy[O.Option[int]], GR](O.Map(
|
||||
F.Flow2(
|
||||
T.Replicate2[int],
|
||||
T.Map2(F.Flow2(N.Add(1), recurse), val.Index),
|
||||
),
|
||||
)),
|
||||
)
|
||||
}
|
||||
|
||||
// start the recursion
|
||||
return recurse(0)
|
||||
}
|
27
iterator/stateless/reflect.go
Normal file
27
iterator/stateless/reflect.go
Normal file
@@ -0,0 +1,27 @@
|
||||
// Copyright (c) 2023 IBM Corp.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package stateless
|
||||
|
||||
import (
|
||||
R "reflect"
|
||||
|
||||
G "github.com/IBM/fp-go/iterator/stateless/generic"
|
||||
)
|
||||
|
||||
// FromReflect creates an iterator that can iterate over types that define [R.Index] and [R.Len]
|
||||
func FromReflect(val R.Value) Iterator[R.Value] {
|
||||
return G.FromReflect[Iterator[R.Value]](val)
|
||||
}
|
38
iterator/stateless/reflect_test.go
Normal file
38
iterator/stateless/reflect_test.go
Normal file
@@ -0,0 +1,38 @@
|
||||
// Copyright (c) 2023 IBM Corp.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package stateless
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
A "github.com/IBM/fp-go/array"
|
||||
F "github.com/IBM/fp-go/function"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestReflect(t *testing.T) {
|
||||
ar := A.From("a", "b", "c")
|
||||
|
||||
res := F.Pipe3(
|
||||
reflect.ValueOf(ar),
|
||||
FromReflect,
|
||||
ToArray[reflect.Value],
|
||||
A.Map(reflect.Value.String),
|
||||
)
|
||||
|
||||
assert.Equal(t, ar, res)
|
||||
}
|
@@ -32,6 +32,6 @@ func ToTypeE[A any](src any) E.Either[error, A] {
|
||||
func ToTypeO[A any](src any) O.Option[A] {
|
||||
return F.Pipe1(
|
||||
ToTypeE[A](src),
|
||||
E.ToOption[error, A](),
|
||||
E.ToOption[error, A],
|
||||
)
|
||||
}
|
||||
|
38
lazy/example_lazy_test.go
Normal file
38
lazy/example_lazy_test.go
Normal file
@@ -0,0 +1,38 @@
|
||||
// Copyright (c) 2023 IBM Corp.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package lazy
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
F "github.com/IBM/fp-go/function"
|
||||
)
|
||||
|
||||
func ExampleLazy_creation() {
|
||||
// lazy function of a constant value
|
||||
val := Of(42)
|
||||
// create another function to transform this
|
||||
valS := F.Pipe1(
|
||||
val,
|
||||
Map(strconv.Itoa),
|
||||
)
|
||||
|
||||
fmt.Println(valS())
|
||||
|
||||
// Output:
|
||||
// 42
|
||||
}
|
@@ -72,18 +72,18 @@ func Chain[A, B any](f func(A) Lazy[B]) func(Lazy[A]) Lazy[B] {
|
||||
}
|
||||
|
||||
func MonadAp[B, A any](mab Lazy[func(A) B], ma Lazy[A]) Lazy[B] {
|
||||
return G.MonadAp[Lazy[A], Lazy[B]](mab, ma)
|
||||
return G.MonadApSeq[Lazy[A], Lazy[B]](mab, ma)
|
||||
}
|
||||
|
||||
func Ap[B, A any](ma Lazy[A]) func(Lazy[func(A) B]) Lazy[B] {
|
||||
return G.Ap[Lazy[B], Lazy[func(A) B], Lazy[A]](ma)
|
||||
return G.ApSeq[Lazy[B], Lazy[func(A) B], Lazy[A]](ma)
|
||||
}
|
||||
|
||||
func Flatten[A any](mma Lazy[Lazy[A]]) Lazy[A] {
|
||||
return G.Flatten(mma)
|
||||
}
|
||||
|
||||
// Memoize computes the value of the provided IO monad lazily but exactly once
|
||||
// Memoize computes the value of the provided [Lazy] monad lazily but exactly once
|
||||
func Memoize[A any](ma Lazy[A]) Lazy[A] {
|
||||
return G.Memoize(ma)
|
||||
}
|
||||
|
23
number/integer/string.go
Normal file
23
number/integer/string.go
Normal file
@@ -0,0 +1,23 @@
|
||||
// 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 integer
|
||||
|
||||
import "strconv"
|
||||
|
||||
var (
|
||||
// ToString converts an integer to a string
|
||||
ToString = strconv.Itoa
|
||||
)
|
@@ -1,6 +1,6 @@
|
||||
// Code generated by go generate; DO NOT EDIT.
|
||||
// This file was generated by robots at
|
||||
// 2023-08-11 11:38:14.9503867 +0200 CEST m=+0.020206701
|
||||
// 2023-08-17 22:59:16.3450991 +0200 CEST m=+0.104894201
|
||||
|
||||
package option
|
||||
|
||||
|
14
ord/ord.go
14
ord/ord.go
@@ -131,9 +131,7 @@ func FromStrictCompare[A C.Ordered]() Ord[A] {
|
||||
return MakeOrd(strictCompare[A], strictEq[A])
|
||||
}
|
||||
|
||||
/**
|
||||
* Test whether one value is _strictly less than_ another
|
||||
*/
|
||||
// Lt tests whether one value is _strictly less than_ another
|
||||
func Lt[A any](O Ord[A]) func(A) func(A) bool {
|
||||
return func(second A) func(A) bool {
|
||||
return func(first A) bool {
|
||||
@@ -142,9 +140,7 @@ func Lt[A any](O Ord[A]) func(A) func(A) bool {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test whether one value is less or equal than_ another
|
||||
*/
|
||||
// Leq Tests whether one value is less or equal than_ another
|
||||
func Leq[A any](O Ord[A]) func(A) func(A) bool {
|
||||
return func(second A) func(A) bool {
|
||||
return func(first A) bool {
|
||||
@@ -156,7 +152,7 @@ func Leq[A any](O Ord[A]) func(A) func(A) bool {
|
||||
/**
|
||||
* Test whether one value is _strictly greater than_ another
|
||||
*/
|
||||
func Gt[A any](O Ord[A]) func(A) func(A) bool {
|
||||
func cc[A any](O Ord[A]) func(A) func(A) bool {
|
||||
return func(second A) func(A) bool {
|
||||
return func(first A) bool {
|
||||
return O.Compare(first, second) > 0
|
||||
@@ -164,9 +160,7 @@ func Gt[A any](O Ord[A]) func(A) func(A) bool {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test whether one value is greater or equal than_ another
|
||||
*/
|
||||
// Geq tests whether one value is greater or equal than_ another
|
||||
func Geq[A any](O Ord[A]) func(A) func(A) bool {
|
||||
return func(second A) func(A) bool {
|
||||
return func(first A) bool {
|
||||
|
@@ -1,6 +1,6 @@
|
||||
// Code generated by go generate; DO NOT EDIT.
|
||||
// This file was generated by robots at
|
||||
// 2023-08-11 11:38:23.1396887 +0200 CEST m=+0.020805301
|
||||
// 2023-08-17 22:59:18.4448291 +0200 CEST m=+0.161369001
|
||||
|
||||
package reader
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
// Code generated by go generate; DO NOT EDIT.
|
||||
// This file was generated by robots at
|
||||
// 2023-08-11 11:38:23.1402159 +0200 CEST m=+0.021332501
|
||||
// 2023-08-17 22:59:18.5047315 +0200 CEST m=+0.221271401
|
||||
package generic
|
||||
|
||||
// From0 converts a function with 1 parameters returning a [R] into a function with 0 parameters returning a [GRA]
|
||||
|
@@ -1,6 +1,6 @@
|
||||
// Code generated by go generate; DO NOT EDIT.
|
||||
// This file was generated by robots at
|
||||
// 2023-08-11 11:38:26.9546728 +0200 CEST m=+0.032178301
|
||||
// 2023-08-17 22:59:21.3704716 +0200 CEST m=+0.110126101
|
||||
|
||||
package readerioeither
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
// Code generated by go generate; DO NOT EDIT.
|
||||
// This file was generated by robots at
|
||||
// 2023-08-11 11:38:26.9556725 +0200 CEST m=+0.033178001
|
||||
// 2023-08-17 22:59:21.3811525 +0200 CEST m=+0.120807001
|
||||
package generic
|
||||
|
||||
import (
|
||||
|
@@ -98,7 +98,7 @@ func MapRefWithIndex[K comparable, V, R any](f func(K, *V) R) func(map[K]V) map[
|
||||
}
|
||||
|
||||
// Lookup returns the entry for a key in a map if it exists
|
||||
func Lookup[K comparable, V any](k K) func(map[K]V) O.Option[V] {
|
||||
func Lookup[V any, K comparable](k K) func(map[K]V) O.Option[V] {
|
||||
return G.Lookup[map[K]V](k)
|
||||
}
|
||||
|
||||
|
@@ -71,8 +71,8 @@ func TestLookup(t *testing.T) {
|
||||
"b": "b",
|
||||
"c": "c",
|
||||
}
|
||||
assert.Equal(t, O.Some("a"), Lookup[string, string]("a")(data))
|
||||
assert.Equal(t, O.None[string](), Lookup[string, string]("a1")(data))
|
||||
assert.Equal(t, O.Some("a"), Lookup[string]("a")(data))
|
||||
assert.Equal(t, O.None[string](), Lookup[string]("a1")(data))
|
||||
}
|
||||
|
||||
func TestFilterChain(t *testing.T) {
|
||||
|
31
reflect/generic/reflect.go
Normal file
31
reflect/generic/reflect.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 generic
|
||||
|
||||
import (
|
||||
R "reflect"
|
||||
)
|
||||
|
||||
func Map[GA ~[]A, A any](f func(R.Value) A) func(R.Value) GA {
|
||||
return func(val R.Value) GA {
|
||||
l := val.Len()
|
||||
res := make(GA, l)
|
||||
for i := l - 1; i >= 0; i-- {
|
||||
res[i] = f(val.Index(i))
|
||||
}
|
||||
return res
|
||||
}
|
||||
}
|
42
reflect/reflect.go
Normal file
42
reflect/reflect.go
Normal file
@@ -0,0 +1,42 @@
|
||||
// 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 option
|
||||
|
||||
import (
|
||||
R "reflect"
|
||||
|
||||
F "github.com/IBM/fp-go/function"
|
||||
G "github.com/IBM/fp-go/reflect/generic"
|
||||
)
|
||||
|
||||
func ReduceWithIndex[A any](f func(int, A, R.Value) A, initial A) func(R.Value) A {
|
||||
return func(val R.Value) A {
|
||||
count := val.Len()
|
||||
current := initial
|
||||
for i := 0; i < count; i++ {
|
||||
current = f(i, current, val.Index(i))
|
||||
}
|
||||
return current
|
||||
}
|
||||
}
|
||||
|
||||
func Reduce[A any](f func(A, R.Value) A, initial A) func(R.Value) A {
|
||||
return ReduceWithIndex(F.Ignore1of3[int](f), initial)
|
||||
}
|
||||
|
||||
func Map[A any](f func(R.Value) A) func(R.Value) []A {
|
||||
return G.Map[[]A](f)
|
||||
}
|
6
samples/mostly-adequate/README.md
Normal file
6
samples/mostly-adequate/README.md
Normal file
@@ -0,0 +1,6 @@
|
||||
# Mostly Adequate: fp-go Companion Guide
|
||||
|
||||
This resource is meant to serve as a go "companion" resource to Professor [Frisby's Mostly Adequate Guide](https://github.com/MostlyAdequate/mostly-adequate-guide).
|
||||
|
||||
It is a port of the [mostly-adequate-fp-ts](https://github.com/ChuckJonas/mostly-adequate-fp-ts/) book.
|
||||
|
47
samples/mostly-adequate/chapter01_test.go
Normal file
47
samples/mostly-adequate/chapter01_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 mostlyadequate
|
||||
|
||||
import "fmt"
|
||||
|
||||
type Flock struct {
|
||||
Seagulls int
|
||||
}
|
||||
|
||||
func MakeFlock(n int) Flock {
|
||||
return Flock{Seagulls: n}
|
||||
}
|
||||
|
||||
func (f *Flock) Conjoin(other *Flock) *Flock {
|
||||
f.Seagulls += other.Seagulls
|
||||
return f
|
||||
}
|
||||
|
||||
func (f *Flock) Breed(other *Flock) *Flock {
|
||||
f.Seagulls = f.Seagulls * other.Seagulls
|
||||
return f
|
||||
}
|
||||
|
||||
func Example_flock() {
|
||||
|
||||
flockA := MakeFlock(4)
|
||||
flockB := MakeFlock(2)
|
||||
flockC := MakeFlock(0)
|
||||
|
||||
fmt.Println(flockA.Conjoin(&flockC).Breed(&flockB).Conjoin(flockA.Breed(&flockB)).Seagulls)
|
||||
|
||||
// Output: 32
|
||||
}
|
46
samples/mostly-adequate/chapter04_currying_test.go
Normal file
46
samples/mostly-adequate/chapter04_currying_test.go
Normal file
@@ -0,0 +1,46 @@
|
||||
// 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 mostlyadequate
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
F "github.com/IBM/fp-go/function"
|
||||
N "github.com/IBM/fp-go/number"
|
||||
I "github.com/IBM/fp-go/number/integer"
|
||||
S "github.com/IBM/fp-go/string"
|
||||
)
|
||||
|
||||
var (
|
||||
Match = F.Curry2((*regexp.Regexp).FindStringSubmatch)
|
||||
Split = F.Curry2(F.Bind3of3((*regexp.Regexp).Split)(-1))
|
||||
|
||||
Add = N.Add[int]
|
||||
ToString = I.ToString
|
||||
ToLower = strings.ToLower
|
||||
ToUpper = strings.ToUpper
|
||||
Concat = F.Curry2(S.Monoid.Concat)
|
||||
)
|
||||
|
||||
// Replace cannot be generated via [F.Curry3] because the order of parameters does not match our desired curried order
|
||||
func Replace(search *regexp.Regexp) func(replace string) func(s string) string {
|
||||
return func(replace string) func(s string) string {
|
||||
return func(s string) string {
|
||||
return search.ReplaceAllString(s, replace)
|
||||
}
|
||||
}
|
||||
}
|
60
samples/mostly-adequate/chapter05_composing_test.go
Normal file
60
samples/mostly-adequate/chapter05_composing_test.go
Normal file
@@ -0,0 +1,60 @@
|
||||
// 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 mostlyadequate
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
|
||||
A "github.com/IBM/fp-go/array"
|
||||
F "github.com/IBM/fp-go/function"
|
||||
S "github.com/IBM/fp-go/string"
|
||||
)
|
||||
|
||||
var (
|
||||
Exclaim = S.Format[string]("%s!")
|
||||
Shout = F.Flow2(ToUpper, Exclaim)
|
||||
Dasherize = F.Flow4(
|
||||
Replace(regexp.MustCompile(`\s{2,}`))(" "),
|
||||
Split(regexp.MustCompile(` `)),
|
||||
A.Map(ToLower),
|
||||
A.Intercalate(S.Monoid)("-"),
|
||||
)
|
||||
)
|
||||
|
||||
func Example_shout() {
|
||||
fmt.Println(Shout("send in the clowns"))
|
||||
|
||||
// Output: SEND IN THE CLOWNS!
|
||||
}
|
||||
|
||||
func Example_dasherize() {
|
||||
fmt.Println(Dasherize("The world is a vampire"))
|
||||
|
||||
// Output: the-world-is-a-vampire
|
||||
}
|
||||
|
||||
func Example_pipe() {
|
||||
output := F.Pipe2(
|
||||
"send in the clowns",
|
||||
ToUpper,
|
||||
Exclaim,
|
||||
)
|
||||
|
||||
fmt.Println(output)
|
||||
|
||||
// Output: SEND IN THE CLOWNS!
|
||||
}
|
133
samples/mostly-adequate/chapter08_tupperware_test.go
Normal file
133
samples/mostly-adequate/chapter08_tupperware_test.go
Normal file
@@ -0,0 +1,133 @@
|
||||
// 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 mostlyadequate
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
E "github.com/IBM/fp-go/either"
|
||||
"github.com/IBM/fp-go/errors"
|
||||
F "github.com/IBM/fp-go/function"
|
||||
N "github.com/IBM/fp-go/number"
|
||||
O "github.com/IBM/fp-go/option"
|
||||
"github.com/IBM/fp-go/ord"
|
||||
S "github.com/IBM/fp-go/string"
|
||||
)
|
||||
|
||||
type Account struct {
|
||||
Balance float32
|
||||
}
|
||||
|
||||
func MakeAccount(b float32) Account {
|
||||
return Account{Balance: b}
|
||||
}
|
||||
|
||||
func getBalance(a Account) float32 {
|
||||
return a.Balance
|
||||
}
|
||||
|
||||
var (
|
||||
ordFloat32 = ord.FromStrictCompare[float32]()
|
||||
UpdateLedger = F.Identity[Account]
|
||||
RemainingBalance = F.Flow2(
|
||||
getBalance,
|
||||
S.Format[float32]("Your balance is $%0.2f"),
|
||||
)
|
||||
FinishTransaction = F.Flow2(
|
||||
UpdateLedger,
|
||||
RemainingBalance,
|
||||
)
|
||||
getTwenty = F.Flow2(
|
||||
Withdraw(20),
|
||||
O.Fold(F.Constant("You're broke!"), FinishTransaction),
|
||||
)
|
||||
)
|
||||
|
||||
func Withdraw(amount float32) func(account Account) O.Option[Account] {
|
||||
|
||||
return F.Flow3(
|
||||
getBalance,
|
||||
O.FromPredicate(ord.Geq(ordFloat32)(amount)),
|
||||
O.Map(F.Flow2(
|
||||
N.Add(-amount),
|
||||
MakeAccount,
|
||||
)))
|
||||
}
|
||||
|
||||
type User struct {
|
||||
BirthDate string
|
||||
}
|
||||
|
||||
func getBirthDate(u User) string {
|
||||
return u.BirthDate
|
||||
}
|
||||
|
||||
func MakeUser(d string) User {
|
||||
return User{BirthDate: d}
|
||||
}
|
||||
|
||||
var parseDate = F.Bind1of2(E.Eitherize2(time.Parse))(time.DateOnly)
|
||||
|
||||
func GetAge(now time.Time) func(User) E.Either[error, float64] {
|
||||
return F.Flow3(
|
||||
getBirthDate,
|
||||
parseDate,
|
||||
E.Map[error](F.Flow3(
|
||||
now.Sub,
|
||||
time.Duration.Hours,
|
||||
N.Mul(1/24.0),
|
||||
)),
|
||||
)
|
||||
}
|
||||
|
||||
func Example_widthdraw() {
|
||||
fmt.Println(getTwenty(MakeAccount(200)))
|
||||
fmt.Println(getTwenty(MakeAccount(10)))
|
||||
|
||||
// Output:
|
||||
// Your balance is $180.00
|
||||
// You're broke!
|
||||
}
|
||||
|
||||
func Example_getAge() {
|
||||
now, err := time.Parse(time.DateOnly, "2023-09-01")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
fmt.Println(GetAge(now)(MakeUser("2005-12-12")))
|
||||
fmt.Println(GetAge(now)(MakeUser("July 4, 2001")))
|
||||
|
||||
fortune := F.Flow3(
|
||||
N.Add(365.0),
|
||||
S.Format[float64]("%0.0f"),
|
||||
Concat("If you survive, you will be "),
|
||||
)
|
||||
|
||||
zoltar := F.Flow3(
|
||||
GetAge(now),
|
||||
E.Map[error](fortune),
|
||||
E.GetOrElse(errors.ToString),
|
||||
)
|
||||
|
||||
fmt.Println(zoltar(MakeUser("2005-12-12")))
|
||||
|
||||
// Output:
|
||||
// Right[<nil>, float64](6472)
|
||||
// Left[*time.ParseError, float64](parsing time "July 4, 2001" as "2006-01-02": cannot parse "July 4, 2001" as "2006")
|
||||
// If you survive, you will be 6837
|
||||
}
|
64
samples/mostly-adequate/chapter09_monadiconions_test.go
Normal file
64
samples/mostly-adequate/chapter09_monadiconions_test.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 mostlyadequate
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
A "github.com/IBM/fp-go/array"
|
||||
F "github.com/IBM/fp-go/function"
|
||||
O "github.com/IBM/fp-go/option"
|
||||
)
|
||||
|
||||
type (
|
||||
Street struct {
|
||||
Name string
|
||||
Number int
|
||||
}
|
||||
|
||||
Address struct {
|
||||
Street Street
|
||||
Postcode string
|
||||
}
|
||||
|
||||
AddressBook struct {
|
||||
Addresses []Address
|
||||
}
|
||||
)
|
||||
|
||||
func getAddresses(ab AddressBook) []Address {
|
||||
return ab.Addresses
|
||||
}
|
||||
|
||||
func getStreet(s Address) Street {
|
||||
return s.Street
|
||||
}
|
||||
|
||||
var FirstAddressStreet = F.Flow3(
|
||||
getAddresses,
|
||||
A.Head[Address],
|
||||
O.Map(getStreet),
|
||||
)
|
||||
|
||||
func Example_street() {
|
||||
s := FirstAddressStreet(AddressBook{
|
||||
Addresses: A.From(Address{Street: Street{Name: "Mulburry", Number: 8402}, Postcode: "WC2N"}),
|
||||
})
|
||||
fmt.Println(s)
|
||||
|
||||
// Output:
|
||||
// Some[mostlyadequate.Street]({Mulburry 8402})
|
||||
}
|
19
samples/mostly-adequate/doc.go
Normal file
19
samples/mostly-adequate/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 mostlyadequate is meant to serve as a go "companion" resource to Professor [Frisby's Mostly Adequate Guide].
|
||||
//
|
||||
// [Frisby's Mostly Adequate Guide]: https://github.com/MostlyAdequate/mostly-adequate-guide
|
||||
package mostlyadequate
|
65
tuple/gen.go
65
tuple/gen.go
@@ -1,6 +1,6 @@
|
||||
// Code generated by go generate; DO NOT EDIT.
|
||||
// This file was generated by robots at
|
||||
// 2023-08-11 11:38:30.5947727 +0200 CEST m=+0.033600301
|
||||
// 2023-08-17 22:59:23.6923568 +0200 CEST m=+0.056359401
|
||||
|
||||
package tuple
|
||||
|
||||
@@ -205,6 +205,13 @@ func FromArray1[F1 ~func(R) T1, T1, R any](f1 F1) func(r []R) Tuple1[T1] {
|
||||
}
|
||||
}
|
||||
|
||||
// Push1 creates a [Tuple2] from a [Tuple1] by appending a constant value
|
||||
func Push1[T1, T2 any](value T2) func(Tuple1[T1]) Tuple2[T1, T2] {
|
||||
return func(t Tuple1[T1]) Tuple2[T1, T2] {
|
||||
return MakeTuple2(t.F1, value)
|
||||
}
|
||||
}
|
||||
|
||||
// MakeTuple2 is a function that converts its 2 parameters into a [Tuple2]
|
||||
func MakeTuple2[T1, T2 any](t1 T1, t2 T2) Tuple2[T1, T2] {
|
||||
return Tuple2[T1, T2]{t1, t2}
|
||||
@@ -315,6 +322,13 @@ func FromArray2[F1 ~func(R) T1, F2 ~func(R) T2, T1, T2, R any](f1 F1, f2 F2) fun
|
||||
}
|
||||
}
|
||||
|
||||
// Push2 creates a [Tuple3] from a [Tuple2] by appending a constant value
|
||||
func Push2[T1, T2, T3 any](value T3) func(Tuple2[T1, T2]) Tuple3[T1, T2, T3] {
|
||||
return func(t Tuple2[T1, T2]) Tuple3[T1, T2, T3] {
|
||||
return MakeTuple3(t.F1, t.F2, value)
|
||||
}
|
||||
}
|
||||
|
||||
// MakeTuple3 is a function that converts its 3 parameters into a [Tuple3]
|
||||
func MakeTuple3[T1, T2, T3 any](t1 T1, t2 T2, t3 T3) Tuple3[T1, T2, T3] {
|
||||
return Tuple3[T1, T2, T3]{t1, t2, t3}
|
||||
@@ -436,6 +450,13 @@ func FromArray3[F1 ~func(R) T1, F2 ~func(R) T2, F3 ~func(R) T3, T1, T2, T3, R an
|
||||
}
|
||||
}
|
||||
|
||||
// Push3 creates a [Tuple4] from a [Tuple3] by appending a constant value
|
||||
func Push3[T1, T2, T3, T4 any](value T4) func(Tuple3[T1, T2, T3]) Tuple4[T1, T2, T3, T4] {
|
||||
return func(t Tuple3[T1, T2, T3]) Tuple4[T1, T2, T3, T4] {
|
||||
return MakeTuple4(t.F1, t.F2, t.F3, value)
|
||||
}
|
||||
}
|
||||
|
||||
// MakeTuple4 is a function that converts its 4 parameters into a [Tuple4]
|
||||
func MakeTuple4[T1, T2, T3, T4 any](t1 T1, t2 T2, t3 T3, t4 T4) Tuple4[T1, T2, T3, T4] {
|
||||
return Tuple4[T1, T2, T3, T4]{t1, t2, t3, t4}
|
||||
@@ -568,6 +589,13 @@ func FromArray4[F1 ~func(R) T1, F2 ~func(R) T2, F3 ~func(R) T3, F4 ~func(R) T4,
|
||||
}
|
||||
}
|
||||
|
||||
// Push4 creates a [Tuple5] from a [Tuple4] by appending a constant value
|
||||
func Push4[T1, T2, T3, T4, T5 any](value T5) func(Tuple4[T1, T2, T3, T4]) Tuple5[T1, T2, T3, T4, T5] {
|
||||
return func(t Tuple4[T1, T2, T3, T4]) Tuple5[T1, T2, T3, T4, T5] {
|
||||
return MakeTuple5(t.F1, t.F2, t.F3, t.F4, value)
|
||||
}
|
||||
}
|
||||
|
||||
// MakeTuple5 is a function that converts its 5 parameters into a [Tuple5]
|
||||
func MakeTuple5[T1, T2, T3, T4, T5 any](t1 T1, t2 T2, t3 T3, t4 T4, t5 T5) Tuple5[T1, T2, T3, T4, T5] {
|
||||
return Tuple5[T1, T2, T3, T4, T5]{t1, t2, t3, t4, t5}
|
||||
@@ -711,6 +739,13 @@ func FromArray5[F1 ~func(R) T1, F2 ~func(R) T2, F3 ~func(R) T3, F4 ~func(R) T4,
|
||||
}
|
||||
}
|
||||
|
||||
// Push5 creates a [Tuple6] from a [Tuple5] by appending a constant value
|
||||
func Push5[T1, T2, T3, T4, T5, T6 any](value T6) func(Tuple5[T1, T2, T3, T4, T5]) Tuple6[T1, T2, T3, T4, T5, T6] {
|
||||
return func(t Tuple5[T1, T2, T3, T4, T5]) Tuple6[T1, T2, T3, T4, T5, T6] {
|
||||
return MakeTuple6(t.F1, t.F2, t.F3, t.F4, t.F5, value)
|
||||
}
|
||||
}
|
||||
|
||||
// MakeTuple6 is a function that converts its 6 parameters into a [Tuple6]
|
||||
func MakeTuple6[T1, T2, T3, T4, T5, T6 any](t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6) Tuple6[T1, T2, T3, T4, T5, T6] {
|
||||
return Tuple6[T1, T2, T3, T4, T5, T6]{t1, t2, t3, t4, t5, t6}
|
||||
@@ -865,6 +900,13 @@ func FromArray6[F1 ~func(R) T1, F2 ~func(R) T2, F3 ~func(R) T3, F4 ~func(R) T4,
|
||||
}
|
||||
}
|
||||
|
||||
// Push6 creates a [Tuple7] from a [Tuple6] by appending a constant value
|
||||
func Push6[T1, T2, T3, T4, T5, T6, T7 any](value T7) func(Tuple6[T1, T2, T3, T4, T5, T6]) Tuple7[T1, T2, T3, T4, T5, T6, T7] {
|
||||
return func(t Tuple6[T1, T2, T3, T4, T5, T6]) Tuple7[T1, T2, T3, T4, T5, T6, T7] {
|
||||
return MakeTuple7(t.F1, t.F2, t.F3, t.F4, t.F5, t.F6, value)
|
||||
}
|
||||
}
|
||||
|
||||
// MakeTuple7 is a function that converts its 7 parameters into a [Tuple7]
|
||||
func MakeTuple7[T1, T2, T3, T4, T5, T6, T7 any](t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6, t7 T7) Tuple7[T1, T2, T3, T4, T5, T6, T7] {
|
||||
return Tuple7[T1, T2, T3, T4, T5, T6, T7]{t1, t2, t3, t4, t5, t6, t7}
|
||||
@@ -1030,6 +1072,13 @@ func FromArray7[F1 ~func(R) T1, F2 ~func(R) T2, F3 ~func(R) T3, F4 ~func(R) T4,
|
||||
}
|
||||
}
|
||||
|
||||
// Push7 creates a [Tuple8] from a [Tuple7] by appending a constant value
|
||||
func Push7[T1, T2, T3, T4, T5, T6, T7, T8 any](value T8) func(Tuple7[T1, T2, T3, T4, T5, T6, T7]) Tuple8[T1, T2, T3, T4, T5, T6, T7, T8] {
|
||||
return func(t Tuple7[T1, T2, T3, T4, T5, T6, T7]) Tuple8[T1, T2, T3, T4, T5, T6, T7, T8] {
|
||||
return MakeTuple8(t.F1, t.F2, t.F3, t.F4, t.F5, t.F6, t.F7, value)
|
||||
}
|
||||
}
|
||||
|
||||
// MakeTuple8 is a function that converts its 8 parameters into a [Tuple8]
|
||||
func MakeTuple8[T1, T2, T3, T4, T5, T6, T7, T8 any](t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6, t7 T7, t8 T8) Tuple8[T1, T2, T3, T4, T5, T6, T7, T8] {
|
||||
return Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]{t1, t2, t3, t4, t5, t6, t7, t8}
|
||||
@@ -1206,6 +1255,13 @@ func FromArray8[F1 ~func(R) T1, F2 ~func(R) T2, F3 ~func(R) T3, F4 ~func(R) T4,
|
||||
}
|
||||
}
|
||||
|
||||
// Push8 creates a [Tuple9] from a [Tuple8] by appending a constant value
|
||||
func Push8[T1, T2, T3, T4, T5, T6, T7, T8, T9 any](value T9) func(Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]) Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9] {
|
||||
return func(t Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]) Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9] {
|
||||
return MakeTuple9(t.F1, t.F2, t.F3, t.F4, t.F5, t.F6, t.F7, t.F8, value)
|
||||
}
|
||||
}
|
||||
|
||||
// MakeTuple9 is a function that converts its 9 parameters into a [Tuple9]
|
||||
func MakeTuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9 any](t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6, t7 T7, t8 T8, t9 T9) Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9] {
|
||||
return Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]{t1, t2, t3, t4, t5, t6, t7, t8, t9}
|
||||
@@ -1393,6 +1449,13 @@ func FromArray9[F1 ~func(R) T1, F2 ~func(R) T2, F3 ~func(R) T3, F4 ~func(R) T4,
|
||||
}
|
||||
}
|
||||
|
||||
// Push9 creates a [Tuple10] from a [Tuple9] by appending a constant value
|
||||
func Push9[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10 any](value T10) func(Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]) Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10] {
|
||||
return func(t Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]) Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10] {
|
||||
return MakeTuple10(t.F1, t.F2, t.F3, t.F4, t.F5, t.F6, t.F7, t.F8, t.F9, value)
|
||||
}
|
||||
}
|
||||
|
||||
// MakeTuple10 is a function that converts its 10 parameters into a [Tuple10]
|
||||
func MakeTuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10 any](t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6, t7 T7, t8 T8, t9 T9, t10 T10) Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10] {
|
||||
return Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]{t1, t2, t3, t4, t5, t6, t7, t8, t9, t10}
|
||||
|
@@ -17,6 +17,10 @@
|
||||
// consider to use arrays for simplicity
|
||||
package tuple
|
||||
|
||||
func Of[T1 any](t T1) Tuple1[T1] {
|
||||
return MakeTuple1(t)
|
||||
}
|
||||
|
||||
func First[T1, T2 any](t Tuple2[T1, T2]) T1 {
|
||||
return t.F1
|
||||
}
|
||||
@@ -29,7 +33,7 @@ func Swap[T1, T2 any](t Tuple2[T1, T2]) Tuple2[T2, T1] {
|
||||
return MakeTuple2(t.F2, t.F1)
|
||||
}
|
||||
|
||||
func Of[T1, T2 any](e T2) func(T1) Tuple2[T1, T2] {
|
||||
func Of2[T1, T2 any](e T2) func(T1) Tuple2[T1, T2] {
|
||||
return func(t T1) Tuple2[T1, T2] {
|
||||
return MakeTuple2(t, e)
|
||||
}
|
||||
|
Reference in New Issue
Block a user