// 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.
namespace GFramework.Core.functional.pipe;
///
/// 提供函数式编程中的管道和组合操作扩展方法
///
public static class PipeExtensions
{
///
/// Pipe:把值送进函数(value.Pipe(func))
///
/// 输入值的类型
/// 函数返回结果的类型
/// 要传递给函数的输入值
/// 接收输入值并返回结果的函数
/// 函数执行后的结果
public static TResult Pipe(
this TSource value,
Func func)
=> func(value);
///
/// Compose:函数组合(f1.Then(f2))
///
/// 第一个函数的输入类型
/// 第一个函数的输出类型,也是第二个函数的输入类型
/// 第二个函数的输出类型
/// 第一个要执行的函数
/// 第二个要执行的函数
/// 组合后的新函数,先执行first再执行second
public static Func Then(
this Func first,
Func second)
=> x => second(first(x));
///
/// Compose:反向组合(f2.After(f1))
///
/// 第一个函数的输入类型
/// 第一个函数的输出类型,也是第二个函数的输入类型
/// 第二个函数的输出类型
/// 第二个要执行的函数
/// 第一个要执行的函数
/// 组合后的新函数,先执行first再执行second
public static Func After(
this Func second,
Func first)
=> x => second(first(x));
///
/// Tap:执行副作用操作但返回原值(用于调试、日志等)
///
/// 输入值的类型
/// 要执行操作的输入值
/// 要执行的副作用操作
/// 原始输入值
public static TSource Tap(
this TSource value,
Action action)
{
action(value);
return value;
}
///
/// Map:对集合中的每个元素应用函数
///
/// 源集合元素的类型
/// 映射后集合元素的类型
/// 要映射的源集合
/// 用于转换元素的函数
/// 映射后的元素序列
public static IEnumerable Map(
this IEnumerable source,
Func selector)
=> source.Select(selector);
///
/// Filter:过滤集合
///
/// 集合元素的类型
/// 要过滤的源集合
/// 用于确定是否包含元素的条件函数
/// 满足条件的元素序列
public static IEnumerable Filter(
this IEnumerable source,
Func predicate)
=> source.Where(predicate);
///
/// Reduce:将集合归约为单个值
///
/// 集合元素的类型
/// 归约结果的类型
/// 要归约的源集合
/// 初始累加值
/// 累加器函数
/// 归约后的最终值
public static TResult Reduce(
this IEnumerable source,
TResult seed,
Func accumulator)
=> source.Aggregate(seed, accumulator);
///
/// Apply:将函数应用于值(柯里化辅助)
///
/// 输入值的类型
/// 函数返回结果的类型
/// 要应用的函数
/// 要传递给函数的输入值
/// 函数执行后的结果
public static TResult Apply(
this Func func,
TSource value)
=> func(value);
///
/// Curry:将二参数函数转换为柯里化形式
///
/// 第一个参数的类型
/// 第二个参数的类型
/// 函数返回结果的类型
/// 要柯里化的二参数函数
/// 柯里化后的函数,接受一个参数并返回另一个函数
public static Func> Curry(
this Func func)
=> x => y => func(x, y);
///
/// Uncurry:将柯里化函数转换回二参数函数
///
/// 第一个参数的类型
/// 第二个参数的类型
/// 函数返回结果的类型
/// 要取消柯里化的函数
/// 恢复为二参数的函数
public static Func Uncurry(
this Func> func)
=> (x, y) => func(x)(y);
///
/// Partial:部分应用函数(固定第一个参数)
///
/// 第一个参数的类型
/// 第二个参数的类型
/// 函数返回结果的类型
/// 要部分应用的二参数函数
/// 要固定的第一个参数值
/// 部分应用后的函数,只接受第二个参数
public static Func Partial(
this Func func,
T1 firstArg)
=> x => func(firstArg, x);
///
/// Match:模式匹配(类似switch表达式)
///
/// 输入值的类型
/// 匹配结果的类型
/// 要进行模式匹配的输入值
/// 匹配案例数组,每个包含谓词和处理器
/// 匹配到的处理结果
/// 当没有匹配的案例时抛出
public static TResult Match(
this TSource value,
params (Func predicate, Func handler)[] cases)
{
foreach (var (predicate, handler) in cases)
{
if (predicate(value))
return handler(value);
}
throw new InvalidOperationException("No matching case found");
}
///
/// MatchOrDefault:带默认值的模式匹配
///
/// 输入值的类型
/// 匹配结果的类型
/// 要进行模式匹配的输入值
/// 当没有匹配案例时的默认返回值
/// 匹配案例数组,每个包含谓词和处理器
/// 匹配到的处理结果或默认值
public static TResult MatchOrDefault(
this TSource value,
TResult defaultValue,
params (Func predicate, Func handler)[] cases)
{
foreach (var (predicate, handler) in cases)
{
if (predicate(value))
return handler(value);
}
return defaultValue;
}
///
/// If:条件执行
///
/// 输入值的类型
/// 要进行条件判断的输入值
/// 条件判断函数
/// 条件为真时执行的转换函数
/// 条件为真时返回转换后的值,否则返回原值
public static TSource If(
this TSource value,
Func predicate,
Func thenFunc)
=> predicate(value) ? thenFunc(value) : value;
///
/// IfElse:条件分支
///
/// 输入值的类型
/// 要进行条件判断的输入值
/// 条件判断函数
/// 条件为真时执行的转换函数
/// 条件为假时执行的转换函数
/// 根据条件返回相应的转换结果
public static TSource IfElse(
this TSource value,
Func predicate,
Func thenFunc,
Func elseFunc)
=> predicate(value) ? thenFunc(value) : elseFunc(value);
///
/// As:类型转换(安全转换)
///
/// 源类型的泛型参数
/// 目标类型的泛型参数
/// 要进行类型转换的值
/// 转换后的值,如果转换失败则返回null
public static TResult? As(
this TSource value)
where TResult : class
=> value as TResult;
///
/// Cast:强制类型转换
///
/// 目标类型的泛型参数
/// 要进行类型转换的对象
/// 强制转换后的值
public static TResult Cast(
this object value)
=> (TResult)value;
///
/// Also:执行操作并返回原值
///
/// 输入值的类型
/// 要执行操作的输入值
/// 要执行的操作
/// 原始输入值
public static TSource Also(
this TSource value,
Action action)
{
action(value);
return value;
}
///
/// Let:将值转换为另一个值
///
/// 输入值的类型
/// 转换结果的类型
/// 要进行转换的输入值
/// 用于转换值的函数
/// 转换后的结果
public static TResult Let(
this TSource value,
Func transform)
=> transform(value);
///
/// TakeIf:条件返回值或null
///
/// 输入值的类型
/// 要进行条件判断的输入值
/// 条件判断函数
/// 条件为真时返回原值,否则返回null
public static TSource? TakeIf(
this TSource value,
Func predicate)
where TSource : class
=> predicate(value) ? value : null;
///
/// TakeUnless:条件相反的TakeIf
///
/// 输入值的类型
/// 要进行条件判断的输入值
/// 条件判断函数
/// 条件为假时返回原值,否则返回null
public static TSource? TakeUnless(
this TSource value,
Func predicate)
where TSource : class
=> !predicate(value) ? value : null;
///
/// Repeat:重复执行函数n次
///
/// 输入值的类型
/// 初始输入值
/// 重复执行的次数
/// 要重复执行的函数
/// 经过多次变换后的最终值
public static TSource Repeat(
this TSource value,
int times,
Func func)
{
var result = value;
for (int i = 0; i < times; i++)
{
result = func(result);
}
return result;
}
///
/// Try:安全执行,捕获异常
///
/// 输入值的类型
/// 函数返回结果的类型
/// 要传递给函数的输入值
/// 要安全执行的函数
/// 包含执行状态、结果和错误信息的元组
public static (bool success, TResult? result, Exception? error) Try(
this TSource value,
Func func)
{
try
{
return (true, func(value), null);
}
catch (Exception ex)
{
return (false, default, ex);
}
}
///
/// Memoize:缓存函数结果
///
/// 函数输入参数的类型
/// 函数返回结果的类型
/// 要缓存结果的函数
/// 带有缓存功能的包装函数
public static Func Memoize(
this Func func)
where TSource : notnull
{
var cache = new Dictionary();
return x =>
{
if (cache.TryGetValue(x, out var result))
return result;
result = func(x);
cache[x] = result;
return result;
};
}
}