// Copyright (c) 2025 GeWuYou // 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. using System.Collections.Concurrent; using GFramework.Core.Functional; namespace GFramework.Core.functional.functions; /// /// 函数式编程扩展方法集合,提供柯里化、偏函数应用、重复执行、安全执行和缓存等功能 /// public static class FunctionExtensions { #region Repeat /// /// Repeat:对值重复应用函数 n 次 /// /// /// 当 times 小于 0 时抛出 /// public static T Repeat( this T value, int times, Func func) { ArgumentOutOfRangeException.ThrowIfNegative(times); var result = value; for (var i = 0; i < times; i++) result = func(result); return result; } #endregion #region Try → Result /// /// Try:安全执行并返回 language-ext 的 Result /// public static Result Try( this TSource value, Func func) { try { return new Result(func(value)); } catch (Exception ex) { return new Result(ex); } } #endregion #region Memoize (Unbounded / Unsafe) /// /// MemoizeUnbounded: /// 对函数结果进行无界缓存(线程安全) /// ⚠ 注意: /// - 缓存永不释放 /// - TSource 必须具有稳定的 Equals / GetHashCode /// - 仅适用于纯函数 /// public static Func MemoizeUnbounded( this Func func) where TSource : notnull { var cache = new ConcurrentDictionary(); return key => cache.GetOrAdd(key, func); } #endregion #region Partial (Advanced) /// /// Partial:部分应用(二参数函数固定第一个参数) /// ⚠ 偏函数应用属于高级用法,不建议在业务代码滥用 /// public static Func Partial( this Func func, T1 firstArg) { return second => func(firstArg, second); } #endregion #region Compose & AndThen /// /// Compose:函数组合,返回 f(g(x)) /// 数学表示:(f ∘ g)(x) = f(g(x)) /// /// 输入类型 /// 中间类型 /// 输出类型 /// 外层函数 /// 内层函数 /// 组合后的函数 /// 当 f 或 g 为 null 时抛出 /// /// /// Func<int, int> addOne = x => x + 1; /// Func<int, int> multiplyTwo = x => x * 2; /// var composed = multiplyTwo.Compose(addOne); // (x + 1) * 2 /// var result = composed(5); // (5 + 1) * 2 = 12 /// /// public static Func Compose( this Func f, Func g) { ArgumentNullException.ThrowIfNull(f); ArgumentNullException.ThrowIfNull(g); return x => f(g(x)); } /// /// AndThen:函数链式调用,返回 g(f(x)) /// 数学表示:(f >> g)(x) = g(f(x)) /// /// 输入类型 /// 中间类型 /// 输出类型 /// 第一个函数 /// 第二个函数 /// 链式调用后的函数 /// 当 f 或 g 为 null 时抛出 /// /// /// Func<int, int> addOne = x => x + 1; /// Func<int, int> multiplyTwo = x => x * 2; /// var chained = addOne.AndThen(multiplyTwo); // (x + 1) * 2 /// var result = chained(5); // (5 + 1) * 2 = 12 /// /// public static Func AndThen( this Func f, Func g) { ArgumentNullException.ThrowIfNull(f); ArgumentNullException.ThrowIfNull(g); return x => g(f(x)); } #endregion #region Curry & Uncurry /// /// Curry:将二参数函数柯里化为嵌套的单参数函数 /// /// 第一个参数类型 /// 第二个参数类型 /// 返回值类型 /// 要柯里化的函数 /// 柯里化后的函数 /// 当 func 为 null 时抛出 /// /// /// Func<int, int, int> add = (x, y) => x + y; /// var curriedAdd = add.Curry(); /// var add5 = curriedAdd(5); /// var result = add5(3); // 8 /// /// public static Func> Curry( this Func func) { ArgumentNullException.ThrowIfNull(func); return arg1 => arg2 => func(arg1, arg2); } /// /// Curry:将三参数函数柯里化为嵌套的单参数函数 /// /// 第一个参数类型 /// 第二个参数类型 /// 第三个参数类型 /// 返回值类型 /// 要柯里化的函数 /// 柯里化后的函数 /// 当 func 为 null 时抛出 /// /// /// Func<int, int, int, int> add3 = (x, y, z) => x + y + z; /// var curriedAdd = add3.Curry(); /// var result = curriedAdd(1)(2)(3); // 6 /// /// public static Func>> Curry( this Func func) { ArgumentNullException.ThrowIfNull(func); return arg1 => arg2 => arg3 => func(arg1, arg2, arg3); } /// /// Uncurry:将柯里化的函数还原为多参数函数 /// /// 第一个参数类型 /// 第二个参数类型 /// 返回值类型 /// 柯里化的函数 /// 还原后的多参数函数 /// 当 func 为 null 时抛出 /// /// /// Func<int, Func<int, int>> curriedAdd = x => y => x + y; /// var add = curriedAdd.Uncurry(); /// var result = add(5, 3); // 8 /// /// public static Func Uncurry( this Func> func) { ArgumentNullException.ThrowIfNull(func); return (arg1, arg2) => func(arg1)(arg2); } #endregion #region Defer & Once /// /// Defer:延迟执行函数,返回 Lazy<T> /// /// 返回值类型 /// 要延迟执行的函数 /// 包装了延迟执行的 Lazy 对象 /// 当 func 为 null 时抛出 /// /// /// var lazy = (() => ExpensiveComputation()).Defer(); /// // 此时尚未执行 /// var result = lazy.Value; // 首次访问时才执行 /// /// public static Lazy Defer(this Func func) { ArgumentNullException.ThrowIfNull(func); return new Lazy(func); } /// /// Once:确保函数只执行一次,后续调用返回缓存的结果(线程安全) /// /// 返回值类型 /// 要执行的函数 /// 包装后的函数,确保只执行一次 /// 当 func 为 null 时抛出 /// /// /// var counter = 0; /// var once = (() => ++counter).Once(); /// var result1 = once(); // 1 /// var result2 = once(); // 1 (不会再次执行) /// /// public static Func Once(this Func func) { ArgumentNullException.ThrowIfNull(func); var lazy = new Lazy(func, LazyThreadSafetyMode.ExecutionAndPublication); return () => lazy.Value; } #endregion }