// 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 import ( G "github.com/IBM/fp-go/v2/readeroption/generic" ) // TraverseArray transforms an array by applying a function that returns a ReaderOption to each element. // If any element results in None, the entire result is None. // Otherwise, returns Some containing an array of all the unwrapped values. // // This is useful for performing a sequence of operations that may fail on each element of an array, // where you want all operations to succeed or the entire computation to fail. // // Example: // // type DB struct { ... } // // findUser := func(id int) readeroption.ReaderOption[DB, User] { ... } // // userIDs := []int{1, 2, 3} // result := F.Pipe1( // readeroption.Of[DB](userIDs), // readeroption.Chain(readeroption.TraverseArray[DB](findUser)), // ) // // result will be Some([]User) if all users are found, None otherwise func TraverseArray[E, A, B any](f func(A) ReaderOption[E, B]) Kleisli[E, []A, []B] { return G.TraverseArray[ReaderOption[E, B], ReaderOption[E, []B], []A](f) } // TraverseArrayWithIndex is like TraverseArray but the function also receives the index of each element. // // Example: // // type DB struct { ... } // // processWithIndex := func(idx int, value string) readeroption.ReaderOption[DB, Result] { // // Use idx in processing // return readeroption.Asks(func(db DB) option.Option[Result] { ... }) // } // // values := []string{"a", "b", "c"} // result := readeroption.TraverseArrayWithIndex[DB](processWithIndex)(values) func TraverseArrayWithIndex[E, A, B any](f func(int, A) ReaderOption[E, B]) func([]A) ReaderOption[E, []B] { return G.TraverseArrayWithIndex[ReaderOption[E, B], ReaderOption[E, []B], []A](f) } // SequenceArray converts an array of ReaderOption values into a ReaderOption of an array. // If any element is None, the entire result is None. // Otherwise, returns Some containing an array of all the unwrapped values. // // This is useful when you have multiple independent ReaderOption computations and want to // combine their results into a single array. // // Example: // // type Config struct { ... } // // user1 := readeroption.Of[Config](User{ID: 1, Name: "Alice"}) // user2 := readeroption.Of[Config](User{ID: 2, Name: "Bob"}) // user3 := readeroption.None[Config, User]() // // result := readeroption.SequenceArray([]readeroption.ReaderOption[Config, User]{ // user1, user2, user3, // }) // // result(config) will be option.None[[]User]() because user3 is None // // result2 := readeroption.SequenceArray([]readeroption.ReaderOption[Config, User]{ // user1, user2, // }) // // result2(config) will be option.Some([]User{{ID: 1, Name: "Alice"}, {ID: 2, Name: "Bob"}}) func SequenceArray[E, A any](ma []ReaderOption[E, A]) ReaderOption[E, []A] { return G.SequenceArray[ReaderOption[E, A], ReaderOption[E, []A]](ma) }