// 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;
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
}