// Copyright (c) 2023 - 2025 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 readeroption provides a monad transformer that combines the Reader and Option monads. // // ReaderOption[R, A] represents a computation that: // - Depends on a shared environment of type R (Reader monad) // - May fail to produce a value of type A (Option monad) // // This is useful for computations that need access to configuration, context, or dependencies // while also being able to represent the absence of a value without using errors. // // The ReaderOption monad is defined as: Reader[R, Option[A]] // // Key operations: // - Of: Wraps a value in a ReaderOption // - None: Creates a ReaderOption representing no value // - Map: Transforms the value inside a ReaderOption // - Chain: Sequences ReaderOption computations // - Ask/Asks: Accesses the environment // // Example: // // type Config struct { // DatabaseURL string // Timeout int // } // // // A computation that may or may not find a user // func findUser(id int) readeroption.ReaderOption[Config, User] { // return readeroption.Asks(func(cfg Config) option.Option[User] { // // Use cfg.DatabaseURL to query database // // Return Some(user) if found, None() if not found // }) // } // // // Chain multiple operations // result := F.Pipe2( // findUser(123), // readeroption.Chain(func(user User) readeroption.ReaderOption[Config, Profile] { // return loadProfile(user.ProfileID) // }), // readeroption.Map(func(profile Profile) string { // return profile.DisplayName // }), // ) // // // Execute with config // config := Config{DatabaseURL: "localhost:5432", Timeout: 30} // displayName := result(config) // Returns Option[string] package readeroption import ( "github.com/IBM/fp-go/v2/lazy" "github.com/IBM/fp-go/v2/option" "github.com/IBM/fp-go/v2/reader" ) type ( // Lazy represents a deferred computation Lazy[A any] = lazy.Lazy[A] // Option represents an optional value Option[A any] = option.Option[A] // Reader represents a computation that depends on an environment R and produces a value A Reader[R, A any] = reader.Reader[R, A] // ReaderOption represents a computation that depends on an environment R and may produce a value A. // It combines the Reader monad (for dependency injection) with the Option monad (for optional values). ReaderOption[R, A any] = Reader[R, Option[A]] // Kleisli represents a function that takes a value A and returns a ReaderOption[R, B]. // This is the type of functions used with Chain/Bind operations. Kleisli[R, A, B any] = Reader[A, ReaderOption[R, B]] // Operator represents a function that transforms one ReaderOption into another. // This is commonly used for lifting functions into the ReaderOption context. Operator[R, A, B any] = Reader[ReaderOption[R, A], ReaderOption[R, B]] )