mirror of
https://github.com/IBM/fp-go.git
synced 2025-08-26 19:38:58 +02:00
Compare commits
4 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
6ab6ff094b | ||
|
e6e35d643c | ||
|
01d490b710 | ||
|
01786a054b |
@@ -27,16 +27,11 @@ const (
|
||||
|
||||
// MonadApSeq implements the applicative on a single thread by first executing mab and the ma
|
||||
func MonadApSeq[GA ~func() A, GB ~func() B, GAB ~func() func(A) B, A, B any](mab GAB, ma GA) GB {
|
||||
return MakeIO[GB](func() B {
|
||||
return F.Pipe1(
|
||||
ma(),
|
||||
mab(),
|
||||
)
|
||||
})
|
||||
return MonadChain(mab, F.Bind1st(MonadMap[GA, GB], ma))
|
||||
}
|
||||
|
||||
// MonadApPar implements the applicative on two threads, the main thread executes mab and the actuall
|
||||
// apply operation and the second thred computes ma. Communication between the threads happens via a channel
|
||||
// apply operation and the second thread computes ma. Communication between the threads happens via a channel
|
||||
func MonadApPar[GA ~func() A, GB ~func() B, GAB ~func() func(A) B, A, B any](mab GAB, ma GA) GB {
|
||||
return MakeIO[GB](func() B {
|
||||
c := make(chan A)
|
||||
|
@@ -32,6 +32,28 @@ func MonadTraverseArray[GB ~func() B, GBS ~func() BBS, AAS ~[]A, BBS ~[]B, A, B
|
||||
)
|
||||
}
|
||||
|
||||
func MonadTraverseArraySeq[GB ~func() B, GBS ~func() BBS, AAS ~[]A, BBS ~[]B, A, B any](tas AAS, f func(A) GB) GBS {
|
||||
return RA.MonadTraverse(
|
||||
Of[GBS, BBS],
|
||||
Map[GBS, func() func(B) BBS, BBS, func(B) BBS],
|
||||
ApSeq[GBS, func() func(B) BBS, GB],
|
||||
|
||||
tas,
|
||||
f,
|
||||
)
|
||||
}
|
||||
|
||||
func MonadTraverseArrayPar[GB ~func() B, GBS ~func() BBS, AAS ~[]A, BBS ~[]B, A, B any](tas AAS, f func(A) GB) GBS {
|
||||
return RA.MonadTraverse(
|
||||
Of[GBS, BBS],
|
||||
Map[GBS, func() func(B) BBS, BBS, func(B) BBS],
|
||||
ApPar[GBS, func() func(B) BBS, GB],
|
||||
|
||||
tas,
|
||||
f,
|
||||
)
|
||||
}
|
||||
|
||||
func TraverseArray[GB ~func() B, GBS ~func() BBS, AAS ~[]A, BBS ~[]B, A, B any](f func(A) GB) func(AAS) GBS {
|
||||
return RA.Traverse[AAS](
|
||||
Of[GBS, BBS],
|
||||
@@ -42,6 +64,26 @@ func TraverseArray[GB ~func() B, GBS ~func() BBS, AAS ~[]A, BBS ~[]B, A, B any](
|
||||
)
|
||||
}
|
||||
|
||||
func TraverseArraySeq[GB ~func() B, GBS ~func() BBS, AAS ~[]A, BBS ~[]B, A, B any](f func(A) GB) func(AAS) GBS {
|
||||
return RA.Traverse[AAS](
|
||||
Of[GBS, BBS],
|
||||
Map[GBS, func() func(B) BBS, BBS, func(B) BBS],
|
||||
ApSeq[GBS, func() func(B) BBS, GB],
|
||||
|
||||
f,
|
||||
)
|
||||
}
|
||||
|
||||
func TraverseArrayPar[GB ~func() B, GBS ~func() BBS, AAS ~[]A, BBS ~[]B, A, B any](f func(A) GB) func(AAS) GBS {
|
||||
return RA.Traverse[AAS](
|
||||
Of[GBS, BBS],
|
||||
Map[GBS, func() func(B) BBS, BBS, func(B) BBS],
|
||||
ApPar[GBS, func() func(B) BBS, GB],
|
||||
|
||||
f,
|
||||
)
|
||||
}
|
||||
|
||||
func TraverseArrayWithIndex[GB ~func() B, GBS ~func() BBS, AAS ~[]A, BBS ~[]B, A, B any](f func(int, A) GB) func(AAS) GBS {
|
||||
return RA.TraverseWithIndex[AAS](
|
||||
Of[GBS, BBS],
|
||||
@@ -52,10 +94,38 @@ func TraverseArrayWithIndex[GB ~func() B, GBS ~func() BBS, AAS ~[]A, BBS ~[]B, A
|
||||
)
|
||||
}
|
||||
|
||||
func TraverseArrayWithIndexSeq[GB ~func() B, GBS ~func() BBS, AAS ~[]A, BBS ~[]B, A, B any](f func(int, A) GB) func(AAS) GBS {
|
||||
return RA.TraverseWithIndex[AAS](
|
||||
Of[GBS, BBS],
|
||||
Map[GBS, func() func(B) BBS, BBS, func(B) BBS],
|
||||
ApSeq[GBS, func() func(B) BBS, GB],
|
||||
|
||||
f,
|
||||
)
|
||||
}
|
||||
|
||||
func TraverseArrayWithIndexPar[GB ~func() B, GBS ~func() BBS, AAS ~[]A, BBS ~[]B, A, B any](f func(int, A) GB) func(AAS) GBS {
|
||||
return RA.TraverseWithIndex[AAS](
|
||||
Of[GBS, BBS],
|
||||
Map[GBS, func() func(B) BBS, BBS, func(B) BBS],
|
||||
ApPar[GBS, func() func(B) BBS, GB],
|
||||
|
||||
f,
|
||||
)
|
||||
}
|
||||
|
||||
func SequenceArray[GA ~func() A, GAS ~func() AAS, AAS ~[]A, GAAS ~[]GA, A any](tas GAAS) GAS {
|
||||
return MonadTraverseArray[GA, GAS](tas, F.Identity[GA])
|
||||
}
|
||||
|
||||
func SequenceArraySeq[GA ~func() A, GAS ~func() AAS, AAS ~[]A, GAAS ~[]GA, A any](tas GAAS) GAS {
|
||||
return MonadTraverseArraySeq[GA, GAS](tas, F.Identity[GA])
|
||||
}
|
||||
|
||||
func SequenceArrayPar[GA ~func() A, GAS ~func() AAS, AAS ~[]A, GAAS ~[]GA, A any](tas GAAS) GAS {
|
||||
return MonadTraverseArrayPar[GA, GAS](tas, F.Identity[GA])
|
||||
}
|
||||
|
||||
// MonadTraverseRecord transforms a record using an IO transform an IO of a record
|
||||
func MonadTraverseRecord[GBS ~func() MB, MA ~map[K]A, GB ~func() B, MB ~map[K]B, K comparable, A, B any](ma MA, f func(A) GB) GBS {
|
||||
return RR.MonadTraverse[MA](
|
||||
@@ -89,3 +159,71 @@ func TraverseRecordWithIndex[GB ~func() B, GBS ~func() MB, MA ~map[K]A, MB ~map[
|
||||
func SequenceRecord[GA ~func() A, GAS ~func() AAS, AAS ~map[K]A, GAAS ~map[K]GA, K comparable, A any](tas GAAS) GAS {
|
||||
return MonadTraverseRecord[GAS](tas, F.Identity[GA])
|
||||
}
|
||||
|
||||
// MonadTraverseRecordSeq transforms a record using an IO transform an IO of a record
|
||||
func MonadTraverseRecordSeq[GBS ~func() MB, MA ~map[K]A, GB ~func() B, MB ~map[K]B, K comparable, A, B any](ma MA, f func(A) GB) GBS {
|
||||
return RR.MonadTraverse[MA](
|
||||
Of[GBS, MB],
|
||||
Map[GBS, func() func(B) MB, MB, func(B) MB],
|
||||
ApSeq[GBS, func() func(B) MB, GB],
|
||||
ma, f,
|
||||
)
|
||||
}
|
||||
|
||||
// TraverseRecordSeq transforms a record using an IO transform an IO of a record
|
||||
func TraverseRecordSeq[GBS ~func() MB, MA ~map[K]A, GB ~func() B, MB ~map[K]B, K comparable, A, B any](f func(A) GB) func(MA) GBS {
|
||||
return RR.Traverse[MA](
|
||||
Of[GBS, MB],
|
||||
Map[GBS, func() func(B) MB, MB, func(B) MB],
|
||||
ApSeq[GBS, func() func(B) MB, GB],
|
||||
f,
|
||||
)
|
||||
}
|
||||
|
||||
// TraverseRecordWithIndexSeq transforms a record using an IO transform an IO of a record
|
||||
func TraverseRecordWithIndexSeq[GB ~func() B, GBS ~func() MB, MA ~map[K]A, MB ~map[K]B, K comparable, A, B any](f func(K, A) GB) func(MA) GBS {
|
||||
return RR.TraverseWithIndex[MA](
|
||||
Of[GBS, MB],
|
||||
Map[GBS, func() func(B) MB, MB, func(B) MB],
|
||||
ApSeq[GBS, func() func(B) MB, GB],
|
||||
f,
|
||||
)
|
||||
}
|
||||
|
||||
func SequenceRecordSeq[GA ~func() A, GAS ~func() AAS, AAS ~map[K]A, GAAS ~map[K]GA, K comparable, A any](tas GAAS) GAS {
|
||||
return MonadTraverseRecordSeq[GAS](tas, F.Identity[GA])
|
||||
}
|
||||
|
||||
// MonadTraverseRecordPar transforms a record using an IO transform an IO of a record
|
||||
func MonadTraverseRecordPar[GBS ~func() MB, MA ~map[K]A, GB ~func() B, MB ~map[K]B, K comparable, A, B any](ma MA, f func(A) GB) GBS {
|
||||
return RR.MonadTraverse[MA](
|
||||
Of[GBS, MB],
|
||||
Map[GBS, func() func(B) MB, MB, func(B) MB],
|
||||
ApPar[GBS, func() func(B) MB, GB],
|
||||
ma, f,
|
||||
)
|
||||
}
|
||||
|
||||
// TraverseRecordPar transforms a record using an IO transform an IO of a record
|
||||
func TraverseRecordPar[GBS ~func() MB, MA ~map[K]A, GB ~func() B, MB ~map[K]B, K comparable, A, B any](f func(A) GB) func(MA) GBS {
|
||||
return RR.Traverse[MA](
|
||||
Of[GBS, MB],
|
||||
Map[GBS, func() func(B) MB, MB, func(B) MB],
|
||||
ApPar[GBS, func() func(B) MB, GB],
|
||||
f,
|
||||
)
|
||||
}
|
||||
|
||||
// TraverseRecordWithIndexPar transforms a record using an IO transform an IO of a record
|
||||
func TraverseRecordWithIndexPar[GB ~func() B, GBS ~func() MB, MA ~map[K]A, MB ~map[K]B, K comparable, A, B any](f func(K, A) GB) func(MA) GBS {
|
||||
return RR.TraverseWithIndex[MA](
|
||||
Of[GBS, MB],
|
||||
Map[GBS, func() func(B) MB, MB, func(B) MB],
|
||||
ApPar[GBS, func() func(B) MB, GB],
|
||||
f,
|
||||
)
|
||||
}
|
||||
|
||||
func SequenceRecordPar[GA ~func() A, GAS ~func() AAS, AAS ~map[K]A, GAAS ~map[K]GA, K comparable, A any](tas GAAS) GAS {
|
||||
return MonadTraverseRecordPar[GAS](tas, F.Identity[GA])
|
||||
}
|
||||
|
47
io/sequence_test.go
Normal file
47
io/sequence_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 io
|
||||
|
||||
import (
|
||||
A "github.com/IBM/fp-go/array"
|
||||
F "github.com/IBM/fp-go/function"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestMapSeq(t *testing.T) {
|
||||
var results []string
|
||||
|
||||
handler := func(value string) IO[string] {
|
||||
return func() string {
|
||||
results = append(results, value)
|
||||
return value
|
||||
}
|
||||
}
|
||||
|
||||
src := A.From("a", "b", "c")
|
||||
|
||||
res := F.Pipe2(
|
||||
src,
|
||||
TraverseArraySeq(handler),
|
||||
Map(func(data []string) bool {
|
||||
return assert.Equal(t, data, results)
|
||||
}),
|
||||
)
|
||||
|
||||
assert.True(t, res())
|
||||
}
|
@@ -60,3 +60,45 @@ func TraverseRecordWithIndex[K comparable, A, B any](f func(K, A) IO[B]) func(ma
|
||||
func SequenceRecord[K comparable, A any](tas map[K]IO[A]) IO[map[K]A] {
|
||||
return G.SequenceRecord[IO[A], IO[map[K]A]](tas)
|
||||
}
|
||||
|
||||
func MonadTraverseArraySeq[A, B any](tas []A, f func(A) IO[B]) IO[[]B] {
|
||||
return G.MonadTraverseArraySeq[IO[B], IO[[]B]](tas, f)
|
||||
}
|
||||
|
||||
// TraverseArraySeq applies a function returning an [IO] to all elements in an array and the
|
||||
// transforms this into an [IO] of that array
|
||||
func TraverseArraySeq[A, B any](f func(A) IO[B]) func([]A) IO[[]B] {
|
||||
return G.TraverseArraySeq[IO[B], IO[[]B], []A](f)
|
||||
}
|
||||
|
||||
// TraverseArrayWithIndexSeq applies a function returning an [IO] to all elements in an array and the
|
||||
// transforms this into an [IO] of that array
|
||||
func TraverseArrayWithIndexSeq[A, B any](f func(int, A) IO[B]) func([]A) IO[[]B] {
|
||||
return G.TraverseArrayWithIndexSeq[IO[B], IO[[]B], []A](f)
|
||||
}
|
||||
|
||||
// SequenceArraySeq converts an array of [IO] to an [IO] of an array
|
||||
func SequenceArraySeq[A any](tas []IO[A]) IO[[]A] {
|
||||
return G.SequenceArraySeq[IO[A], IO[[]A]](tas)
|
||||
}
|
||||
|
||||
func MonadTraverseRecordSeq[K comparable, A, B any](tas map[K]A, f func(A) IO[B]) IO[map[K]B] {
|
||||
return G.MonadTraverseRecordSeq[IO[map[K]B]](tas, f)
|
||||
}
|
||||
|
||||
// TraverseRecord applies a function returning an [IO] to all elements in a record and the
|
||||
// transforms this into an [IO] of that record
|
||||
func TraverseRecordSeq[K comparable, A, B any](f func(A) IO[B]) func(map[K]A) IO[map[K]B] {
|
||||
return G.TraverseRecordSeq[IO[map[K]B], map[K]A, IO[B]](f)
|
||||
}
|
||||
|
||||
// TraverseRecordWithIndexSeq applies a function returning an [IO] to all elements in a record and the
|
||||
// transforms this into an [IO] of that record
|
||||
func TraverseRecordWithIndeSeq[K comparable, A, B any](f func(K, A) IO[B]) func(map[K]A) IO[map[K]B] {
|
||||
return G.TraverseRecordWithIndexSeq[IO[B], IO[map[K]B], map[K]A](f)
|
||||
}
|
||||
|
||||
// SequenceRecordSeq converts a record of [IO] to an [IO] of a record
|
||||
func SequenceRecordSeq[K comparable, A any](tas map[K]IO[A]) IO[map[K]A] {
|
||||
return G.SequenceRecordSeq[IO[A], IO[map[K]A]](tas)
|
||||
}
|
||||
|
48
ioeither/sequence_test.go
Normal file
48
ioeither/sequence_test.go
Normal file
@@ -0,0 +1,48 @@
|
||||
// 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 (
|
||||
A "github.com/IBM/fp-go/array"
|
||||
E "github.com/IBM/fp-go/either"
|
||||
F "github.com/IBM/fp-go/function"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestMapSeq(t *testing.T) {
|
||||
var results []string
|
||||
|
||||
handler := func(value string) IOEither[error, string] {
|
||||
return func() E.Either[error, string] {
|
||||
results = append(results, value)
|
||||
return E.Of[error](value)
|
||||
}
|
||||
}
|
||||
|
||||
src := A.From("a", "b", "c")
|
||||
|
||||
res := F.Pipe2(
|
||||
src,
|
||||
TraverseArraySeq(handler),
|
||||
Map[error](func(data []string) bool {
|
||||
return assert.Equal(t, data, results)
|
||||
}),
|
||||
)
|
||||
|
||||
assert.Equal(t, E.Of[error](true), res())
|
||||
}
|
3
scan.bat
Normal file
3
scan.bat
Normal file
@@ -0,0 +1,3 @@
|
||||
@echo off
|
||||
|
||||
busybox find . -type f -name "*\.go" | busybox xargs gopls check
|
31
state/eq.go
Normal file
31
state/eq.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 state
|
||||
|
||||
import (
|
||||
EQ "github.com/IBM/fp-go/eq"
|
||||
G "github.com/IBM/fp-go/state/generic"
|
||||
)
|
||||
|
||||
// Constructs an equal predicate for a [State]
|
||||
func Eq[S, A any](w EQ.Eq[S], a EQ.Eq[A]) func(S) EQ.Eq[State[S, A]] {
|
||||
return G.Eq[State[S, A]](w, a)
|
||||
}
|
||||
|
||||
// FromStrictEquals constructs an [EQ.Eq] from the canonical comparison function
|
||||
func FromStrictEquals[S, A comparable]() func(S) EQ.Eq[State[S, A]] {
|
||||
return G.FromStrictEquals[State[S, A]]()
|
||||
}
|
36
state/generic/eq.go
Normal file
36
state/generic/eq.go
Normal file
@@ -0,0 +1,36 @@
|
||||
// Copyright (c) 2023 IBM Corp.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package generic
|
||||
|
||||
import (
|
||||
EQ "github.com/IBM/fp-go/eq"
|
||||
P "github.com/IBM/fp-go/pair"
|
||||
)
|
||||
|
||||
// Constructs an equal predicate for a [State]
|
||||
func Eq[GA ~func(S) P.Pair[A, S], S, A any](w EQ.Eq[S], a EQ.Eq[A]) func(S) EQ.Eq[GA] {
|
||||
eqp := P.Eq(a, w)
|
||||
return func(s S) EQ.Eq[GA] {
|
||||
return EQ.FromEquals(func(l, r GA) bool {
|
||||
return eqp.Equals(l(s), r(s))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// FromStrictEquals constructs an [EQ.Eq] from the canonical comparison function
|
||||
func FromStrictEquals[GA ~func(S) P.Pair[A, S], S, A comparable]() func(S) EQ.Eq[GA] {
|
||||
return Eq[GA](EQ.FromStrictEquals[S](), EQ.FromStrictEquals[A]())
|
||||
}
|
88
state/generic/monad.go
Normal file
88
state/generic/monad.go
Normal file
@@ -0,0 +1,88 @@
|
||||
// Copyright (c) 2024 IBM Corp.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package generic
|
||||
|
||||
import (
|
||||
"github.com/IBM/fp-go/internal/applicative"
|
||||
"github.com/IBM/fp-go/internal/functor"
|
||||
"github.com/IBM/fp-go/internal/monad"
|
||||
"github.com/IBM/fp-go/internal/pointed"
|
||||
P "github.com/IBM/fp-go/pair"
|
||||
)
|
||||
|
||||
type statePointed[GA ~func(S) P.Pair[A, S], S, A any] struct{}
|
||||
|
||||
type stateFunctor[GB ~func(S) P.Pair[B, S], GA ~func(S) P.Pair[A, S], S, A, B any] struct{}
|
||||
|
||||
type stateApplicative[GB ~func(S) P.Pair[B, S], GAB ~func(S) P.Pair[func(A) B, S], GA ~func(S) P.Pair[A, S], S, A, B any] struct{}
|
||||
|
||||
type stateMonad[GB ~func(S) P.Pair[B, S], GAB ~func(S) P.Pair[func(A) B, S], GA ~func(S) P.Pair[A, S], S, A, B any] struct{}
|
||||
|
||||
func (o *statePointed[GA, S, A]) Of(a A) GA {
|
||||
return Of[GA](a)
|
||||
}
|
||||
|
||||
func (o *stateApplicative[GB, GAB, GA, S, A, B]) Of(a A) GA {
|
||||
return Of[GA](a)
|
||||
}
|
||||
|
||||
func (o *stateMonad[GB, GAB, GA, S, A, B]) Of(a A) GA {
|
||||
return Of[GA](a)
|
||||
}
|
||||
|
||||
func (o *stateFunctor[GB, GA, S, A, B]) Map(f func(A) B) func(GA) GB {
|
||||
return Map[GB, GA](f)
|
||||
}
|
||||
|
||||
func (o *stateApplicative[GB, GAB, GA, S, A, B]) Map(f func(A) B) func(GA) GB {
|
||||
return Map[GB, GA](f)
|
||||
}
|
||||
|
||||
func (o *stateMonad[GB, GAB, GA, S, A, B]) Map(f func(A) B) func(GA) GB {
|
||||
return Map[GB, GA](f)
|
||||
}
|
||||
|
||||
func (o *stateMonad[GB, GAB, GA, S, A, B]) Chain(f func(A) GB) func(GA) GB {
|
||||
return Chain[GB, GA](f)
|
||||
}
|
||||
|
||||
func (o *stateApplicative[GB, GAB, GA, S, A, B]) Ap(fa GA) func(GAB) GB {
|
||||
return Ap[GB, GAB, GA](fa)
|
||||
}
|
||||
|
||||
func (o *stateMonad[GB, GAB, GA, S, A, B]) Ap(fa GA) func(GAB) GB {
|
||||
return Ap[GB, GAB, GA](fa)
|
||||
}
|
||||
|
||||
// Pointed implements the pointed operations for [Writer]
|
||||
func Pointed[GA ~func(S) P.Pair[A, S], S, A any]() pointed.Pointed[A, GA] {
|
||||
return &statePointed[GA, S, A]{}
|
||||
}
|
||||
|
||||
// Functor implements the functor operations for [Writer]
|
||||
func Functor[GB ~func(S) P.Pair[B, S], GA ~func(S) P.Pair[A, S], S, A, B any]() functor.Functor[A, B, GA, GB] {
|
||||
return &stateFunctor[GB, GA, S, A, B]{}
|
||||
}
|
||||
|
||||
// Applicative implements the applicative operations for [Writer]
|
||||
func Applicative[GB ~func(S) P.Pair[B, S], GAB ~func(S) P.Pair[func(A) B, S], GA ~func(S) P.Pair[A, S], S, A, B any]() applicative.Applicative[A, B, GA, GB, GAB] {
|
||||
return &stateApplicative[GB, GAB, GA, S, A, B]{}
|
||||
}
|
||||
|
||||
// Monad implements the monadic operations for [Writer]
|
||||
func Monad[GB ~func(S) P.Pair[B, S], GAB ~func(S) P.Pair[func(A) B, S], GA ~func(S) P.Pair[A, S], S, A, B any]() monad.Monad[A, B, GA, GB, GAB] {
|
||||
return &stateMonad[GB, GAB, GA, S, A, B]{}
|
||||
}
|
131
state/generic/state.go
Normal file
131
state/generic/state.go
Normal file
@@ -0,0 +1,131 @@
|
||||
// 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 (
|
||||
F "github.com/IBM/fp-go/function"
|
||||
C "github.com/IBM/fp-go/internal/chain"
|
||||
FC "github.com/IBM/fp-go/internal/functor"
|
||||
P "github.com/IBM/fp-go/pair"
|
||||
)
|
||||
|
||||
var (
|
||||
undefined any = struct{}{}
|
||||
)
|
||||
|
||||
func Get[GA ~func(S) P.Pair[S, S], S any]() GA {
|
||||
return P.Of[S]
|
||||
}
|
||||
|
||||
func Gets[GA ~func(S) P.Pair[A, S], FCT ~func(S) A, A, S any](f FCT) GA {
|
||||
return func(s S) P.Pair[A, S] {
|
||||
return P.MakePair(f(s), s)
|
||||
}
|
||||
}
|
||||
|
||||
func Put[GA ~func(S) P.Pair[any, S], S any]() GA {
|
||||
return F.Bind1st(P.MakePair[any, S], undefined)
|
||||
}
|
||||
|
||||
func Modify[GA ~func(S) P.Pair[any, S], FCT ~func(S) S, S any](f FCT) GA {
|
||||
return F.Flow2(
|
||||
f,
|
||||
F.Bind1st(P.MakePair[any, S], undefined),
|
||||
)
|
||||
}
|
||||
|
||||
func Of[GA ~func(S) P.Pair[A, S], S, A any](a A) GA {
|
||||
return F.Bind1st(P.MakePair[A, S], a)
|
||||
}
|
||||
|
||||
func MonadMap[GB ~func(S) P.Pair[B, S], GA ~func(S) P.Pair[A, S], FCT ~func(A) B, S, A, B any](fa GA, f FCT) GB {
|
||||
return func(s S) P.Pair[B, S] {
|
||||
p2 := fa(s)
|
||||
return P.MakePair(f(P.Head(p2)), P.Tail(p2))
|
||||
}
|
||||
}
|
||||
|
||||
func Map[GB ~func(S) P.Pair[B, S], GA ~func(S) P.Pair[A, S], FCT ~func(A) B, S, A, B any](f FCT) func(GA) GB {
|
||||
return F.Bind2nd(MonadMap[GB, GA, FCT, S, A, B], f)
|
||||
}
|
||||
|
||||
func MonadChain[GB ~func(S) P.Pair[B, S], GA ~func(S) P.Pair[A, S], FCT ~func(A) GB, S, A, B any](fa GA, f FCT) GB {
|
||||
return func(s S) P.Pair[B, S] {
|
||||
a := fa(s)
|
||||
return f(P.Head(a))(P.Tail(a))
|
||||
}
|
||||
}
|
||||
|
||||
func Chain[GB ~func(S) P.Pair[B, S], GA ~func(S) P.Pair[A, S], FCT ~func(A) GB, S, A, B any](f FCT) func(GA) GB {
|
||||
return F.Bind2nd(MonadChain[GB, GA, FCT, S, A, B], f)
|
||||
}
|
||||
|
||||
func MonadAp[GB ~func(S) P.Pair[B, S], GAB ~func(S) P.Pair[func(A) B, S], GA ~func(S) P.Pair[A, S], S, A, B any](fab GAB, fa GA) GB {
|
||||
return func(s S) P.Pair[B, S] {
|
||||
f := fab(s)
|
||||
a := fa(P.Tail(f))
|
||||
|
||||
return P.MakePair(P.Head(f)(P.Head(a)), P.Tail(a))
|
||||
}
|
||||
}
|
||||
|
||||
func Ap[GB ~func(S) P.Pair[B, S], GAB ~func(S) P.Pair[func(A) B, S], GA ~func(S) P.Pair[A, S], S, A, B any](ga GA) func(GAB) GB {
|
||||
return F.Bind2nd(MonadAp[GB, GAB, GA, S, A, B], ga)
|
||||
}
|
||||
|
||||
func MonadChainFirst[GB ~func(S) P.Pair[B, S], GA ~func(S) P.Pair[A, S], FCT ~func(A) GB, S, A, B any](ma GA, f FCT) GA {
|
||||
return C.MonadChainFirst(
|
||||
MonadChain[GA, GA, func(A) GA],
|
||||
MonadMap[GA, GB, func(B) A],
|
||||
ma,
|
||||
f,
|
||||
)
|
||||
}
|
||||
|
||||
func ChainFirst[GB ~func(S) P.Pair[B, S], GA ~func(S) P.Pair[A, S], FCT ~func(A) GB, S, A, B any](f FCT) func(GA) GA {
|
||||
return C.ChainFirst(
|
||||
Chain[GA, GA, func(A) GA],
|
||||
Map[GA, GB, func(B) A],
|
||||
f,
|
||||
)
|
||||
}
|
||||
|
||||
func Flatten[GAA ~func(S) P.Pair[GA, S], GA ~func(S) P.Pair[A, S], S, A any](mma GAA) GA {
|
||||
return MonadChain[GA, GAA, func(GA) GA](mma, F.Identity[GA])
|
||||
}
|
||||
|
||||
func Execute[GA ~func(S) P.Pair[A, S], S, A any](s S) func(GA) S {
|
||||
return func(fa GA) S {
|
||||
return P.Tail(fa(s))
|
||||
}
|
||||
}
|
||||
|
||||
func Evaluate[GA ~func(S) P.Pair[A, S], S, A any](s S) func(GA) A {
|
||||
return func(fa GA) A {
|
||||
return P.Head(fa(s))
|
||||
}
|
||||
}
|
||||
|
||||
func MonadFlap[FAB ~func(A) B, GFAB ~func(S) P.Pair[FAB, S], GB ~func(S) P.Pair[B, S], S, A, B any](fab GFAB, a A) GB {
|
||||
return FC.MonadFlap(
|
||||
MonadMap[GB, GFAB, func(FAB) B],
|
||||
fab,
|
||||
a)
|
||||
}
|
||||
|
||||
func Flap[FAB ~func(A) B, GFAB ~func(S) P.Pair[FAB, S], GB ~func(S) P.Pair[B, S], S, A, B any](a A) func(GFAB) GB {
|
||||
return FC.Flap(Map[GB, GFAB, func(FAB) B], a)
|
||||
}
|
44
state/monad.go
Normal file
44
state/monad.go
Normal file
@@ -0,0 +1,44 @@
|
||||
// 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 state
|
||||
|
||||
import (
|
||||
"github.com/IBM/fp-go/internal/applicative"
|
||||
"github.com/IBM/fp-go/internal/functor"
|
||||
"github.com/IBM/fp-go/internal/monad"
|
||||
"github.com/IBM/fp-go/internal/pointed"
|
||||
G "github.com/IBM/fp-go/state/generic"
|
||||
)
|
||||
|
||||
// Pointed implements the pointed operations for [State]
|
||||
func Pointed[S, A any]() pointed.Pointed[A, State[S, A]] {
|
||||
return G.Pointed[State[S, A], S, A]()
|
||||
}
|
||||
|
||||
// Functor implements the pointed operations for [State]
|
||||
func Functor[S, A, B any]() functor.Functor[A, B, State[S, A], State[S, B]] {
|
||||
return G.Functor[State[S, B], State[S, A], S, A, B]()
|
||||
}
|
||||
|
||||
// Applicative implements the applicative operations for [State]
|
||||
func Applicative[S, A, B any]() applicative.Applicative[A, B, State[S, A], State[S, B], State[S, func(A) B]] {
|
||||
return G.Applicative[State[S, B], State[S, func(A) B], State[S, A]]()
|
||||
}
|
||||
|
||||
// Monad implements the monadic operations for [State]
|
||||
func Monad[S, A, B any]() monad.Monad[A, B, State[S, A], State[S, B], State[S, func(A) B]] {
|
||||
return G.Monad[State[S, B], State[S, func(A) B], State[S, A]]()
|
||||
}
|
97
state/state.go
Normal file
97
state/state.go
Normal file
@@ -0,0 +1,97 @@
|
||||
// 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 state
|
||||
|
||||
import (
|
||||
P "github.com/IBM/fp-go/pair"
|
||||
R "github.com/IBM/fp-go/reader"
|
||||
G "github.com/IBM/fp-go/state/generic"
|
||||
)
|
||||
|
||||
// State represents an operation on top of a current [State] that produces a value and a new [State]
|
||||
type State[S, A any] R.Reader[S, P.Pair[A, S]]
|
||||
|
||||
func Get[S any]() State[S, S] {
|
||||
return G.Get[State[S, S]]()
|
||||
}
|
||||
|
||||
func Gets[FCT ~func(S) A, A, S any](f FCT) State[S, A] {
|
||||
return G.Gets[State[S, A]](f)
|
||||
}
|
||||
|
||||
func Put[S any]() State[S, any] {
|
||||
return G.Put[State[S, any]]()
|
||||
}
|
||||
|
||||
func Modify[FCT ~func(S) S, S any](f FCT) State[S, any] {
|
||||
return G.Modify[State[S, any]](f)
|
||||
}
|
||||
|
||||
func Of[S, A any](a A) State[S, A] {
|
||||
return G.Of[State[S, A]](a)
|
||||
}
|
||||
|
||||
func MonadMap[S any, FCT ~func(A) B, A, B any](fa State[S, A], f FCT) State[S, B] {
|
||||
return G.MonadMap[State[S, B], State[S, A]](fa, f)
|
||||
}
|
||||
|
||||
func Map[S any, FCT ~func(A) B, A, B any](f FCT) func(State[S, A]) State[S, B] {
|
||||
return G.Map[State[S, B], State[S, A]](f)
|
||||
}
|
||||
|
||||
func MonadChain[S any, FCT ~func(A) State[S, B], A, B any](fa State[S, A], f FCT) State[S, B] {
|
||||
return G.MonadChain[State[S, B], State[S, A]](fa, f)
|
||||
}
|
||||
|
||||
func Chain[S any, FCT ~func(A) State[S, B], A, B any](f FCT) func(State[S, A]) State[S, B] {
|
||||
return G.Chain[State[S, B], State[S, A]](f)
|
||||
}
|
||||
|
||||
func MonadAp[S, A, B any](fab State[S, func(A) B], fa State[S, A]) State[S, B] {
|
||||
return G.MonadAp[State[S, B], State[S, func(A) B], State[S, A]](fab, fa)
|
||||
}
|
||||
|
||||
func Ap[S, A, B any](ga State[S, A]) func(State[S, func(A) B]) State[S, B] {
|
||||
return G.Ap[State[S, B], State[S, func(A) B], State[S, A]](ga)
|
||||
}
|
||||
|
||||
func MonadChainFirst[S any, FCT ~func(A) State[S, B], A, B any](ma State[S, A], f FCT) State[S, A] {
|
||||
return G.MonadChainFirst[State[S, B], State[S, A]](ma, f)
|
||||
}
|
||||
|
||||
func ChainFirst[S any, FCT ~func(A) State[S, B], A, B any](f FCT) func(State[S, A]) State[S, A] {
|
||||
return G.ChainFirst[State[S, B], State[S, A]](f)
|
||||
}
|
||||
|
||||
func Flatten[S, A any](mma State[S, State[S, A]]) State[S, A] {
|
||||
return G.Flatten[State[S, State[S, A]], State[S, A]](mma)
|
||||
}
|
||||
|
||||
func Execute[A, S any](s S) func(State[S, A]) S {
|
||||
return G.Execute[State[S, A]](s)
|
||||
}
|
||||
|
||||
func Evaluate[A, S any](s S) func(State[S, A]) A {
|
||||
return G.Evaluate[State[S, A]](s)
|
||||
}
|
||||
|
||||
func MonadFlap[FAB ~func(A) B, S, A, B any](fab State[S, FAB], a A) State[S, B] {
|
||||
return G.MonadFlap[FAB, State[S, FAB], State[S, B], S, A, B](fab, a)
|
||||
}
|
||||
|
||||
func Flap[S, A, B any](a A) func(State[S, func(A) B]) State[S, B] {
|
||||
return G.Flap[func(A) B, State[S, func(A) B], State[S, B]](a)
|
||||
}
|
78
state/testing/laws.go
Normal file
78
state/testing/laws.go
Normal file
@@ -0,0 +1,78 @@
|
||||
// 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"
|
||||
|
||||
EQ "github.com/IBM/fp-go/eq"
|
||||
L "github.com/IBM/fp-go/internal/monad/testing"
|
||||
ST "github.com/IBM/fp-go/state"
|
||||
)
|
||||
|
||||
// AssertLaws asserts the apply monad laws for the `Either` monad
|
||||
func AssertLaws[S, A, B, C any](t *testing.T,
|
||||
eqw EQ.Eq[S],
|
||||
eqa EQ.Eq[A],
|
||||
eqb EQ.Eq[B],
|
||||
eqc EQ.Eq[C],
|
||||
|
||||
ab func(A) B,
|
||||
bc func(B) C,
|
||||
|
||||
s S,
|
||||
) func(a A) bool {
|
||||
|
||||
fofc := ST.Pointed[S, C]()
|
||||
fofaa := ST.Pointed[S, func(A) A]()
|
||||
fofbc := ST.Pointed[S, func(B) C]()
|
||||
fofabb := ST.Pointed[S, func(func(A) B) B]()
|
||||
|
||||
fmap := ST.Functor[S, func(B) C, func(func(A) B) func(A) C]()
|
||||
|
||||
fapabb := ST.Applicative[S, func(A) B, B]()
|
||||
fapabac := ST.Applicative[S, func(A) B, func(A) C]()
|
||||
|
||||
maa := ST.Monad[S, A, A]()
|
||||
mab := ST.Monad[S, A, B]()
|
||||
mac := ST.Monad[S, A, C]()
|
||||
mbc := ST.Monad[S, B, C]()
|
||||
|
||||
return L.MonadAssertLaws(t,
|
||||
ST.Eq(eqw, eqa)(s),
|
||||
ST.Eq(eqw, eqb)(s),
|
||||
ST.Eq(eqw, eqc)(s),
|
||||
|
||||
fofc,
|
||||
fofaa,
|
||||
fofbc,
|
||||
fofabb,
|
||||
|
||||
fmap,
|
||||
|
||||
fapabb,
|
||||
fapabac,
|
||||
|
||||
maa,
|
||||
mab,
|
||||
mac,
|
||||
mbc,
|
||||
|
||||
ab,
|
||||
bc,
|
||||
)
|
||||
|
||||
}
|
49
state/testing/laws_test.go
Normal file
49
state/testing/laws_test.go
Normal file
@@ -0,0 +1,49 @@
|
||||
// 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"
|
||||
|
||||
A "github.com/IBM/fp-go/array"
|
||||
EQ "github.com/IBM/fp-go/eq"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestMonadLaws(t *testing.T) {
|
||||
// some comparison
|
||||
eqs := A.Eq[string](EQ.FromStrictEquals[string]())
|
||||
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, eqs, eqa, eqb, eqc, ab, bc, A.Empty[string]())
|
||||
|
||||
assert.True(t, laws(true))
|
||||
assert.True(t, laws(false))
|
||||
}
|
@@ -17,20 +17,22 @@ package writer
|
||||
|
||||
import (
|
||||
M "github.com/IBM/fp-go/monoid"
|
||||
SG "github.com/IBM/fp-go/semigroup"
|
||||
G "github.com/IBM/fp-go/writer/generic"
|
||||
)
|
||||
|
||||
// Bind creates an empty context of type [S] to be used with the [Bind] operation
|
||||
func Do[S, W any](m M.Monoid[W]) func(S) Writer[W, S] {
|
||||
return G.Do[Writer[W, S], W, S](m)
|
||||
func Do[S, W any](m M.Monoid[W], s S) Writer[W, S] {
|
||||
return G.Do[Writer[W, S], W, S](m, s)
|
||||
}
|
||||
|
||||
// Bind attaches the result of a computation to a context [S1] to produce a context [S2]
|
||||
func Bind[S1, S2, T, W any](
|
||||
s SG.Semigroup[W],
|
||||
setter func(T) func(S1) S2,
|
||||
f func(S1) Writer[W, T],
|
||||
) func(Writer[W, S1]) Writer[W, S2] {
|
||||
return G.Bind[Writer[W, S1], Writer[W, S2], Writer[W, T], W, S1, S2, T](setter, f)
|
||||
return G.Bind[Writer[W, S1], Writer[W, S2], Writer[W, T], W, S1, S2, T](s, setter, f)
|
||||
}
|
||||
|
||||
// Let attaches the result of a computation to a context [S1] to produce a context [S2]
|
||||
@@ -58,8 +60,9 @@ func BindTo[W, S1, T any](
|
||||
|
||||
// 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, W any](
|
||||
s SG.Semigroup[W],
|
||||
setter func(T) func(S1) S2,
|
||||
fa Writer[W, T],
|
||||
) func(Writer[W, S1]) Writer[W, S2] {
|
||||
return G.ApS[Writer[W, S1], Writer[W, S2], Writer[W, T], W, S1, S2, T](setter, fa)
|
||||
return G.ApS[Writer[W, S1], Writer[W, S2], Writer[W, T], W, S1, S2, T](s, setter, fa)
|
||||
}
|
||||
|
@@ -34,33 +34,33 @@ var (
|
||||
)
|
||||
|
||||
func getLastName(s utils.Initial) Writer[[]string, string] {
|
||||
return Of[string](monoid)("Doe")
|
||||
return Of[string](monoid, "Doe")
|
||||
}
|
||||
|
||||
func getGivenName(s utils.WithLastName) Writer[[]string, string] {
|
||||
return Of[string](monoid)("John")
|
||||
return Of[string](monoid, "John")
|
||||
}
|
||||
|
||||
func TestBind(t *testing.T) {
|
||||
|
||||
res := F.Pipe3(
|
||||
Do[utils.Initial](monoid)(utils.Empty),
|
||||
Bind(utils.SetLastName, getLastName),
|
||||
Bind(utils.SetGivenName, getGivenName),
|
||||
Do[utils.Initial](monoid, utils.Empty),
|
||||
Bind(sg, utils.SetLastName, getLastName),
|
||||
Bind(sg, utils.SetGivenName, getGivenName),
|
||||
Map[[]string](utils.GetFullName),
|
||||
)
|
||||
|
||||
assert.True(t, eq.Equals(res, Of[string](monoid)("John Doe")))
|
||||
assert.True(t, eq.Equals(res, Of[string](monoid, "John Doe")))
|
||||
}
|
||||
|
||||
func TestApS(t *testing.T) {
|
||||
|
||||
res := F.Pipe3(
|
||||
Do[utils.Initial](monoid)(utils.Empty),
|
||||
ApS(utils.SetLastName, Of[string](monoid)("Doe")),
|
||||
ApS(utils.SetGivenName, Of[string](monoid)("John")),
|
||||
Do[utils.Initial](monoid, utils.Empty),
|
||||
ApS(sg, utils.SetLastName, Of[string](monoid, "Doe")),
|
||||
ApS(sg, utils.SetGivenName, Of[string](monoid, "John")),
|
||||
Map[[]string](utils.GetFullName),
|
||||
)
|
||||
|
||||
assert.True(t, eq.Equals(res, Of[string](monoid)("John Doe")))
|
||||
assert.True(t, eq.Equals(res, Of[string](monoid, "John Doe")))
|
||||
}
|
||||
|
@@ -16,26 +16,28 @@
|
||||
package generic
|
||||
|
||||
import (
|
||||
FCT "github.com/IBM/fp-go/function"
|
||||
"github.com/IBM/fp-go/internal/apply"
|
||||
C "github.com/IBM/fp-go/internal/chain"
|
||||
F "github.com/IBM/fp-go/internal/functor"
|
||||
M "github.com/IBM/fp-go/monoid"
|
||||
P "github.com/IBM/fp-go/pair"
|
||||
SG "github.com/IBM/fp-go/semigroup"
|
||||
T "github.com/IBM/fp-go/tuple"
|
||||
)
|
||||
|
||||
// Bind creates an empty context of type [S] to be used with the [Bind] operation
|
||||
func Do[GS ~func() T.Tuple3[S, W, SG.Semigroup[W]], W, S any](m M.Monoid[W]) func(S) GS {
|
||||
return Of[GS, W, S](m)
|
||||
func Do[GS ~func() P.Pair[S, W], W, S any](m M.Monoid[W], s S) GS {
|
||||
return Of[GS, W, S](m, s)
|
||||
}
|
||||
|
||||
// Bind attaches the result of a computation to a context [S1] to produce a context [S2]
|
||||
func Bind[GS1 ~func() T.Tuple3[S1, W, SG.Semigroup[W]], GS2 ~func() T.Tuple3[S2, W, SG.Semigroup[W]], GT ~func() T.Tuple3[A, W, SG.Semigroup[W]], W, S1, S2, A any](
|
||||
func Bind[GS1 ~func() P.Pair[S1, W], GS2 ~func() P.Pair[S2, W], GT ~func() P.Pair[A, W], W, S1, S2, A any](
|
||||
s SG.Semigroup[W],
|
||||
setter func(A) func(S1) S2,
|
||||
f func(S1) GT,
|
||||
) func(GS1) GS2 {
|
||||
return C.Bind(
|
||||
Chain[GS2, GS1, func(S1) GS2, W, S1, S2],
|
||||
FCT.Bind1st(Chain[GS2, GS1, func(S1) GS2, W, S1, S2], s),
|
||||
Map[GS2, GT, func(A) S2, W, A, S2],
|
||||
setter,
|
||||
f,
|
||||
@@ -43,7 +45,7 @@ func Bind[GS1 ~func() T.Tuple3[S1, W, SG.Semigroup[W]], GS2 ~func() T.Tuple3[S2,
|
||||
}
|
||||
|
||||
// Let attaches the result of a computation to a context [S1] to produce a context [S2]
|
||||
func Let[GS1 ~func() T.Tuple3[S1, W, SG.Semigroup[W]], GS2 ~func() T.Tuple3[S2, W, SG.Semigroup[W]], W, S1, S2, A any](
|
||||
func Let[GS1 ~func() P.Pair[S1, W], GS2 ~func() P.Pair[S2, W], W, S1, S2, A any](
|
||||
key func(A) func(S1) S2,
|
||||
f func(S1) A,
|
||||
) func(GS1) GS2 {
|
||||
@@ -55,7 +57,7 @@ func Let[GS1 ~func() T.Tuple3[S1, W, SG.Semigroup[W]], GS2 ~func() T.Tuple3[S2,
|
||||
}
|
||||
|
||||
// LetTo attaches the a value to a context [S1] to produce a context [S2]
|
||||
func LetTo[GS1 ~func() T.Tuple3[S1, W, SG.Semigroup[W]], GS2 ~func() T.Tuple3[S2, W, SG.Semigroup[W]], W, S1, S2, B any](
|
||||
func LetTo[GS1 ~func() P.Pair[S1, W], GS2 ~func() P.Pair[S2, W], W, S1, S2, B any](
|
||||
key func(B) func(S1) S2,
|
||||
b B,
|
||||
) func(GS1) GS2 {
|
||||
@@ -67,7 +69,7 @@ func LetTo[GS1 ~func() T.Tuple3[S1, W, SG.Semigroup[W]], GS2 ~func() T.Tuple3[S2
|
||||
}
|
||||
|
||||
// BindTo initializes a new state [S1] from a value [T]
|
||||
func BindTo[GS1 ~func() T.Tuple3[S1, W, SG.Semigroup[W]], GT ~func() T.Tuple3[A, W, SG.Semigroup[W]], W, S1, A any](
|
||||
func BindTo[GS1 ~func() P.Pair[S1, W], GT ~func() P.Pair[A, W], W, S1, A any](
|
||||
setter func(A) S1,
|
||||
) func(GT) GS1 {
|
||||
return C.BindTo(
|
||||
@@ -77,13 +79,14 @@ func BindTo[GS1 ~func() T.Tuple3[S1, W, SG.Semigroup[W]], GT ~func() T.Tuple3[A,
|
||||
}
|
||||
|
||||
// ApS attaches a value to a context [S1] to produce a context [S2] by considering the context and the value concurrently
|
||||
func ApS[GS1 ~func() T.Tuple3[S1, W, SG.Semigroup[W]], GS2 ~func() T.Tuple3[S2, W, SG.Semigroup[W]], GT ~func() T.Tuple3[A, W, SG.Semigroup[W]], W, S1, S2, A any](
|
||||
func ApS[GS1 ~func() P.Pair[S1, W], GS2 ~func() P.Pair[S2, W], GT ~func() P.Pair[A, W], W, S1, S2, A any](
|
||||
s SG.Semigroup[W],
|
||||
setter func(A) func(S1) S2,
|
||||
fa GT,
|
||||
) func(GS1) GS2 {
|
||||
return apply.ApS(
|
||||
Ap[GS2, func() T.Tuple3[func(A) S2, W, SG.Semigroup[W]], GT, W, A, S2],
|
||||
Map[func() T.Tuple3[func(A) S2, W, SG.Semigroup[W]], GS1, func(S1) func(A) S2],
|
||||
FCT.Bind1st(Ap[GS2, func() P.Pair[func(A) S2, W], GT, W, A, S2], s),
|
||||
Map[func() P.Pair[func(A) S2, W], GS1, func(S1) func(A) S2],
|
||||
setter,
|
||||
fa,
|
||||
)
|
||||
|
@@ -17,21 +17,18 @@ package generic
|
||||
|
||||
import (
|
||||
EQ "github.com/IBM/fp-go/eq"
|
||||
SG "github.com/IBM/fp-go/semigroup"
|
||||
T "github.com/IBM/fp-go/tuple"
|
||||
P "github.com/IBM/fp-go/pair"
|
||||
)
|
||||
|
||||
// Constructs an equal predicate for a [Writer]
|
||||
func Eq[GA ~func() T.Tuple3[A, W, SG.Semigroup[W]], W, A any](w EQ.Eq[W], a EQ.Eq[A]) EQ.Eq[GA] {
|
||||
func Eq[GA ~func() P.Pair[A, W], W, A any](w EQ.Eq[W], a EQ.Eq[A]) EQ.Eq[GA] {
|
||||
eqp := P.Eq(a, w)
|
||||
return EQ.FromEquals(func(l, r GA) bool {
|
||||
ll := l()
|
||||
rr := r()
|
||||
|
||||
return a.Equals(ll.F1, rr.F1) && w.Equals(ll.F2, rr.F2)
|
||||
return eqp.Equals(l(), r())
|
||||
})
|
||||
}
|
||||
|
||||
// FromStrictEquals constructs an [EQ.Eq] from the canonical comparison function
|
||||
func FromStrictEquals[GA ~func() T.Tuple3[A, W, SG.Semigroup[W]], W, A comparable]() EQ.Eq[GA] {
|
||||
func FromStrictEquals[GA ~func() P.Pair[A, W], W, A comparable]() EQ.Eq[GA] {
|
||||
return Eq[GA](EQ.FromStrictEquals[W](), EQ.FromStrictEquals[A]())
|
||||
}
|
||||
|
106
writer/generic/monad.go
Normal file
106
writer/generic/monad.go
Normal file
@@ -0,0 +1,106 @@
|
||||
// Copyright (c) 2024 IBM Corp.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package generic
|
||||
|
||||
import (
|
||||
"github.com/IBM/fp-go/internal/applicative"
|
||||
"github.com/IBM/fp-go/internal/functor"
|
||||
"github.com/IBM/fp-go/internal/monad"
|
||||
"github.com/IBM/fp-go/internal/pointed"
|
||||
M "github.com/IBM/fp-go/monoid"
|
||||
P "github.com/IBM/fp-go/pair"
|
||||
SG "github.com/IBM/fp-go/semigroup"
|
||||
)
|
||||
|
||||
type writerPointed[GA ~func() P.Pair[A, W], W, A any] struct {
|
||||
m M.Monoid[W]
|
||||
}
|
||||
|
||||
type writerFunctor[GB ~func() P.Pair[B, W], GA ~func() P.Pair[A, W], W, A, B any] struct{}
|
||||
|
||||
type writerApplicative[GB ~func() P.Pair[B, W], GAB ~func() P.Pair[func(A) B, W], GA ~func() P.Pair[A, W], W, A, B any] struct {
|
||||
s SG.Semigroup[W]
|
||||
m M.Monoid[W]
|
||||
}
|
||||
|
||||
type writerMonad[GB ~func() P.Pair[B, W], GAB ~func() P.Pair[func(A) B, W], GA ~func() P.Pair[A, W], W, A, B any] struct {
|
||||
s SG.Semigroup[W]
|
||||
m M.Monoid[W]
|
||||
}
|
||||
|
||||
func (o *writerPointed[GA, W, A]) Of(a A) GA {
|
||||
return Of[GA](o.m, a)
|
||||
}
|
||||
|
||||
func (o *writerApplicative[GB, GAB, GA, W, A, B]) Of(a A) GA {
|
||||
return Of[GA](o.m, a)
|
||||
}
|
||||
|
||||
func (o *writerMonad[GB, GAB, GA, W, A, B]) Of(a A) GA {
|
||||
return Of[GA](o.m, a)
|
||||
}
|
||||
|
||||
func (o *writerFunctor[GB, GA, W, A, B]) Map(f func(A) B) func(GA) GB {
|
||||
return Map[GB, GA](f)
|
||||
}
|
||||
|
||||
func (o *writerApplicative[GB, GAB, GA, W, A, B]) Map(f func(A) B) func(GA) GB {
|
||||
return Map[GB, GA](f)
|
||||
}
|
||||
|
||||
func (o *writerMonad[GB, GAB, GA, W, A, B]) Map(f func(A) B) func(GA) GB {
|
||||
return Map[GB, GA](f)
|
||||
}
|
||||
|
||||
func (o *writerMonad[GB, GAB, GA, W, A, B]) Chain(f func(A) GB) func(GA) GB {
|
||||
return Chain[GB, GA](o.s, f)
|
||||
}
|
||||
|
||||
func (o *writerApplicative[GB, GAB, GA, W, A, B]) Ap(fa GA) func(GAB) GB {
|
||||
return Ap[GB, GAB, GA](o.s, fa)
|
||||
}
|
||||
|
||||
func (o *writerMonad[GB, GAB, GA, W, A, B]) Ap(fa GA) func(GAB) GB {
|
||||
return Ap[GB, GAB, GA](o.s, fa)
|
||||
}
|
||||
|
||||
// Pointed implements the pointed operations for [Writer]
|
||||
func Pointed[GA ~func() P.Pair[A, W], W, A any](m M.Monoid[W]) pointed.Pointed[A, GA] {
|
||||
return &writerPointed[GA, W, A]{
|
||||
m: m,
|
||||
}
|
||||
}
|
||||
|
||||
// Functor implements the functor operations for [Writer]
|
||||
func Functor[GB ~func() P.Pair[B, W], GA ~func() P.Pair[A, W], W, A, B any]() functor.Functor[A, B, GA, GB] {
|
||||
return &writerFunctor[GB, GA, W, A, B]{}
|
||||
}
|
||||
|
||||
// Applicative implements the applicative operations for [Writer]
|
||||
func Applicative[GB ~func() P.Pair[B, W], GAB ~func() P.Pair[func(A) B, W], GA ~func() P.Pair[A, W], W, A, B any](m M.Monoid[W]) applicative.Applicative[A, B, GA, GB, GAB] {
|
||||
return &writerApplicative[GB, GAB, GA, W, A, B]{
|
||||
s: M.ToSemigroup(m),
|
||||
m: m,
|
||||
}
|
||||
}
|
||||
|
||||
// Monad implements the monadic operations for [Writer]
|
||||
func Monad[GB ~func() P.Pair[B, W], GAB ~func() P.Pair[func(A) B, W], GA ~func() P.Pair[A, W], W, A, B any](m M.Monoid[W]) monad.Monad[A, B, GA, GB, GAB] {
|
||||
return &writerMonad[GB, GAB, GA, W, A, B]{
|
||||
s: M.ToSemigroup(m),
|
||||
m: m,
|
||||
}
|
||||
}
|
@@ -21,133 +21,137 @@ import (
|
||||
FC "github.com/IBM/fp-go/internal/functor"
|
||||
IO "github.com/IBM/fp-go/io/generic"
|
||||
M "github.com/IBM/fp-go/monoid"
|
||||
P "github.com/IBM/fp-go/pair"
|
||||
SG "github.com/IBM/fp-go/semigroup"
|
||||
T "github.com/IBM/fp-go/tuple"
|
||||
)
|
||||
|
||||
func Tell[GA ~func() T.Tuple3[any, W, SG.Semigroup[W]], W any](s SG.Semigroup[W]) func(W) GA {
|
||||
return F.Flow2(
|
||||
F.Bind13of3(T.MakeTuple3[any, W, SG.Semigroup[W]])(nil, s),
|
||||
IO.Of[GA],
|
||||
)
|
||||
var (
|
||||
undefined any = struct{}{}
|
||||
)
|
||||
|
||||
func Tell[GA ~func() P.Pair[any, W], W any](w W) GA {
|
||||
return IO.Of[GA](P.MakePair[any](undefined, w))
|
||||
}
|
||||
|
||||
func Of[GA ~func() T.Tuple3[A, W, SG.Semigroup[W]], W, A any](m M.Monoid[W]) func(A) GA {
|
||||
return F.Flow2(
|
||||
F.Bind23of3(T.MakeTuple3[A, W, SG.Semigroup[W]])(m.Empty(), M.ToSemigroup(m)),
|
||||
IO.Of[GA],
|
||||
)
|
||||
func Of[GA ~func() P.Pair[A, W], W, A any](m M.Monoid[W], a A) GA {
|
||||
return IO.Of[GA](P.MakePair(a, m.Empty()))
|
||||
}
|
||||
|
||||
// Listen modifies the result to include the changes to the accumulator
|
||||
func Listen[GA ~func() T.Tuple3[A, W, SG.Semigroup[W]], GTA ~func() T.Tuple3[T.Tuple2[A, W], W, SG.Semigroup[W]], W, A any](fa GA) GTA {
|
||||
return func() T.Tuple3[T.Tuple2[A, W], W, SG.Semigroup[W]] {
|
||||
func Listen[GA ~func() P.Pair[A, W], GTA ~func() P.Pair[P.Pair[A, W], W], W, A any](fa GA) GTA {
|
||||
return func() P.Pair[P.Pair[A, W], W] {
|
||||
t := fa()
|
||||
return T.MakeTuple3(T.MakeTuple2(t.F1, t.F2), t.F2, t.F3)
|
||||
return P.MakePair(t, P.Tail(t))
|
||||
}
|
||||
}
|
||||
|
||||
// Pass applies the returned function to the accumulator
|
||||
func Pass[GFA ~func() T.Tuple3[T.Tuple2[A, FCT], W, SG.Semigroup[W]], GA ~func() T.Tuple3[A, W, SG.Semigroup[W]], FCT ~func(W) W, W, A any](fa GFA) GA {
|
||||
return func() T.Tuple3[A, W, SG.Semigroup[W]] {
|
||||
func Pass[GFA ~func() P.Pair[P.Pair[A, FCT], W], GA ~func() P.Pair[A, W], FCT ~func(W) W, W, A any](fa GFA) GA {
|
||||
return func() P.Pair[A, W] {
|
||||
t := fa()
|
||||
return T.MakeTuple3(t.F1.F1, t.F1.F2(t.F2), t.F3)
|
||||
a := P.Head(t)
|
||||
return P.MakePair(P.Head(a), P.Tail(a)(P.Tail(t)))
|
||||
}
|
||||
}
|
||||
|
||||
func MonadMap[GB ~func() T.Tuple3[B, W, SG.Semigroup[W]], GA ~func() T.Tuple3[A, W, SG.Semigroup[W]], FCT ~func(A) B, W, A, B any](fa GA, f FCT) GB {
|
||||
return IO.MonadMap[GA, GB](fa, T.Map3(f, F.Identity[W], F.Identity[SG.Semigroup[W]]))
|
||||
func MonadMap[GB ~func() P.Pair[B, W], GA ~func() P.Pair[A, W], FCT ~func(A) B, W, A, B any](fa GA, f FCT) GB {
|
||||
return IO.MonadMap[GA, GB](fa, P.Map[W](f))
|
||||
}
|
||||
|
||||
func Map[GB ~func() T.Tuple3[B, W, SG.Semigroup[W]], GA ~func() T.Tuple3[A, W, SG.Semigroup[W]], FCT ~func(A) B, W, A, B any](f FCT) func(GA) GB {
|
||||
return IO.Map[GA, GB](T.Map3(f, F.Identity[W], F.Identity[SG.Semigroup[W]]))
|
||||
func Map[GB ~func() P.Pair[B, W], GA ~func() P.Pair[A, W], FCT ~func(A) B, W, A, B any](f FCT) func(GA) GB {
|
||||
return IO.Map[GA, GB](P.Map[W](f))
|
||||
}
|
||||
|
||||
func MonadChain[GB ~func() T.Tuple3[B, W, SG.Semigroup[W]], GA ~func() T.Tuple3[A, W, SG.Semigroup[W]], FCT ~func(A) GB, W, A, B any](fa GA, f FCT) GB {
|
||||
return func() T.Tuple3[B, W, SG.Semigroup[W]] {
|
||||
func MonadChain[GB ~func() P.Pair[B, W], GA ~func() P.Pair[A, W], FCT ~func(A) GB, W, A, B any](s SG.Semigroup[W], fa GA, f FCT) GB {
|
||||
return func() P.Pair[B, W] {
|
||||
a := fa()
|
||||
b := f(a.F1)()
|
||||
b := f(P.Head(a))()
|
||||
|
||||
return T.MakeTuple3(b.F1, b.F3.Concat(a.F2, b.F2), b.F3)
|
||||
return P.MakePair(P.Head(b), s.Concat(P.Tail(a), P.Tail(b)))
|
||||
}
|
||||
}
|
||||
|
||||
func Chain[GB ~func() T.Tuple3[B, W, SG.Semigroup[W]], GA ~func() T.Tuple3[A, W, SG.Semigroup[W]], FCT ~func(A) GB, W, A, B any](f FCT) func(GA) GB {
|
||||
return F.Bind2nd(MonadChain[GB, GA, FCT, W, A, B], f)
|
||||
func Chain[GB ~func() P.Pair[B, W], GA ~func() P.Pair[A, W], FCT ~func(A) GB, W, A, B any](s SG.Semigroup[W], f FCT) func(GA) GB {
|
||||
return func(fa GA) GB {
|
||||
return MonadChain(s, fa, f)
|
||||
}
|
||||
}
|
||||
|
||||
func MonadAp[GB ~func() T.Tuple3[B, W, SG.Semigroup[W]], GAB ~func() T.Tuple3[func(A) B, W, SG.Semigroup[W]], GA ~func() T.Tuple3[A, W, SG.Semigroup[W]], W, A, B any](fab GAB, fa GA) GB {
|
||||
return func() T.Tuple3[B, W, SG.Semigroup[W]] {
|
||||
func MonadAp[GB ~func() P.Pair[B, W], GAB ~func() P.Pair[func(A) B, W], GA ~func() P.Pair[A, W], W, A, B any](s SG.Semigroup[W], fab GAB, fa GA) GB {
|
||||
return func() P.Pair[B, W] {
|
||||
f := fab()
|
||||
a := fa()
|
||||
|
||||
return T.MakeTuple3(f.F1(a.F1), f.F3.Concat(f.F2, a.F2), f.F3)
|
||||
return P.MakePair(P.Head(f)(P.Head(a)), s.Concat(P.Tail(f), P.Tail(a)))
|
||||
}
|
||||
}
|
||||
|
||||
func Ap[GB ~func() T.Tuple3[B, W, SG.Semigroup[W]], GAB ~func() T.Tuple3[func(A) B, W, SG.Semigroup[W]], GA ~func() T.Tuple3[A, W, SG.Semigroup[W]], W, A, B any](ga GA) func(GAB) GB {
|
||||
return F.Bind2nd(MonadAp[GB, GAB, GA], ga)
|
||||
func Ap[GB ~func() P.Pair[B, W], GAB ~func() P.Pair[func(A) B, W], GA ~func() P.Pair[A, W], W, A, B any](s SG.Semigroup[W], ga GA) func(GAB) GB {
|
||||
return func(fab GAB) GB {
|
||||
return MonadAp[GB](s, fab, ga)
|
||||
}
|
||||
}
|
||||
|
||||
func MonadChainFirst[GB ~func() T.Tuple3[B, W, SG.Semigroup[W]], GA ~func() T.Tuple3[A, W, SG.Semigroup[W]], FCT ~func(A) GB, W, A, B any](ma GA, f FCT) GA {
|
||||
func MonadChainFirst[GB ~func() P.Pair[B, W], GA ~func() P.Pair[A, W], FCT ~func(A) GB, W, A, B any](s SG.Semigroup[W], ma GA, f FCT) GA {
|
||||
return C.MonadChainFirst(
|
||||
MonadChain[GA, GA, func(A) GA],
|
||||
F.Bind1of3(MonadChain[GA, GA, func(A) GA])(s),
|
||||
MonadMap[GA, GB, func(B) A],
|
||||
ma,
|
||||
f,
|
||||
)
|
||||
}
|
||||
|
||||
func ChainFirst[GB ~func() T.Tuple3[B, W, SG.Semigroup[W]], GA ~func() T.Tuple3[A, W, SG.Semigroup[W]], FCT ~func(A) GB, W, A, B any](f FCT) func(GA) GA {
|
||||
func ChainFirst[GB ~func() P.Pair[B, W], GA ~func() P.Pair[A, W], FCT ~func(A) GB, W, A, B any](s SG.Semigroup[W], f FCT) func(GA) GA {
|
||||
return C.ChainFirst(
|
||||
Chain[GA, GA, func(A) GA],
|
||||
F.Bind1st(Chain[GA, GA, func(A) GA], s),
|
||||
Map[GA, GB, func(B) A],
|
||||
f,
|
||||
)
|
||||
}
|
||||
|
||||
func Flatten[GAA ~func() T.Tuple3[GA, W, SG.Semigroup[W]], GA ~func() T.Tuple3[A, W, SG.Semigroup[W]], W, A any](mma GAA) GA {
|
||||
return MonadChain[GA, GAA, func(GA) GA](mma, F.Identity[GA])
|
||||
func Flatten[GAA ~func() P.Pair[GA, W], GA ~func() P.Pair[A, W], W, A any](s SG.Semigroup[W], mma GAA) GA {
|
||||
return MonadChain[GA, GAA, func(GA) GA](s, mma, F.Identity[GA])
|
||||
}
|
||||
|
||||
func Execute[GA ~func() T.Tuple3[A, W, SG.Semigroup[W]], W, A any](fa GA) W {
|
||||
return fa().F2
|
||||
func Execute[GA ~func() P.Pair[A, W], W, A any](fa GA) W {
|
||||
return P.Tail(fa())
|
||||
}
|
||||
|
||||
func Evaluate[GA ~func() T.Tuple3[A, W, SG.Semigroup[W]], W, A any](fa GA) A {
|
||||
return fa().F1
|
||||
func Evaluate[GA ~func() P.Pair[A, W], W, A any](fa GA) A {
|
||||
return P.Head(fa())
|
||||
}
|
||||
|
||||
// MonadCensor modifies the final accumulator value by applying a function
|
||||
func MonadCensor[GA ~func() T.Tuple3[A, W, SG.Semigroup[W]], FCT ~func(W) W, W, A any](fa GA, f FCT) GA {
|
||||
return IO.MonadMap[GA, GA](fa, T.Map3(F.Identity[A], f, F.Identity[SG.Semigroup[W]]))
|
||||
func MonadCensor[GA ~func() P.Pair[A, W], FCT ~func(W) W, W, A any](fa GA, f FCT) GA {
|
||||
return IO.MonadMap[GA, GA](fa, P.MapTail[A](f))
|
||||
}
|
||||
|
||||
// Censor modifies the final accumulator value by applying a function
|
||||
func Censor[GA ~func() T.Tuple3[A, W, SG.Semigroup[W]], FCT ~func(W) W, W, A any](f FCT) func(GA) GA {
|
||||
return IO.Map[GA, GA](T.Map3(F.Identity[A], f, F.Identity[SG.Semigroup[W]]))
|
||||
func Censor[GA ~func() P.Pair[A, W], FCT ~func(W) W, W, A any](f FCT) func(GA) GA {
|
||||
return IO.Map[GA, GA](P.MapTail[A](f))
|
||||
}
|
||||
|
||||
// MonadListens projects a value from modifications made to the accumulator during an action
|
||||
func MonadListens[GA ~func() T.Tuple3[A, W, SG.Semigroup[W]], GAB ~func() T.Tuple3[T.Tuple2[A, B], W, SG.Semigroup[W]], FCT ~func(W) B, W, A, B any](fa GA, f FCT) GAB {
|
||||
return func() T.Tuple3[T.Tuple2[A, B], W, SG.Semigroup[W]] {
|
||||
func MonadListens[GA ~func() P.Pair[A, W], GAB ~func() P.Pair[P.Pair[A, B], W], FCT ~func(W) B, W, A, B any](fa GA, f FCT) GAB {
|
||||
return func() P.Pair[P.Pair[A, B], W] {
|
||||
a := fa()
|
||||
return T.MakeTuple3(T.MakeTuple2(a.F1, f(a.F2)), a.F2, a.F3)
|
||||
t := P.Tail(a)
|
||||
return P.MakePair(P.MakePair(P.Head(a), f(t)), t)
|
||||
}
|
||||
}
|
||||
|
||||
// Listens projects a value from modifications made to the accumulator during an action
|
||||
func Listens[GA ~func() T.Tuple3[A, W, SG.Semigroup[W]], GAB ~func() T.Tuple3[T.Tuple2[A, B], W, SG.Semigroup[W]], FCT ~func(W) B, W, A, B any](f FCT) func(GA) GAB {
|
||||
func Listens[GA ~func() P.Pair[A, W], GAB ~func() P.Pair[P.Pair[A, B], W], FCT ~func(W) B, W, A, B any](f FCT) func(GA) GAB {
|
||||
return F.Bind2nd(MonadListens[GA, GAB, FCT], f)
|
||||
}
|
||||
|
||||
func MonadFlap[FAB ~func(A) B, GFAB ~func() T.Tuple3[FAB, W, SG.Semigroup[W]], GB ~func() T.Tuple3[B, W, SG.Semigroup[W]], W, A, B any](fab GFAB, a A) GB {
|
||||
func MonadFlap[FAB ~func(A) B, GFAB ~func() P.Pair[FAB, W], GB ~func() P.Pair[B, W], W, A, B any](fab GFAB, a A) GB {
|
||||
return FC.MonadFlap(
|
||||
MonadMap[GB, GFAB, func(FAB) B],
|
||||
fab,
|
||||
a)
|
||||
}
|
||||
|
||||
func Flap[FAB ~func(A) B, GFAB ~func() T.Tuple3[FAB, W, SG.Semigroup[W]], GB ~func() T.Tuple3[B, W, SG.Semigroup[W]], W, A, B any](a A) func(GFAB) GB {
|
||||
func Flap[FAB ~func(A) B, GFAB ~func() P.Pair[FAB, W], GB ~func() P.Pair[B, W], W, A, B any](a A) func(GFAB) GB {
|
||||
return FC.Flap(Map[GB, GFAB, func(FAB) B], a)
|
||||
}
|
||||
|
45
writer/monad.go
Normal file
45
writer/monad.go
Normal file
@@ -0,0 +1,45 @@
|
||||
// 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 writer
|
||||
|
||||
import (
|
||||
"github.com/IBM/fp-go/internal/applicative"
|
||||
"github.com/IBM/fp-go/internal/functor"
|
||||
"github.com/IBM/fp-go/internal/monad"
|
||||
"github.com/IBM/fp-go/internal/pointed"
|
||||
M "github.com/IBM/fp-go/monoid"
|
||||
G "github.com/IBM/fp-go/writer/generic"
|
||||
)
|
||||
|
||||
// Pointed implements the pointed operations for [Writer]
|
||||
func Pointed[W, A any](m M.Monoid[W]) pointed.Pointed[A, Writer[W, A]] {
|
||||
return G.Pointed[Writer[W, A], W, A](m)
|
||||
}
|
||||
|
||||
// Functor implements the pointed operations for [Writer]
|
||||
func Functor[W, A, B any]() functor.Functor[A, B, Writer[W, A], Writer[W, B]] {
|
||||
return G.Functor[Writer[W, B], Writer[W, A], W, A, B]()
|
||||
}
|
||||
|
||||
// Applicative implements the applicative operations for [Writer]
|
||||
func Applicative[W, A, B any](m M.Monoid[W]) applicative.Applicative[A, B, Writer[W, A], Writer[W, B], Writer[W, func(A) B]] {
|
||||
return G.Applicative[Writer[W, B], Writer[W, func(A) B], Writer[W, A]](m)
|
||||
}
|
||||
|
||||
// Monad implements the monadic operations for [Writer]
|
||||
func Monad[W, A, B any](m M.Monoid[W]) monad.Monad[A, B, Writer[W, A], Writer[W, B], Writer[W, func(A) B]] {
|
||||
return G.Monad[Writer[W, B], Writer[W, func(A) B], Writer[W, A]](m)
|
||||
}
|
@@ -37,39 +37,40 @@ func AssertLaws[W, A, B, C any](t *testing.T,
|
||||
bc func(B) C,
|
||||
) func(a A) bool {
|
||||
|
||||
return L.AssertLaws(t,
|
||||
fofc := WRT.Pointed[W, C](m)
|
||||
fofaa := WRT.Pointed[W, func(A) A](m)
|
||||
fofbc := WRT.Pointed[W, func(B) C](m)
|
||||
fofabb := WRT.Pointed[W, func(func(A) B) B](m)
|
||||
|
||||
fmap := WRT.Functor[W, func(B) C, func(func(A) B) func(A) C]()
|
||||
|
||||
fapabb := WRT.Applicative[W, func(A) B, B](m)
|
||||
fapabac := WRT.Applicative[W, func(A) B, func(A) C](m)
|
||||
|
||||
maa := WRT.Monad[W, A, A](m)
|
||||
mab := WRT.Monad[W, A, B](m)
|
||||
mac := WRT.Monad[W, A, C](m)
|
||||
mbc := WRT.Monad[W, B, C](m)
|
||||
|
||||
return L.MonadAssertLaws(t,
|
||||
WRT.Eq(eqw, eqa),
|
||||
WRT.Eq(eqw, eqb),
|
||||
WRT.Eq(eqw, eqc),
|
||||
|
||||
WRT.Of[A](m),
|
||||
WRT.Of[B](m),
|
||||
WRT.Of[C](m),
|
||||
fofc,
|
||||
fofaa,
|
||||
fofbc,
|
||||
fofabb,
|
||||
|
||||
WRT.Of[func(A) A](m),
|
||||
WRT.Of[func(A) B](m),
|
||||
WRT.Of[func(B) C](m),
|
||||
WRT.Of[func(func(A) B) B](m),
|
||||
fmap,
|
||||
|
||||
WRT.MonadMap[func(A) A, W, A, A],
|
||||
WRT.MonadMap[func(A) B, W, A, B],
|
||||
WRT.MonadMap[func(A) C, W, A, C],
|
||||
WRT.MonadMap[func(B) C, W, B, C],
|
||||
fapabb,
|
||||
fapabac,
|
||||
|
||||
WRT.MonadMap[func(func(B) C) func(func(A) B) func(A) C, W, func(B) C, func(func(A) B) func(A) C],
|
||||
|
||||
WRT.MonadChain[func(A) WRT.Writer[W, A], W, A, A],
|
||||
WRT.MonadChain[func(A) WRT.Writer[W, B], W, A, B],
|
||||
WRT.MonadChain[func(A) WRT.Writer[W, C], W, A, C],
|
||||
WRT.MonadChain[func(B) WRT.Writer[W, C], W, B, C],
|
||||
|
||||
WRT.MonadAp[A, A, W],
|
||||
WRT.MonadAp[B, A, W],
|
||||
WRT.MonadAp[C, B, W],
|
||||
WRT.MonadAp[C, A, W],
|
||||
|
||||
WRT.MonadAp[B, func(A) B, W],
|
||||
WRT.MonadAp[func(A) C, func(A) B, W],
|
||||
maa,
|
||||
mab,
|
||||
mac,
|
||||
mbc,
|
||||
|
||||
ab,
|
||||
bc,
|
||||
|
@@ -19,30 +19,30 @@ import (
|
||||
EM "github.com/IBM/fp-go/endomorphism"
|
||||
IO "github.com/IBM/fp-go/io"
|
||||
M "github.com/IBM/fp-go/monoid"
|
||||
S "github.com/IBM/fp-go/semigroup"
|
||||
T "github.com/IBM/fp-go/tuple"
|
||||
P "github.com/IBM/fp-go/pair"
|
||||
SG "github.com/IBM/fp-go/semigroup"
|
||||
G "github.com/IBM/fp-go/writer/generic"
|
||||
)
|
||||
|
||||
type Writer[W, A any] IO.IO[T.Tuple3[A, W, S.Semigroup[W]]]
|
||||
type Writer[W, A any] IO.IO[P.Pair[A, W]]
|
||||
|
||||
// Tell appends a value to the accumulator
|
||||
func Tell[W any](s S.Semigroup[W]) func(W) Writer[W, any] {
|
||||
return G.Tell[Writer[W, any]](s)
|
||||
func Tell[W any](w W) Writer[W, any] {
|
||||
return G.Tell[Writer[W, any]](w)
|
||||
}
|
||||
|
||||
func Of[A, W any](m M.Monoid[W]) func(A) Writer[W, A] {
|
||||
return G.Of[Writer[W, A]](m)
|
||||
func Of[A, W any](m M.Monoid[W], a A) Writer[W, A] {
|
||||
return G.Of[Writer[W, A]](m, a)
|
||||
}
|
||||
|
||||
// Listen modifies the result to include the changes to the accumulator
|
||||
func Listen[W, A any](fa Writer[W, A]) Writer[W, T.Tuple2[A, W]] {
|
||||
return G.Listen[Writer[W, A], Writer[W, T.Tuple2[A, W]], W, A](fa)
|
||||
func Listen[W, A any](fa Writer[W, A]) Writer[W, P.Pair[A, W]] {
|
||||
return G.Listen[Writer[W, A], Writer[W, P.Pair[A, W]], W, A](fa)
|
||||
}
|
||||
|
||||
// Pass applies the returned function to the accumulator
|
||||
func Pass[W, A any](fa Writer[W, T.Tuple2[A, EM.Endomorphism[W]]]) Writer[W, A] {
|
||||
return G.Pass[Writer[W, T.Tuple2[A, EM.Endomorphism[W]]], Writer[W, A]](fa)
|
||||
func Pass[W, A any](fa Writer[W, P.Pair[A, EM.Endomorphism[W]]]) Writer[W, A] {
|
||||
return G.Pass[Writer[W, P.Pair[A, EM.Endomorphism[W]]], Writer[W, A]](fa)
|
||||
}
|
||||
|
||||
func MonadMap[FCT ~func(A) B, W, A, B any](fa Writer[W, A], f FCT) Writer[W, B] {
|
||||
@@ -53,32 +53,32 @@ func Map[W any, FCT ~func(A) B, A, B any](f FCT) func(Writer[W, A]) Writer[W, B]
|
||||
return G.Map[Writer[W, B], Writer[W, A]](f)
|
||||
}
|
||||
|
||||
func MonadChain[FCT ~func(A) Writer[W, B], W, A, B any](fa Writer[W, A], fct FCT) Writer[W, B] {
|
||||
return G.MonadChain[Writer[W, B], Writer[W, A], FCT](fa, fct)
|
||||
func MonadChain[FCT ~func(A) Writer[W, B], W, A, B any](s SG.Semigroup[W], fa Writer[W, A], fct FCT) Writer[W, B] {
|
||||
return G.MonadChain[Writer[W, B], Writer[W, A], FCT](s, fa, fct)
|
||||
}
|
||||
|
||||
func Chain[A, B, W any](fa func(A) Writer[W, B]) func(Writer[W, A]) Writer[W, B] {
|
||||
return G.Chain[Writer[W, B], Writer[W, A], func(A) Writer[W, B]](fa)
|
||||
func Chain[A, B, W any](s SG.Semigroup[W], fa func(A) Writer[W, B]) func(Writer[W, A]) Writer[W, B] {
|
||||
return G.Chain[Writer[W, B], Writer[W, A], func(A) Writer[W, B]](s, fa)
|
||||
}
|
||||
|
||||
func MonadAp[B, A, W any](fab Writer[W, func(A) B], fa Writer[W, A]) Writer[W, B] {
|
||||
return G.MonadAp[Writer[W, B], Writer[W, func(A) B], Writer[W, A]](fab, fa)
|
||||
func MonadAp[B, A, W any](s SG.Semigroup[W], fab Writer[W, func(A) B], fa Writer[W, A]) Writer[W, B] {
|
||||
return G.MonadAp[Writer[W, B], Writer[W, func(A) B], Writer[W, A]](s, fab, fa)
|
||||
}
|
||||
|
||||
func Ap[B, A, W any](fa Writer[W, A]) func(Writer[W, func(A) B]) Writer[W, B] {
|
||||
return G.Ap[Writer[W, B], Writer[W, func(A) B], Writer[W, A]](fa)
|
||||
func Ap[B, A, W any](s SG.Semigroup[W], fa Writer[W, A]) func(Writer[W, func(A) B]) Writer[W, B] {
|
||||
return G.Ap[Writer[W, B], Writer[W, func(A) B], Writer[W, A]](s, fa)
|
||||
}
|
||||
|
||||
func MonadChainFirst[FCT ~func(A) Writer[W, B], W, A, B any](fa Writer[W, A], fct FCT) Writer[W, A] {
|
||||
return G.MonadChainFirst[Writer[W, B], Writer[W, A], FCT](fa, fct)
|
||||
func MonadChainFirst[FCT ~func(A) Writer[W, B], W, A, B any](s SG.Semigroup[W], fa Writer[W, A], fct FCT) Writer[W, A] {
|
||||
return G.MonadChainFirst[Writer[W, B], Writer[W, A], FCT](s, fa, fct)
|
||||
}
|
||||
|
||||
func ChainFirst[FCT ~func(A) Writer[W, B], W, A, B any](fct FCT) func(Writer[W, A]) Writer[W, A] {
|
||||
return G.ChainFirst[Writer[W, B], Writer[W, A], FCT](fct)
|
||||
func ChainFirst[FCT ~func(A) Writer[W, B], W, A, B any](s SG.Semigroup[W], fct FCT) func(Writer[W, A]) Writer[W, A] {
|
||||
return G.ChainFirst[Writer[W, B], Writer[W, A], FCT](s, fct)
|
||||
}
|
||||
|
||||
func Flatten[W, A any](mma Writer[W, Writer[W, A]]) Writer[W, A] {
|
||||
return G.Flatten[Writer[W, Writer[W, A]], Writer[W, A]](mma)
|
||||
func Flatten[W, A any](s SG.Semigroup[W], mma Writer[W, Writer[W, A]]) Writer[W, A] {
|
||||
return G.Flatten[Writer[W, Writer[W, A]], Writer[W, A]](s, mma)
|
||||
}
|
||||
|
||||
// Execute extracts the accumulator
|
||||
@@ -102,13 +102,13 @@ func Censor[A any, FCT ~func(W) W, W any](f FCT) func(Writer[W, A]) Writer[W, A]
|
||||
}
|
||||
|
||||
// MonadListens projects a value from modifications made to the accumulator during an action
|
||||
func MonadListens[A any, FCT ~func(W) B, W, B any](fa Writer[W, A], f FCT) Writer[W, T.Tuple2[A, B]] {
|
||||
return G.MonadListens[Writer[W, A], Writer[W, T.Tuple2[A, B]]](fa, f)
|
||||
func MonadListens[A any, FCT ~func(W) B, W, B any](fa Writer[W, A], f FCT) Writer[W, P.Pair[A, B]] {
|
||||
return G.MonadListens[Writer[W, A], Writer[W, P.Pair[A, B]]](fa, f)
|
||||
}
|
||||
|
||||
// Listens projects a value from modifications made to the accumulator during an action
|
||||
func Listens[A any, FCT ~func(W) B, W, B any](f FCT) func(Writer[W, A]) Writer[W, T.Tuple2[A, B]] {
|
||||
return G.Listens[Writer[W, A], Writer[W, T.Tuple2[A, B]]](f)
|
||||
func Listens[A any, FCT ~func(W) B, W, B any](f FCT) func(Writer[W, A]) Writer[W, P.Pair[A, B]] {
|
||||
return G.Listens[Writer[W, A], Writer[W, P.Pair[A, B]]](f)
|
||||
}
|
||||
|
||||
func MonadFlap[W, B, A any](fab Writer[W, func(A) B], a A) Writer[W, B] {
|
||||
|
@@ -20,24 +20,22 @@ import (
|
||||
|
||||
A "github.com/IBM/fp-go/array"
|
||||
F "github.com/IBM/fp-go/function"
|
||||
S "github.com/IBM/fp-go/semigroup"
|
||||
T "github.com/IBM/fp-go/tuple"
|
||||
P "github.com/IBM/fp-go/pair"
|
||||
)
|
||||
|
||||
func doubleAndLog(data int) Writer[[]string, int] {
|
||||
return func() T.Tuple3[int, []string, S.Semigroup[[]string]] {
|
||||
return func() P.Pair[int, []string] {
|
||||
result := data * 2
|
||||
return T.MakeTuple3(result, A.Of(fmt.Sprintf("Doubled %d -> %d", data, result)), sg)
|
||||
return P.MakePair(result, A.Of(fmt.Sprintf("Doubled %d -> %d", data, result)))
|
||||
}
|
||||
}
|
||||
|
||||
func ExampleWriter_logging() {
|
||||
|
||||
res := F.Pipe4(
|
||||
10,
|
||||
Of[int](monoid),
|
||||
Chain(doubleAndLog),
|
||||
Chain(doubleAndLog),
|
||||
res := F.Pipe3(
|
||||
Of[int](monoid, 10),
|
||||
Chain(sg, doubleAndLog),
|
||||
Chain(sg, doubleAndLog),
|
||||
Execute[[]string, int],
|
||||
)
|
||||
|
||||
|
Reference in New Issue
Block a user