mirror of
https://github.com/IBM/fp-go.git
synced 2025-12-09 23:11:40 +02:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
311ed55f06 | ||
|
|
23333ce52c |
210
v2/README.md
210
v2/README.md
@@ -2,25 +2,152 @@
|
||||
|
||||
[](https://pkg.go.dev/github.com/IBM/fp-go/v2)
|
||||
[](https://coveralls.io/github/IBM/fp-go?branch=main)
|
||||
[](https://goreportcard.com/report/github.com/IBM/fp-go/v2)
|
||||
|
||||
Version 2 of fp-go leverages [generic type aliases](https://github.com/golang/go/issues/46477) introduced in Go 1.24, providing a more ergonomic and streamlined API.
|
||||
**fp-go** is a comprehensive functional programming library for Go, bringing type-safe functional patterns inspired by [fp-ts](https://gcanti.github.io/fp-ts/) to the Go ecosystem. Version 2 leverages [generic type aliases](https://github.com/golang/go/issues/46477) introduced in Go 1.24, providing a more ergonomic and streamlined API.
|
||||
|
||||
## 📚 Table of Contents
|
||||
|
||||
- [Overview](#-overview)
|
||||
- [Features](#-features)
|
||||
- [Requirements](#-requirements)
|
||||
- [Breaking Changes](#-breaking-changes)
|
||||
- [Installation](#-installation)
|
||||
- [Quick Start](#-quick-start)
|
||||
- [Breaking Changes](#️-breaking-changes)
|
||||
- [Key Improvements](#-key-improvements)
|
||||
- [Migration Guide](#-migration-guide)
|
||||
- [Installation](#-installation)
|
||||
- [What's New](#-whats-new)
|
||||
- [Documentation](#-documentation)
|
||||
- [Contributing](#-contributing)
|
||||
- [License](#-license)
|
||||
|
||||
## 🎯 Overview
|
||||
|
||||
fp-go brings the power of functional programming to Go with:
|
||||
|
||||
- **Type-safe abstractions** - Monads, Functors, Applicatives, and more
|
||||
- **Composable operations** - Build complex logic from simple, reusable functions
|
||||
- **Error handling** - Elegant error management with `Either`, `Result`, and `IOEither`
|
||||
- **Lazy evaluation** - Control when and how computations execute
|
||||
- **Optics** - Powerful lens, prism, and traversal operations for immutable data manipulation
|
||||
|
||||
## ✨ Features
|
||||
|
||||
- 🔒 **Type Safety** - Leverage Go's generics for compile-time guarantees
|
||||
- 🧩 **Composability** - Chain operations naturally with functional composition
|
||||
- 📦 **Rich Type System** - `Option`, `Either`, `Result`, `IO`, `Reader`, and more
|
||||
- 🎯 **Practical** - Designed for real-world Go applications
|
||||
- 🚀 **Performance** - Zero-cost abstractions where possible
|
||||
- 📖 **Well-documented** - Comprehensive API documentation and examples
|
||||
- 🧪 **Battle-tested** - Extensive test coverage
|
||||
|
||||
## 🔧 Requirements
|
||||
|
||||
- **Go 1.24 or later** (for generic type alias support)
|
||||
|
||||
## ⚠️ Breaking Changes
|
||||
## 📦 Installation
|
||||
|
||||
### 1. Generic Type Aliases
|
||||
```bash
|
||||
go get github.com/IBM/fp-go/v2
|
||||
```
|
||||
|
||||
## 🚀 Quick Start
|
||||
|
||||
### Working with Option
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/IBM/fp-go/v2/option"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Create an Option
|
||||
some := option.Some(42)
|
||||
none := option.None[int]()
|
||||
|
||||
// Map over values
|
||||
doubled := option.Map(func(x int) int { return x * 2 })(some)
|
||||
fmt.Println(option.GetOrElse(0)(doubled)) // Output: 84
|
||||
|
||||
// Chain operations
|
||||
result := option.Chain(func(x int) option.Option[string] {
|
||||
if x > 0 {
|
||||
return option.Some(fmt.Sprintf("Positive: %d", x))
|
||||
}
|
||||
return option.None[string]()
|
||||
})(some)
|
||||
|
||||
fmt.Println(option.GetOrElse("No value")(result)) // Output: Positive: 42
|
||||
}
|
||||
```
|
||||
|
||||
### Error Handling with Result
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/IBM/fp-go/v2/result"
|
||||
)
|
||||
|
||||
func divide(a, b int) result.Result[int] {
|
||||
if b == 0 {
|
||||
return result.Error[int](errors.New("division by zero"))
|
||||
}
|
||||
return result.Ok(a / b)
|
||||
}
|
||||
|
||||
func main() {
|
||||
res := divide(10, 2)
|
||||
|
||||
// Pattern match on the result
|
||||
result.Fold(
|
||||
func(err error) { fmt.Println("Error:", err) },
|
||||
func(val int) { fmt.Println("Result:", val) },
|
||||
)(res)
|
||||
// Output: Result: 5
|
||||
|
||||
// Or use GetOrElse for a default value
|
||||
value := result.GetOrElse(0)(divide(10, 0))
|
||||
fmt.Println("Value:", value) // Output: Value: 0
|
||||
}
|
||||
```
|
||||
|
||||
### Composing IO Operations
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/IBM/fp-go/v2/io"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Define pure IO operations
|
||||
readInput := io.MakeIO(func() string {
|
||||
return "Hello, fp-go!"
|
||||
})
|
||||
|
||||
// Transform the result
|
||||
uppercase := io.Map(func(s string) string {
|
||||
return fmt.Sprintf(">>> %s <<<", s)
|
||||
})(readInput)
|
||||
|
||||
// Execute the IO operation
|
||||
result := uppercase()
|
||||
fmt.Println(result) // Output: >>> Hello, fp-go! <<<
|
||||
}
|
||||
```
|
||||
|
||||
### From V1 to V2
|
||||
|
||||
#### 1. Generic Type Aliases
|
||||
|
||||
V2 uses [generic type aliases](https://github.com/golang/go/issues/46477) which require Go 1.24+. This is the most significant change and enables cleaner type definitions.
|
||||
|
||||
@@ -34,7 +161,7 @@ type ReaderIOEither[R, E, A any] RD.Reader[R, IOE.IOEither[E, A]]
|
||||
type ReaderIOEither[R, E, A any] = RD.Reader[R, IOE.IOEither[E, A]]
|
||||
```
|
||||
|
||||
### 2. Generic Type Parameter Ordering
|
||||
#### 2. Generic Type Parameter Ordering
|
||||
|
||||
Type parameters that **cannot** be inferred from function arguments now come first, improving type inference.
|
||||
|
||||
@@ -52,7 +179,7 @@ func Ap[B, R, E, A any](fa ReaderIOEither[R, E, A]) func(ReaderIOEither[R, E, fu
|
||||
|
||||
This change allows the Go compiler to infer more types automatically, reducing the need for explicit type parameters.
|
||||
|
||||
### 3. Pair Monad Semantics
|
||||
#### 3. Pair Monad Semantics
|
||||
|
||||
Monadic operations for `Pair` now operate on the **second argument** to align with the [Haskell definition](https://hackage.haskell.org/package/TypeCompose-0.9.14/docs/Data-Pair.html).
|
||||
|
||||
@@ -91,16 +218,16 @@ func processData(input string) ET.Either[error, OPT.Option[int]] {
|
||||
**V2 Approach:**
|
||||
```go
|
||||
import (
|
||||
"github.com/IBM/fp-go/v2/either"
|
||||
"github.com/IBM/fp-go/v2/result"
|
||||
"github.com/IBM/fp-go/v2/option"
|
||||
)
|
||||
|
||||
// Define type aliases once
|
||||
type Either[A any] = either.Either[error, A]
|
||||
type Result[A any] = result.Result[A]
|
||||
type Option[A any] = option.Option[A]
|
||||
|
||||
// Use them throughout your codebase
|
||||
func processData(input string) Either[Option[int]] {
|
||||
func processData(input string) Result[Option[int]] {
|
||||
// implementation
|
||||
}
|
||||
```
|
||||
@@ -230,20 +357,14 @@ Create project-wide type aliases for common patterns:
|
||||
package myapp
|
||||
|
||||
import (
|
||||
"github.com/IBM/fp-go/v2/either"
|
||||
"github.com/IBM/fp-go/v2/result"
|
||||
"github.com/IBM/fp-go/v2/option"
|
||||
"github.com/IBM/fp-go/v2/ioeither"
|
||||
"github.com/IBM/fp-go/v2/ioresult"
|
||||
)
|
||||
|
||||
type Either[A any] = either.Either[error, A]
|
||||
type Result[A any] = result.Result[A]
|
||||
type Option[A any] = option.Option[A]
|
||||
type IOEither[A any] = ioeither.IOEither[error, A]
|
||||
```
|
||||
|
||||
## 📦 Installation
|
||||
|
||||
```bash
|
||||
go get github.com/IBM/fp-go/v2
|
||||
type IOResult[A any] = ioresult.IOResult[A]
|
||||
```
|
||||
|
||||
## 🆕 What's New
|
||||
@@ -277,25 +398,37 @@ func process() IOET.IOEither[error, string] {
|
||||
**V2 Simplified Example:**
|
||||
```go
|
||||
import (
|
||||
"github.com/IBM/fp-go/v2/either"
|
||||
"github.com/IBM/fp-go/v2/ioeither"
|
||||
"strconv"
|
||||
"github.com/IBM/fp-go/v2/ioresult"
|
||||
)
|
||||
|
||||
type IOEither[A any] = ioeither.IOEither[error, A]
|
||||
type IOResult[A any] = ioresult.IOResult[A]
|
||||
|
||||
func process() IOEither[string] {
|
||||
return ioeither.Map(
|
||||
func process() IOResult[string] {
|
||||
return ioresult.Map(
|
||||
strconv.Itoa,
|
||||
)(fetchData())
|
||||
}
|
||||
```
|
||||
|
||||
## 📚 Additional Resources
|
||||
## 📚 Documentation
|
||||
|
||||
- [Main README](../README.md) - Core concepts and design philosophy
|
||||
- [API Documentation](https://pkg.go.dev/github.com/IBM/fp-go/v2)
|
||||
- [Code Samples](../samples/)
|
||||
- [Go 1.24 Release Notes](https://tip.golang.org/doc/go1.24)
|
||||
- **[API Documentation](https://pkg.go.dev/github.com/IBM/fp-go/v2)** - Complete API reference
|
||||
- **[Code Samples](./samples/)** - Practical examples and use cases
|
||||
- **[Go 1.24 Release Notes](https://tip.golang.org/doc/go1.24)** - Information about generic type aliases
|
||||
|
||||
### Core Modules
|
||||
|
||||
- **Option** - Represent optional values without nil
|
||||
- **Either** - Type-safe error handling with left/right values
|
||||
- **Result** - Simplified Either with error as left type
|
||||
- **IO** - Lazy evaluation and side effect management
|
||||
- **IOEither** - Combine IO with error handling
|
||||
- **Reader** - Dependency injection pattern
|
||||
- **ReaderIOEither** - Combine Reader, IO, and Either for complex workflows
|
||||
- **Array** - Functional array operations
|
||||
- **Record** - Functional record/map operations
|
||||
- **Optics** - Lens, Prism, Optional, and Traversal for immutable updates
|
||||
|
||||
## 🤔 Should I Migrate?
|
||||
|
||||
@@ -310,10 +443,25 @@ func process() IOEither[string] {
|
||||
- ⚠️ Migration effort outweighs benefits for your project
|
||||
- ⚠️ You need stability in production (V2 is newer)
|
||||
|
||||
## 🤝 Contributing
|
||||
|
||||
Contributions are welcome! Here's how you can help:
|
||||
|
||||
1. **Report bugs** - Open an issue with a clear description and reproduction steps
|
||||
2. **Suggest features** - Share your ideas for improvements
|
||||
3. **Submit PRs** - Fix bugs or add features (please discuss major changes first)
|
||||
4. **Improve docs** - Help make the documentation clearer and more comprehensive
|
||||
|
||||
Please read our contribution guidelines before submitting pull requests.
|
||||
|
||||
## 🐛 Issues and Feedback
|
||||
|
||||
Found a bug or have a suggestion? Please [open an issue](https://github.com/IBM/fp-go/issues) on GitHub.
|
||||
|
||||
## 📄 License
|
||||
|
||||
This project is licensed under the Apache License 2.0 - see the LICENSE file for details.
|
||||
This project is licensed under the Apache License 2.0. See the [LICENSE](https://github.com/IBM/fp-go/blob/main/LICENSE) file for details.
|
||||
|
||||
---
|
||||
|
||||
**Made with ❤️ by IBM**
|
||||
@@ -836,3 +836,8 @@ func ChainReaderOptionK[A, B any](onNone func() error) func(readeroption.Kleisli
|
||||
func ChainFirstReaderOptionK[A, B any](onNone func() error) func(readeroption.Kleisli[context.Context, A, B]) Operator[A, A] {
|
||||
return RIOR.ChainFirstReaderOptionK[context.Context, A, B](onNone)
|
||||
}
|
||||
|
||||
//go:inline
|
||||
func Read[A any](r context.Context) func(ReaderIOResult[A]) IOResult[A] {
|
||||
return RIOR.Read[A](r)
|
||||
}
|
||||
|
||||
@@ -883,5 +883,3 @@ func BenchmarkExecuteApPar_CanceledContext(b *testing.B) {
|
||||
benchResult = rioe(ctx)()
|
||||
}
|
||||
}
|
||||
|
||||
// Made with Bob
|
||||
|
||||
@@ -875,5 +875,3 @@ func TestBracket(t *testing.T) {
|
||||
assert.Equal(t, E.Left[int](err), res)
|
||||
})
|
||||
}
|
||||
|
||||
// Made with Bob
|
||||
|
||||
@@ -92,3 +92,8 @@ func MonadFlap[B, A any](fab ReaderResult[func(A) B], a A) ReaderResult[B] {
|
||||
func Flap[B, A any](a A) Operator[func(A) B, B] {
|
||||
return readereither.Flap[context.Context, error, B](a)
|
||||
}
|
||||
|
||||
//go:inline
|
||||
func Read[A any](r context.Context) func(ReaderResult[A]) Result[A] {
|
||||
return readereither.Read[error, A](r)
|
||||
}
|
||||
|
||||
@@ -23,11 +23,13 @@ import (
|
||||
"github.com/IBM/fp-go/v2/option"
|
||||
"github.com/IBM/fp-go/v2/reader"
|
||||
"github.com/IBM/fp-go/v2/readereither"
|
||||
"github.com/IBM/fp-go/v2/result"
|
||||
)
|
||||
|
||||
type (
|
||||
Option[A any] = option.Option[A]
|
||||
Either[A any] = either.Either[error, A]
|
||||
Result[A any] = result.Result[A]
|
||||
// ReaderResult is a specialization of the Reader monad for the typical golang scenario
|
||||
ReaderResult[A any] = readereither.ReaderEither[context.Context, error, A]
|
||||
|
||||
|
||||
@@ -648,5 +648,3 @@ func BenchmarkString_Left(b *testing.B) {
|
||||
benchString = left.String()
|
||||
}
|
||||
}
|
||||
|
||||
// Made with Bob
|
||||
|
||||
@@ -78,12 +78,26 @@ func Ap[A, B, HKTFAB, HKTFGAB, HKTFA, HKTFB any](
|
||||
return apply.Ap(fap, fmap, O.Ap[B, A], fa)
|
||||
}
|
||||
|
||||
func MatchE[A, HKTEA, HKTB any](mchain func(HKTEA, func(O.Option[A]) HKTB) HKTB, onNone func() HKTB, onSome func(A) HKTB) func(HKTEA) HKTB {
|
||||
return F.Bind2nd(mchain, O.Fold(onNone, onSome))
|
||||
func MonadMatchE[A, HKTEA, HKTB any](
|
||||
fa HKTEA,
|
||||
mchain func(HKTEA, func(O.Option[A]) HKTB) HKTB,
|
||||
onNone func() HKTB,
|
||||
onSome func(A) HKTB) HKTB {
|
||||
return mchain(fa, O.Fold(onNone, onSome))
|
||||
}
|
||||
|
||||
func MatchE[A, HKTEA, HKTB any](
|
||||
mchain func(func(O.Option[A]) HKTB) func(HKTEA) HKTB,
|
||||
onNone func() HKTB,
|
||||
onSome func(A) HKTB) func(HKTEA) HKTB {
|
||||
return mchain(O.Fold(onNone, onSome))
|
||||
}
|
||||
|
||||
//go:inline
|
||||
func GetOrElse[A, HKTEA, HKTB any](mchain func(HKTEA, func(O.Option[A]) HKTB) HKTB, onNone func() HKTB, onSome func(A) HKTB) func(HKTEA) HKTB {
|
||||
func GetOrElse[A, HKTEA, HKTB any](
|
||||
mchain func(func(O.Option[A]) HKTB) func(HKTEA) HKTB,
|
||||
onNone func() HKTB,
|
||||
onSome func(A) HKTB) func(HKTEA) HKTB {
|
||||
return MatchE(mchain, onNone, onSome)
|
||||
}
|
||||
|
||||
|
||||
@@ -233,7 +233,7 @@ func After[GA ~func() O.Option[A], A any](timestamp time.Time) func(GA) GA {
|
||||
|
||||
// Fold convers an IOOption into an IO
|
||||
func Fold[GA ~func() O.Option[A], GB ~func() B, A, B any](onNone func() GB, onSome func(A) GB) func(GA) GB {
|
||||
return optiont.MatchE(IO.MonadChain[GA, GB, O.Option[A], B], onNone, onSome)
|
||||
return optiont.MatchE(IO.Chain[GA, GB, O.Option[A], B], onNone, onSome)
|
||||
}
|
||||
|
||||
// Defer creates an IO by creating a brand new IO via a generator function, each time
|
||||
|
||||
@@ -24,6 +24,7 @@ import (
|
||||
"github.com/IBM/fp-go/v2/internal/fromio"
|
||||
"github.com/IBM/fp-go/v2/internal/optiont"
|
||||
"github.com/IBM/fp-go/v2/io"
|
||||
"github.com/IBM/fp-go/v2/lazy"
|
||||
"github.com/IBM/fp-go/v2/option"
|
||||
)
|
||||
|
||||
@@ -47,7 +48,7 @@ func FromOption[A any](o Option[A]) IOOption[A] {
|
||||
return io.Of(o)
|
||||
}
|
||||
|
||||
func ChainOptionK[A, B any](f func(A) Option[B]) func(IOOption[A]) IOOption[B] {
|
||||
func ChainOptionK[A, B any](f func(A) Option[B]) Operator[A, B] {
|
||||
return optiont.ChainOptionK(
|
||||
io.Chain[Option[A], Option[B]],
|
||||
FromOption[B],
|
||||
@@ -55,7 +56,7 @@ func ChainOptionK[A, B any](f func(A) Option[B]) func(IOOption[A]) IOOption[B] {
|
||||
)
|
||||
}
|
||||
|
||||
func MonadChainIOK[A, B any](ma IOOption[A], f func(A) IO[B]) IOOption[B] {
|
||||
func MonadChainIOK[A, B any](ma IOOption[A], f io.Kleisli[A, B]) IOOption[B] {
|
||||
return fromio.MonadChainIOK(
|
||||
MonadChain[A, B],
|
||||
FromIO[B],
|
||||
@@ -64,7 +65,7 @@ func MonadChainIOK[A, B any](ma IOOption[A], f func(A) IO[B]) IOOption[B] {
|
||||
)
|
||||
}
|
||||
|
||||
func ChainIOK[A, B any](f func(A) IO[B]) func(IOOption[A]) IOOption[B] {
|
||||
func ChainIOK[A, B any](f io.Kleisli[A, B]) Operator[A, B] {
|
||||
return fromio.ChainIOK(
|
||||
Chain[A, B],
|
||||
FromIO[B],
|
||||
@@ -80,15 +81,15 @@ func MonadMap[A, B any](fa IOOption[A], f func(A) B) IOOption[B] {
|
||||
return optiont.MonadMap(io.MonadMap[Option[A], Option[B]], fa, f)
|
||||
}
|
||||
|
||||
func Map[A, B any](f func(A) B) func(IOOption[A]) IOOption[B] {
|
||||
func Map[A, B any](f func(A) B) Operator[A, B] {
|
||||
return optiont.Map(io.Map[Option[A], Option[B]], f)
|
||||
}
|
||||
|
||||
func MonadChain[A, B any](fa IOOption[A], f func(A) IOOption[B]) IOOption[B] {
|
||||
func MonadChain[A, B any](fa IOOption[A], f Kleisli[A, B]) IOOption[B] {
|
||||
return optiont.MonadChain(io.MonadChain[Option[A], Option[B]], io.MonadOf[Option[B]], fa, f)
|
||||
}
|
||||
|
||||
func Chain[A, B any](f func(A) IOOption[B]) func(IOOption[A]) IOOption[B] {
|
||||
func Chain[A, B any](f Kleisli[A, B]) Operator[A, B] {
|
||||
return optiont.Chain(io.Chain[Option[A], Option[B]], io.Of[Option[B]], f)
|
||||
}
|
||||
|
||||
@@ -99,21 +100,21 @@ func MonadAp[B, A any](mab IOOption[func(A) B], ma IOOption[A]) IOOption[B] {
|
||||
mab, ma)
|
||||
}
|
||||
|
||||
func Ap[B, A any](ma IOOption[A]) func(IOOption[func(A) B]) IOOption[B] {
|
||||
func Ap[B, A any](ma IOOption[A]) Operator[func(A) B, B] {
|
||||
return optiont.Ap(
|
||||
io.Ap[Option[B], Option[A]],
|
||||
io.Map[Option[func(A) B], func(Option[A]) Option[B]],
|
||||
ma)
|
||||
}
|
||||
|
||||
func ApSeq[B, A any](ma IOOption[A]) func(IOOption[func(A) B]) IOOption[B] {
|
||||
func ApSeq[B, A any](ma IOOption[A]) Operator[func(A) B, B] {
|
||||
return optiont.Ap(
|
||||
io.ApSeq[Option[B], Option[A]],
|
||||
io.Map[Option[func(A) B], func(Option[A]) Option[B]],
|
||||
ma)
|
||||
}
|
||||
|
||||
func ApPar[B, A any](ma IOOption[A]) func(IOOption[func(A) B]) IOOption[B] {
|
||||
func ApPar[B, A any](ma IOOption[A]) Operator[func(A) B, B] {
|
||||
return optiont.Ap(
|
||||
io.ApPar[Option[B], Option[A]],
|
||||
io.Map[Option[func(A) B], func(Option[A]) Option[B]],
|
||||
@@ -124,14 +125,14 @@ func Flatten[A any](mma IOOption[IOOption[A]]) IOOption[A] {
|
||||
return MonadChain(mma, function.Identity[IOOption[A]])
|
||||
}
|
||||
|
||||
func Optionize0[A any](f func() (A, bool)) func() IOOption[A] {
|
||||
func Optionize0[A any](f func() (A, bool)) Lazy[IOOption[A]] {
|
||||
ef := option.Optionize0(f)
|
||||
return func() IOOption[A] {
|
||||
return ef
|
||||
}
|
||||
}
|
||||
|
||||
func Optionize1[T1, A any](f func(t1 T1) (A, bool)) func(T1) IOOption[A] {
|
||||
func Optionize1[T1, A any](f func(t1 T1) (A, bool)) Kleisli[T1, A] {
|
||||
ef := option.Optionize1(f)
|
||||
return func(t1 T1) IOOption[A] {
|
||||
return func() Option[A] {
|
||||
@@ -172,8 +173,8 @@ func Memoize[A any](ma IOOption[A]) IOOption[A] {
|
||||
}
|
||||
|
||||
// Fold convers an [IOOption] into an [IO]
|
||||
func Fold[A, B any](onNone func() IO[B], onSome func(A) IO[B]) func(IOOption[A]) IO[B] {
|
||||
return optiont.MatchE(io.MonadChain[Option[A], B], onNone, onSome)
|
||||
func Fold[A, B any](onNone IO[B], onSome io.Kleisli[A, B]) func(IOOption[A]) IO[B] {
|
||||
return optiont.MatchE(io.Chain[Option[A], B], function.Constant(onNone), onSome)
|
||||
}
|
||||
|
||||
// Defer creates an IO by creating a brand new IO via a generator function, each time
|
||||
@@ -191,28 +192,28 @@ func FromEither[E, A any](e Either[E, A]) IOOption[A] {
|
||||
}
|
||||
|
||||
// MonadAlt identifies an associative operation on a type constructor
|
||||
func MonadAlt[A any](first IOOption[A], second Lazy[IOOption[A]]) IOOption[A] {
|
||||
func MonadAlt[A any](first IOOption[A], second IOOption[A]) IOOption[A] {
|
||||
return optiont.MonadAlt(
|
||||
io.MonadOf[Option[A]],
|
||||
io.MonadChain[Option[A], Option[A]],
|
||||
|
||||
first,
|
||||
second,
|
||||
lazy.Of(second),
|
||||
)
|
||||
}
|
||||
|
||||
// Alt identifies an associative operation on a type constructor
|
||||
func Alt[A any](second Lazy[IOOption[A]]) func(IOOption[A]) IOOption[A] {
|
||||
func Alt[A any](second IOOption[A]) Operator[A, A] {
|
||||
return optiont.Alt(
|
||||
io.Of[Option[A]],
|
||||
io.Chain[Option[A], Option[A]],
|
||||
|
||||
second,
|
||||
lazy.Of(second),
|
||||
)
|
||||
}
|
||||
|
||||
// MonadChainFirst runs the monad returned by the function but returns the result of the original monad
|
||||
func MonadChainFirst[A, B any](ma IOOption[A], f func(A) IOOption[B]) IOOption[A] {
|
||||
func MonadChainFirst[A, B any](ma IOOption[A], f Kleisli[A, B]) IOOption[A] {
|
||||
return chain.MonadChainFirst(
|
||||
MonadChain[A, A],
|
||||
MonadMap[B, A],
|
||||
@@ -222,7 +223,7 @@ func MonadChainFirst[A, B any](ma IOOption[A], f func(A) IOOption[B]) IOOption[A
|
||||
}
|
||||
|
||||
// ChainFirst runs the monad returned by the function but returns the result of the original monad
|
||||
func ChainFirst[A, B any](f func(A) IOOption[B]) func(IOOption[A]) IOOption[A] {
|
||||
func ChainFirst[A, B any](f Kleisli[A, B]) Operator[A, A] {
|
||||
return chain.ChainFirst(
|
||||
Chain[A, A],
|
||||
Map[B, A],
|
||||
@@ -231,7 +232,7 @@ func ChainFirst[A, B any](f func(A) IOOption[B]) func(IOOption[A]) IOOption[A] {
|
||||
}
|
||||
|
||||
// MonadChainFirstIOK runs the monad returned by the function but returns the result of the original monad
|
||||
func MonadChainFirstIOK[A, B any](first IOOption[A], f func(A) IO[B]) IOOption[A] {
|
||||
func MonadChainFirstIOK[A, B any](first IOOption[A], f io.Kleisli[A, B]) IOOption[A] {
|
||||
return fromio.MonadChainFirstIOK(
|
||||
MonadChain[A, A],
|
||||
MonadMap[B, A],
|
||||
@@ -242,7 +243,7 @@ func MonadChainFirstIOK[A, B any](first IOOption[A], f func(A) IO[B]) IOOption[A
|
||||
}
|
||||
|
||||
// ChainFirstIOK runs the monad returned by the function but returns the result of the original monad
|
||||
func ChainFirstIOK[A, B any](f func(A) IO[B]) func(IOOption[A]) IOOption[A] {
|
||||
func ChainFirstIOK[A, B any](f io.Kleisli[A, B]) Operator[A, A] {
|
||||
return fromio.ChainFirstIOK(
|
||||
Chain[A, A],
|
||||
Map[B, A],
|
||||
@@ -252,11 +253,11 @@ func ChainFirstIOK[A, B any](f func(A) IO[B]) func(IOOption[A]) IOOption[A] {
|
||||
}
|
||||
|
||||
// Delay creates an operation that passes in the value after some delay
|
||||
func Delay[A any](delay time.Duration) func(IOOption[A]) IOOption[A] {
|
||||
func Delay[A any](delay time.Duration) Operator[A, A] {
|
||||
return io.Delay[Option[A]](delay)
|
||||
}
|
||||
|
||||
// After creates an operation that passes after the given [time.Time]
|
||||
func After[A any](timestamp time.Time) func(IOOption[A]) IOOption[A] {
|
||||
func After[A any](timestamp time.Time) Operator[A, A] {
|
||||
return io.After[Option[A]](timestamp)
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ import "github.com/IBM/fp-go/v2/function"
|
||||
|
||||
// WithResource constructs a function that creates a resource, then operates on it and then releases the resource
|
||||
func WithResource[
|
||||
R, A, ANY any](onCreate IOOption[R], onRelease func(R) IOOption[ANY]) Kleisli[Kleisli[R, A], A] {
|
||||
R, A, ANY any](onCreate IOOption[R], onRelease Kleisli[R, ANY]) Kleisli[Kleisli[R, A], A] {
|
||||
// simply map to implementation of bracket
|
||||
return function.Bind13of3(Bracket[R, A, ANY])(onCreate, function.Ignore2of2[Option[A]](onRelease))
|
||||
}
|
||||
|
||||
@@ -265,5 +265,3 @@
|
||||
// In practice, they are the same type, but the lazy package provides a more focused
|
||||
// API for pure computations.
|
||||
package lazy
|
||||
|
||||
// Made with Bob
|
||||
|
||||
@@ -501,5 +501,3 @@ func TestMapComposition(t *testing.T) {
|
||||
|
||||
assert.Equal(t, 20, result())
|
||||
}
|
||||
|
||||
// Made with Bob
|
||||
|
||||
@@ -278,7 +278,7 @@ func Local[A, R2, R1 any](f func(R2) R1) func(Reader[R1, A]) Reader[R2, A] {
|
||||
// getPort := reader.Asks(func(c Config) int { return c.Port })
|
||||
// run := reader.Read(Config{Port: 8080})
|
||||
// port := run(getPort) // 8080
|
||||
func Read[E, A any](e E) func(Reader[E, A]) A {
|
||||
func Read[A, E any](e E) func(Reader[E, A]) A {
|
||||
return I.Ap[A](e)
|
||||
}
|
||||
|
||||
|
||||
@@ -175,7 +175,7 @@ func TestLocal(t *testing.T) {
|
||||
func TestRead(t *testing.T) {
|
||||
config := Config{Port: 8080}
|
||||
getPort := Asks(func(c Config) int { return c.Port })
|
||||
run := Read[Config, int](config)
|
||||
run := Read[int](config)
|
||||
port := run(getPort)
|
||||
assert.Equal(t, 8080, port)
|
||||
}
|
||||
|
||||
@@ -153,7 +153,7 @@ func Local[E, A, R2, R1 any](f func(R2) R1) func(ReaderEither[R1, E, A]) ReaderE
|
||||
|
||||
// Read applies a context to a reader to obtain its value
|
||||
func Read[E1, A, E any](e E) func(ReaderEither[E, E1, A]) Either[E1, A] {
|
||||
return reader.Read[E, Either[E1, A]](e)
|
||||
return reader.Read[Either[E1, A]](e)
|
||||
}
|
||||
|
||||
func MonadFlap[L, E, A, B any](fab ReaderEither[L, E, func(A) B], a A) ReaderEither[L, E, B] {
|
||||
|
||||
@@ -750,3 +750,8 @@ func MapLeft[R, A, E1, E2 any](f func(E1) E2) func(ReaderIOEither[R, E1, A]) Rea
|
||||
func Local[E, A, R1, R2 any](f func(R2) R1) func(ReaderIOEither[R1, E, A]) ReaderIOEither[R2, E, A] {
|
||||
return reader.Local[IOEither[E, A]](f)
|
||||
}
|
||||
|
||||
//go:inline
|
||||
func Read[E, A, R any](r R) func(ReaderIOEither[R, E, A]) IOEither[E, A] {
|
||||
return reader.Read[IOEither[E, A]](r)
|
||||
}
|
||||
|
||||
@@ -56,5 +56,3 @@ func TestApS(t *testing.T) {
|
||||
|
||||
assert.Equal(t, res(context.Background())(), result.Of("John Doe"))
|
||||
}
|
||||
|
||||
// Made with Bob
|
||||
|
||||
@@ -677,3 +677,8 @@ func MapLeft[R, A, E any](f func(error) E) func(ReaderIOResult[R, A]) RIOE.Reade
|
||||
func Local[A, R1, R2 any](f func(R2) R1) func(ReaderIOResult[R1, A]) ReaderIOResult[R2, A] {
|
||||
return RIOE.Local[error, A](f)
|
||||
}
|
||||
|
||||
//go:inline
|
||||
func Read[A, R any](r R) func(ReaderIOResult[R, A]) IOResult[A] {
|
||||
return RIOE.Read[error, A](r)
|
||||
}
|
||||
|
||||
@@ -160,5 +160,3 @@ func TestUncurry3(t *testing.T) {
|
||||
assert.True(t, ok)
|
||||
assert.Equal(t, 42, result)
|
||||
}
|
||||
|
||||
// Made with Bob
|
||||
|
||||
@@ -110,5 +110,3 @@ func TestFrom3(t *testing.T) {
|
||||
result2 := roFunc("test", 5, false)(ctx1)
|
||||
assert.Equal(t, O.None[string](), result2)
|
||||
}
|
||||
|
||||
// Made with Bob
|
||||
|
||||
@@ -82,11 +82,11 @@ func FromPredicate[GEA ~func(E) O.Option[A], E, A any](pred func(A) bool) func(A
|
||||
}
|
||||
|
||||
func Fold[GEA ~func(E) O.Option[A], GB ~func(E) B, E, A, B any](onNone func() GB, onRight func(A) GB) func(GEA) GB {
|
||||
return optiont.MatchE(R.MonadChain[GEA, GB, E, O.Option[A], B], onNone, onRight)
|
||||
return optiont.MatchE(R.Chain[GEA, GB, E, O.Option[A], B], onNone, onRight)
|
||||
}
|
||||
|
||||
func GetOrElse[GEA ~func(E) O.Option[A], GA ~func(E) A, E, A any](onNone func() GA) func(GEA) GA {
|
||||
return optiont.GetOrElse(R.MonadChain[GEA, GA, E, O.Option[A], A], onNone, R.Of[GA, E, A])
|
||||
return optiont.GetOrElse(R.Chain[GEA, GA, E, O.Option[A], A], onNone, R.Of[GA, E, A])
|
||||
}
|
||||
|
||||
func Ask[GEE ~func(E) O.Option[E], E, L any]() GEE {
|
||||
|
||||
@@ -36,6 +36,8 @@ func FromOption[E, A any](e Option[A]) ReaderOption[E, A] {
|
||||
|
||||
// Some wraps a value in a ReaderOption, representing a successful computation.
|
||||
// This is equivalent to Of but more explicit about the Option semantics.
|
||||
//
|
||||
//go:inline
|
||||
func Some[E, A any](r A) ReaderOption[E, A] {
|
||||
return optiont.Of(reader.Of[E, Option[A]], r)
|
||||
}
|
||||
@@ -50,6 +52,8 @@ func FromReader[E, A any](r Reader[E, A]) ReaderOption[E, A] {
|
||||
|
||||
// SomeReader lifts a Reader[E, A] into a ReaderOption[E, A].
|
||||
// The resulting computation always succeeds (returns Some).
|
||||
//
|
||||
//go:inline
|
||||
func SomeReader[E, A any](r Reader[E, A]) ReaderOption[E, A] {
|
||||
return optiont.SomeF(reader.MonadMap[E, A, Option[A]], r)
|
||||
}
|
||||
@@ -61,6 +65,8 @@ func SomeReader[E, A any](r Reader[E, A]) ReaderOption[E, A] {
|
||||
//
|
||||
// ro := readeroption.Of[Config](42)
|
||||
// doubled := readeroption.MonadMap(ro, func(x int) int { return x * 2 })
|
||||
//
|
||||
//go:inline
|
||||
func MonadMap[E, A, B any](fa ReaderOption[E, A], f func(A) B) ReaderOption[E, B] {
|
||||
return readert.MonadMap[ReaderOption[E, A], ReaderOption[E, B]](O.MonadMap[A, B], fa, f)
|
||||
}
|
||||
@@ -74,6 +80,8 @@ func MonadMap[E, A, B any](fa ReaderOption[E, A], f func(A) B) ReaderOption[E, B
|
||||
// readeroption.Of[Config](42),
|
||||
// readeroption.Map[Config](func(x int) int { return x * 2 }),
|
||||
// )
|
||||
//
|
||||
//go:inline
|
||||
func Map[E, A, B any](f func(A) B) Operator[E, A, B] {
|
||||
return readert.Map[ReaderOption[E, A], ReaderOption[E, B]](O.Map[A, B], f)
|
||||
}
|
||||
@@ -86,6 +94,8 @@ func Map[E, A, B any](f func(A) B) Operator[E, A, B] {
|
||||
// findUser := func(id int) readeroption.ReaderOption[DB, User] { ... }
|
||||
// loadProfile := func(user User) readeroption.ReaderOption[DB, Profile] { ... }
|
||||
// result := readeroption.MonadChain(findUser(123), loadProfile)
|
||||
//
|
||||
//go:inline
|
||||
func MonadChain[E, A, B any](ma ReaderOption[E, A], f Kleisli[E, A, B]) ReaderOption[E, B] {
|
||||
return readert.MonadChain(O.MonadChain[A, B], ma, f)
|
||||
}
|
||||
@@ -99,6 +109,8 @@ func MonadChain[E, A, B any](ma ReaderOption[E, A], f Kleisli[E, A, B]) ReaderOp
|
||||
// findUser(123),
|
||||
// readeroption.Chain(loadProfile),
|
||||
// )
|
||||
//
|
||||
//go:inline
|
||||
func Chain[E, A, B any](f Kleisli[E, A, B]) Operator[E, A, B] {
|
||||
return readert.Chain[ReaderOption[E, A]](O.Chain[A, B], f)
|
||||
}
|
||||
@@ -110,6 +122,8 @@ func Chain[E, A, B any](f Kleisli[E, A, B]) Operator[E, A, B] {
|
||||
//
|
||||
// ro := readeroption.Of[Config](42)
|
||||
// result := ro(config) // Returns option.Some(42)
|
||||
//
|
||||
//go:inline
|
||||
func Of[E, A any](a A) ReaderOption[E, A] {
|
||||
return readert.MonadOf[ReaderOption[E, A]](O.Of[A], a)
|
||||
}
|
||||
@@ -121,6 +135,8 @@ func Of[E, A any](a A) ReaderOption[E, A] {
|
||||
//
|
||||
// ro := readeroption.None[Config, int]()
|
||||
// result := ro(config) // Returns option.None[int]()
|
||||
//
|
||||
//go:inline
|
||||
func None[E, A any]() ReaderOption[E, A] {
|
||||
return reader.Of[E](O.None[A]())
|
||||
}
|
||||
@@ -128,12 +144,16 @@ func None[E, A any]() ReaderOption[E, A] {
|
||||
// MonadAp applies a function wrapped in a ReaderOption to a value wrapped in a ReaderOption.
|
||||
// Both computations are executed with the same environment.
|
||||
// If either computation returns None, the result is None.
|
||||
//
|
||||
//go:inline
|
||||
func MonadAp[E, A, B any](fab ReaderOption[E, func(A) B], fa ReaderOption[E, A]) ReaderOption[E, B] {
|
||||
return readert.MonadAp[ReaderOption[E, A], ReaderOption[E, B], ReaderOption[E, func(A) B], E, A](O.MonadAp[B, A], fab, fa)
|
||||
}
|
||||
|
||||
// Ap returns a function that applies a function wrapped in a ReaderOption to a value.
|
||||
// This is the curried version of MonadAp.
|
||||
//
|
||||
//go:inline
|
||||
func Ap[B, E, A any](fa ReaderOption[E, A]) Operator[E, func(A) B, B] {
|
||||
return readert.Ap[ReaderOption[E, A], ReaderOption[E, B], ReaderOption[E, func(A) B], E, A](O.Ap[B, A], fa)
|
||||
}
|
||||
@@ -148,6 +168,8 @@ func Ap[B, E, A any](fa ReaderOption[E, A]) Operator[E, func(A) B, B] {
|
||||
// readeroption.Of[Config](42),
|
||||
// readeroption.Chain(isPositive),
|
||||
// )
|
||||
//
|
||||
//go:inline
|
||||
func FromPredicate[E, A any](pred func(A) bool) Kleisli[E, A, A] {
|
||||
return fromoption.FromPredicate(FromOption[E, A], pred)
|
||||
}
|
||||
@@ -162,8 +184,14 @@ func FromPredicate[E, A any](pred func(A) bool) Kleisli[E, A, A] {
|
||||
// func() reader.Reader[Config, string] { return reader.Of[Config]("not found") },
|
||||
// func(user User) reader.Reader[Config, string] { return reader.Of[Config](user.Name) },
|
||||
// )(findUser(123))
|
||||
func Fold[E, A, B any](onNone func() Reader[E, B], onRight func(A) Reader[E, B]) func(ReaderOption[E, A]) Reader[E, B] {
|
||||
return optiont.MatchE(reader.MonadChain[E, Option[A], B], onNone, onRight)
|
||||
//
|
||||
//go:inline
|
||||
func Fold[E, A, B any](onNone Reader[E, B], onRight func(A) Reader[E, B]) func(ReaderOption[E, A]) Reader[E, B] {
|
||||
return optiont.MatchE(reader.Chain[E, Option[A], B], function.Constant(onNone), onRight)
|
||||
}
|
||||
|
||||
func MonadFold[E, A, B any](fa ReaderOption[E, A], onNone Reader[E, B], onRight func(A) Reader[E, B]) Reader[E, B] {
|
||||
return optiont.MonadMatchE(fa, reader.MonadChain[E, Option[A], B], function.Constant(onNone), onRight)
|
||||
}
|
||||
|
||||
// GetOrElse returns the value from a ReaderOption, or a default value if it's None.
|
||||
@@ -173,8 +201,10 @@ func Fold[E, A, B any](onNone func() Reader[E, B], onRight func(A) Reader[E, B])
|
||||
// result := readeroption.GetOrElse(
|
||||
// func() reader.Reader[Config, User] { return reader.Of[Config](defaultUser) },
|
||||
// )(findUser(123))
|
||||
func GetOrElse[E, A any](onNone func() Reader[E, A]) func(ReaderOption[E, A]) Reader[E, A] {
|
||||
return optiont.GetOrElse(reader.MonadChain[E, Option[A], A], onNone, reader.Of[E, A])
|
||||
//
|
||||
//go:inline
|
||||
func GetOrElse[E, A any](onNone Reader[E, A]) func(ReaderOption[E, A]) Reader[E, A] {
|
||||
return optiont.GetOrElse(reader.Chain[E, Option[A], A], function.Constant(onNone), reader.Of[E, A])
|
||||
}
|
||||
|
||||
// Ask retrieves the current environment as a ReaderOption.
|
||||
@@ -184,6 +214,8 @@ func GetOrElse[E, A any](onNone func() Reader[E, A]) func(ReaderOption[E, A]) Re
|
||||
//
|
||||
// getConfig := readeroption.Ask[Config, any]()
|
||||
// result := getConfig(myConfig) // Returns option.Some(myConfig)
|
||||
//
|
||||
//go:inline
|
||||
func Ask[E, L any]() ReaderOption[E, E] {
|
||||
return fromreader.Ask(FromReader[E, E])()
|
||||
}
|
||||
@@ -195,6 +227,8 @@ func Ask[E, L any]() ReaderOption[E, E] {
|
||||
//
|
||||
// getTimeout := readeroption.Asks(func(cfg Config) int { return cfg.Timeout })
|
||||
// result := getTimeout(myConfig) // Returns option.Some(myConfig.Timeout)
|
||||
//
|
||||
//go:inline
|
||||
func Asks[E, A any](r Reader[E, A]) ReaderOption[E, A] {
|
||||
return fromreader.Asks(FromReader[E, A])(r)
|
||||
}
|
||||
@@ -209,6 +243,8 @@ func Asks[E, A any](r Reader[E, A]) ReaderOption[E, A] {
|
||||
// readeroption.Of[Config]("25"),
|
||||
// parseAge,
|
||||
// )
|
||||
//
|
||||
//go:inline
|
||||
func MonadChainOptionK[E, A, B any](ma ReaderOption[E, A], f func(A) Option[B]) ReaderOption[E, B] {
|
||||
return fromoption.MonadChainOptionK(
|
||||
MonadChain[E, A, B],
|
||||
@@ -228,6 +264,8 @@ func MonadChainOptionK[E, A, B any](ma ReaderOption[E, A], f func(A) Option[B])
|
||||
// readeroption.Of[Config]("25"),
|
||||
// readeroption.ChainOptionK[Config](parseAge),
|
||||
// )
|
||||
//
|
||||
//go:inline
|
||||
func ChainOptionK[E, A, B any](f func(A) Option[B]) Operator[E, A, B] {
|
||||
return fromoption.ChainOptionK(
|
||||
Chain[E, A, B],
|
||||
@@ -243,6 +281,8 @@ func ChainOptionK[E, A, B any](f func(A) Option[B]) Operator[E, A, B] {
|
||||
//
|
||||
// nested := readeroption.Of[Config](readeroption.Of[Config](42))
|
||||
// flattened := readeroption.Flatten(nested)
|
||||
//
|
||||
//go:inline
|
||||
func Flatten[E, A any](mma ReaderOption[E, ReaderOption[E, A]]) ReaderOption[E, A] {
|
||||
return MonadChain(mma, function.Identity[ReaderOption[E, A]])
|
||||
}
|
||||
@@ -264,6 +304,8 @@ func Flatten[E, A any](mma ReaderOption[E, ReaderOption[E, A]]) ReaderOption[E,
|
||||
// result := readeroption.Local(func(g GlobalConfig) DBConfig { return g.DB })(
|
||||
// readeroption.Asks(query),
|
||||
// )
|
||||
//
|
||||
//go:inline
|
||||
func Local[A, R2, R1 any](f func(R2) R1) func(ReaderOption[R1, A]) ReaderOption[R2, A] {
|
||||
return reader.Local[Option[A]](f)
|
||||
}
|
||||
@@ -275,18 +317,34 @@ func Local[A, R2, R1 any](f func(R2) R1) func(ReaderOption[R1, A]) ReaderOption[
|
||||
//
|
||||
// ro := readeroption.Of[Config](42)
|
||||
// result := readeroption.Read[int](myConfig)(ro) // Returns option.Some(42)
|
||||
//
|
||||
//go:inline
|
||||
func Read[A, E any](e E) func(ReaderOption[E, A]) Option[A] {
|
||||
return reader.Read[E, Option[A]](e)
|
||||
return reader.Read[Option[A]](e)
|
||||
}
|
||||
|
||||
// MonadFlap applies a value to a function wrapped in a ReaderOption.
|
||||
// This is the reverse of MonadAp.
|
||||
//
|
||||
//go:inline
|
||||
func MonadFlap[E, A, B any](fab ReaderOption[E, func(A) B], a A) ReaderOption[E, B] {
|
||||
return functor.MonadFlap(MonadMap[E, func(A) B, B], fab, a)
|
||||
}
|
||||
|
||||
// Flap returns a function that applies a value to a function wrapped in a ReaderOption.
|
||||
// This is the curried version of MonadFlap.
|
||||
//
|
||||
//go:inline
|
||||
func Flap[E, B, A any](a A) Operator[E, func(A) B, B] {
|
||||
return functor.Flap(Map[E, func(A) B, B], a)
|
||||
}
|
||||
|
||||
//go:inline
|
||||
func MonadAlt[E, A any](fa ReaderOption[E, A], that ReaderOption[E, A]) ReaderOption[E, A] {
|
||||
return MonadFold(fa, that, Of[E, A])
|
||||
}
|
||||
|
||||
//go:inline
|
||||
func Alt[E, A any](that ReaderOption[E, A]) Operator[E, A, A] {
|
||||
return Fold(that, Of[E, A])
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import (
|
||||
F "github.com/IBM/fp-go/v2/function"
|
||||
"github.com/IBM/fp-go/v2/internal/utils"
|
||||
O "github.com/IBM/fp-go/v2/option"
|
||||
"github.com/IBM/fp-go/v2/reader"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
@@ -135,15 +136,9 @@ func TestFromPredicate(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestFold(t *testing.T) {
|
||||
onNone := func() Reader[MyContext, string] {
|
||||
return func(ctx MyContext) string {
|
||||
return "none"
|
||||
}
|
||||
}
|
||||
onNone := reader.Of[MyContext]("none")
|
||||
onSome := func(x int) Reader[MyContext, string] {
|
||||
return func(ctx MyContext) string {
|
||||
return fmt.Sprintf("%d", x)
|
||||
}
|
||||
return reader.Of[MyContext](fmt.Sprintf("%d", x))
|
||||
}
|
||||
|
||||
// Test with Some
|
||||
@@ -156,11 +151,7 @@ func TestFold(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetOrElse(t *testing.T) {
|
||||
defaultValue := func() Reader[MyContext, int] {
|
||||
return func(ctx MyContext) int {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
defaultValue := reader.Of[MyContext](0)
|
||||
|
||||
// Test with Some
|
||||
g1 := GetOrElse(defaultValue)(Of[MyContext](42))
|
||||
|
||||
Reference in New Issue
Block a user