Skip to content

Commit

Permalink
Merge pull request #11 from IBM/cleue-better-doc
Browse files Browse the repository at this point in the history
fix: introduce stateless iterator
  • Loading branch information
CarstenLeue authored Jul 24, 2023
2 parents 8c58e8d + 1713de0 commit 41b792b
Show file tree
Hide file tree
Showing 51 changed files with 2,076 additions and 25 deletions.
13 changes: 6 additions & 7 deletions array/array.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ func Append[A any](as []A, a A) []A {
}

func IsEmpty[A any](as []A) bool {
return array.IsEmpty(as)
return G.IsEmpty(as)
}

func IsNonEmpty[A any](as []A) bool {
Expand Down Expand Up @@ -181,12 +181,11 @@ func Ap[B, A any](fa []A) func([]func(A) B) []B {
}

func Match[A, B any](onEmpty func() B, onNonEmpty func([]A) B) func([]A) B {
return func(as []A) B {
if IsEmpty(as) {
return onEmpty()
}
return onNonEmpty(as)
}
return G.Match[[]A](onEmpty, onNonEmpty)
}

func MatchLeft[A, B any](onEmpty func() B, onNonEmpty func(A, []A) B) func([]A) B {
return G.MatchLeft[[]A](onEmpty, onNonEmpty)
}

func Tail[A any](as []A) O.Option[[]A] {
Expand Down
22 changes: 22 additions & 0 deletions array/generic/array.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,3 +158,25 @@ func MonadAp[BS ~[]B, ABS ~[]func(A) B, AS ~[]A, B, A any](fab ABS, fa AS) BS {
func Ap[BS ~[]B, ABS ~[]func(A) B, AS ~[]A, B, A any](fa AS) func(ABS) BS {
return F.Bind2nd(MonadAp[BS, ABS, AS], fa)
}

func IsEmpty[AS ~[]A, A any](as AS) bool {
return array.IsEmpty(as)
}

func Match[AS ~[]A, A, B any](onEmpty func() B, onNonEmpty func(AS) B) func(AS) B {
return func(as AS) B {
if IsEmpty(as) {
return onEmpty()
}
return onNonEmpty(as)
}
}

func MatchLeft[AS ~[]A, A, B any](onEmpty func() B, onNonEmpty func(A, AS) B) func(AS) B {
return func(as AS) B {
if IsEmpty(as) {
return onEmpty()
}
return onNonEmpty(as[0], as[1:])
}
}
64 changes: 64 additions & 0 deletions bounded/bounded.go
Original file line number Diff line number Diff line change
@@ -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 bounded

import (
O "github.com/IBM/fp-go/ord"
)

type Bounded[T any] interface {
O.Ord[T]
Top() T
Bottom() T
}

type bounded[T any] struct {
c func(x, y T) int
e func(x, y T) bool
t T
b T
}

func (self bounded[T]) Equals(x, y T) bool {
return self.e(x, y)
}

func (self bounded[T]) Compare(x, y T) int {
return self.c(x, y)
}

func (self bounded[T]) Top() T {
return self.t
}

func (self bounded[T]) Bottom() T {
return self.b
}

// MakeBounded creates an instance of a bounded type
func MakeBounded[T any](o O.Ord[T], t, b T) Bounded[T] {
return bounded[T]{c: o.Compare, e: o.Equals, t: t, b: b}
}

// Clamp returns a function that clamps against the bounds defined in the bounded type
func Clamp[T any](b Bounded[T]) func(T) T {
return O.Clamp[T](b)(b.Bottom(), b.Top())
}

// Reverse reverses the ordering and swaps the bounds
func Reverse[T any](b Bounded[T]) Bounded[T] {
return MakeBounded(O.Reverse[T](b), b.Bottom(), b.Top())
}
4 changes: 4 additions & 0 deletions bytes/bytes.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,7 @@ package bytes
func ToString(a []byte) string {
return string(a)
}

func Size(as []byte) int {
return len(as)
}
2 changes: 1 addition & 1 deletion context/readerioeither/cancel.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import (
G "github.com/IBM/fp-go/context/readerioeither/generic"
)

// WithContext wraps an existing ReaderIOEither and performs a context check for cancellation before delegating
// WithContext wraps an existing [ReaderIOEither] and performs a context check for cancellation before delegating
func WithContext[A any](ma ReaderIOEither[A]) ReaderIOEither[A] {
return G.WithContext(ma)
}
1 change: 1 addition & 0 deletions context/readerioeither/data/file.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Carsten
2 changes: 1 addition & 1 deletion context/readerioeither/eq.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import (
EQ "github.com/IBM/fp-go/eq"
)

// Eq implements the equals predicate for values contained in the IOEither monad
// Eq implements the equals predicate for values contained in the [ReaderIOEither] monad
func Eq[A any](eq EQ.Eq[ET.Either[error, A]]) func(context.Context) EQ.Eq[ReaderIOEither[A]] {
return G.Eq[ReaderIOEither[A]](eq)
}
2 changes: 1 addition & 1 deletion context/readerioeither/file/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ func Close[C io.Closer](c C) RIOE.ReaderIOEither[any] {

// ReadFile reads a file in the scope of a context
func ReadFile(path string) RIOE.ReaderIOEither[[]byte] {
return RIOE.WithResource[*os.File, []byte](Open(path), Close[*os.File])(func(r *os.File) RIOE.ReaderIOEither[[]byte] {
return RIOE.WithResource[[]byte](Open(path), Close[*os.File])(func(r *os.File) RIOE.ReaderIOEither[[]byte] {
return func(ctx context.Context) IOE.IOEither[error, []byte] {
return IOE.MakeIO(func() ET.Either[error, []byte] {
return file.ReadAll(ctx, r)
Expand Down
2 changes: 1 addition & 1 deletion context/readerioeither/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import (
)

// WithResource constructs a function that creates a resource, then operates on it and then releases the resource
func WithResource[R, A, ANY any](onCreate ReaderIOEither[R], onRelease func(R) ReaderIOEither[ANY]) func(func(R) ReaderIOEither[A]) ReaderIOEither[A] {
func WithResource[A, R, ANY any](onCreate ReaderIOEither[R], onRelease func(R) ReaderIOEither[ANY]) func(func(R) ReaderIOEither[A]) ReaderIOEither[A] {
// wraps the callback functions with a context check
return G.WithResource[ReaderIOEither[A]](onCreate, onRelease)
}
79 changes: 79 additions & 0 deletions context/readerioeither/resource_test.go
Original file line number Diff line number Diff line change
@@ -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 readerioeither

import (
"context"
"io"
"os"

B "github.com/IBM/fp-go/bytes"
F "github.com/IBM/fp-go/function"
IO "github.com/IBM/fp-go/io"
IOE "github.com/IBM/fp-go/ioeither"
)

var (
openFile = F.Flow3(
IOE.Eitherize1(os.Open),
FromIOEither[*os.File],
ChainFirstIOK(F.Flow2(
(*os.File).Name,
IO.Logf[string]("Opened file [%s]"),
)),
)
)

func closeFile(f *os.File) ReaderIOEither[string] {
return F.Pipe1(
TryCatch(func(_ context.Context) func() (string, error) {
return func() (string, error) {
return f.Name(), f.Close()
}
}),
ChainFirstIOK(IO.Logf[string]("Closed file [%s]")),
)
}

func ExampleWithResource() {

stringReader := WithResource[string](openFile("data/file.txt"), closeFile)

rdr := stringReader(func(f *os.File) ReaderIOEither[string] {
return F.Pipe2(
TryCatch(func(_ context.Context) func() ([]byte, error) {
return func() ([]byte, error) {
return io.ReadAll(f)
}
}),
ChainFirstIOK(F.Flow2(
B.Size,
IO.Logf[int]("Read content of length [%d]"),
)),
Map(B.ToString),
)
})

contentIOE := F.Pipe2(
context.Background(),
rdr,
IOE.ChainFirstIOK[error](IO.Printf[string]("Content: %s")),
)

contentIOE()

// Output: Content: Carsten
}
3 changes: 2 additions & 1 deletion context/readerioeither/type.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,6 @@ import (
RE "github.com/IBM/fp-go/readerioeither"
)

// ReaderIOEither is a specialization of the Reader monad for the typical golang scenario
// ReaderIOEither is a specialization of the [RE.ReaderIOEither] monad for the typical golang scenario in which the
// left value is an [error] and the context is a [context.Context]
type ReaderIOEither[A any] RE.ReaderIOEither[context.Context, error, A]
51 changes: 51 additions & 0 deletions erasure/erasure.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package erasure

import (
F "github.com/IBM/fp-go/function"
)

// Erase converts a variable of type T to an any by returning a pointer to that variable
func Erase[T any](t T) any {
return &t
}

// Unerase converts an erased variable back to its original value
func Unerase[T any](t any) T {
return *t.(*T)
}

// Erase0 converts a type safe function into an erased function
func Erase0[T1 any](f func() T1) func() any {
return F.Nullary2(f, Erase[T1])
}

// Erase1 converts a type safe function into an erased function
func Erase1[T1, T2 any](f func(T1) T2) func(any) any {
return F.Flow3(
Unerase[T1],
f,
Erase[T2],
)
}

// Erase2 converts a type safe function into an erased function
func Erase2[T1, T2, T3 any](f func(T1, T2) T3) func(any, any) any {
return func(t1, t2 any) any {
return Erase(f(Unerase[T1](t1), Unerase[T2](t2)))
}
}
39 changes: 39 additions & 0 deletions erasure/erasure_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package erasure

import (
"fmt"
"strings"
"testing"

E "github.com/IBM/fp-go/either"
F "github.com/IBM/fp-go/function"
)

func TestEither(t *testing.T) {

e1 := F.Pipe3(
E.Of[error](Erase("Carsten")),
E.Map[error](Erase1(strings.ToUpper)),
E.GetOrElse(func(e error) any {
return Erase("Error")
}),
Unerase[string],
)

fmt.Println(e1)
}
Loading

0 comments on commit 41b792b

Please sign in to comment.