// 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 tuple provides type-safe heterogeneous tuple data structures and operations. // // Tuples are immutable data structures that can hold a fixed number of values of different types. // Unlike arrays or slices which hold homogeneous data, tuples can contain values of different types // at compile-time known positions. // // # Tuple Types // // The package provides tuple types from Tuple1 to Tuple15, where the number indicates how many // elements the tuple contains. Each tuple type is generic over its element types: // // Tuple1[T1] // Single element // Tuple2[T1, T2] // Pair // Tuple3[T1, T2, T3] // Triple // // ... up to Tuple15 // // # Creating Tuples // // Tuples can be created using the MakeTupleN functions: // // t2 := tuple.MakeTuple2("hello", 42) // Tuple2[string, int] // t3 := tuple.MakeTuple3(1.5, true, "world") // Tuple3[float64, bool, string] // // For single-element tuples, you can also use the Of function: // // t1 := tuple.Of(42) // Equivalent to MakeTuple1(42) // // # Accessing Elements // // Tuple elements are accessed via their F1, F2, F3, ... fields: // // t := tuple.MakeTuple2("hello", 42) // s := t.F1 // "hello" // n := t.F2 // 42 // // For Tuple2, convenience accessors are provided: // // s := tuple.First(t) // Same as t.F1 // n := tuple.Second(t) // Same as t.F2 // // # Transforming Tuples // // The package provides several transformation functions: // // Map functions transform each element independently: // // t := tuple.MakeTuple2(5, "hello") // mapper := tuple.Map2( // func(n int) string { return fmt.Sprintf("%d", n) }, // func(s string) int { return len(s) }, // ) // result := mapper(t) // Tuple2[string, int]{"5", 5} // // BiMap transforms both elements of a Tuple2: // // mapper := tuple.BiMap( // func(s string) int { return len(s) }, // func(n int) string { return fmt.Sprintf("%d", n*2) }, // ) // // Swap exchanges the elements of a Tuple2: // // t := tuple.MakeTuple2("hello", 42) // swapped := tuple.Swap(t) // Tuple2[int, string]{42, "hello"} // // # Function Conversion // // Tupled and Untupled functions convert between regular multi-parameter functions // and functions that take/return tuples: // // // Regular function // add := func(a, b int) int { return a + b } // // // Convert to tuple-taking function // tupledAdd := tuple.Tupled2(add) // result := tupledAdd(tuple.MakeTuple2(3, 4)) // 7 // // // Convert back // untupledAdd := tuple.Untupled2(tupledAdd) // result = untupledAdd(3, 4) // 7 // // # Array Conversion // // Tuples can be converted to and from arrays using transformation functions: // // t := tuple.MakeTuple3(1, 2, 3) // toArray := tuple.ToArray3( // func(n int) int { return n }, // func(n int) int { return n }, // func(n int) int { return n }, // ) // arr := toArray(t) // []int{1, 2, 3} // // # Algebraic Operations // // The package supports algebraic structures: // // Monoid operations for combining tuples: // // import "github.com/IBM/fp-go/v2/monoid" // import "github.com/IBM/fp-go/v2/string" // // m := tuple.Monoid2(string.Monoid, monoid.MonoidSum[int]()) // t1 := tuple.MakeTuple2("hello", 5) // t2 := tuple.MakeTuple2(" world", 3) // result := m.Concat(t1, t2) // Tuple2[string, int]{"hello world", 8} // // Ord operations for comparing tuples: // // import "github.com/IBM/fp-go/v2/ord" // // o := tuple.Ord2(ord.FromStrictCompare[string](), ord.FromStrictCompare[int]()) // t1 := tuple.MakeTuple2("a", 1) // t2 := tuple.MakeTuple2("b", 2) // cmp := o.Compare(t1, t2) // -1 (t1 < t2) // // # JSON Serialization // // Tuples support JSON marshaling and unmarshaling as arrays: // // t := tuple.MakeTuple2("hello", 42) // data, _ := json.Marshal(t) // ["hello", 42] // // var t2 tuple.Tuple2[string, int] // json.Unmarshal(data, &t2) // Reconstructs the tuple // // # Building Tuples Incrementally // // The Push functions allow building larger tuples from smaller ones: // // t1 := tuple.MakeTuple1(42) // push := tuple.Push1[int, string]("hello") // t2 := push(t1) // Tuple2[int, string]{42, "hello"} // // # Replication // // Create tuples with all elements set to the same value: // // t := tuple.Replicate3(42) // Tuple3[int, int, int]{42, 42, 42} // // # Use Cases // // Tuples are useful when you need to: // - Return multiple values from a function in a type-safe way // - Group related but differently-typed values together // - Work with fixed-size heterogeneous collections // - Implement functional programming patterns like bifunctors // - Avoid defining custom struct types for simple data groupings // // For homogeneous collections of unknown or variable size, consider using // arrays or slices instead. package tuple //go:generate go run .. tuple --count 15 --filename gen.go