diff --git a/Funcky.SourceGenerator/ApplyGenerator.cs b/Funcky.SourceGenerator/ApplyGenerator.cs new file mode 100644 index 00000000..eaced7c4 --- /dev/null +++ b/Funcky.SourceGenerator/ApplyGenerator.cs @@ -0,0 +1,101 @@ +using System.Collections.Immutable; +using Funcky.Extensions; +using Microsoft.CodeAnalysis; + +namespace Funcky.SourceGenerator; + +[Generator(LanguageNames.CSharp)] +public sealed class ApplyGenerator : IIncrementalGenerator +{ + private const int MaxParameterCount = 4; + private const string ResultTypeParameter = "TResult"; + + public void Initialize(IncrementalGeneratorInitializationContext context) + { + context.RegisterPostInitializationOutput(static context => context.AddSource("FuncExtensions.Apply.g.cs", GenerateApplyExtensions())); + context.RegisterPostInitializationOutput(static context => context.AddSource("Functional.Apply.g.cs", GenerateApplyFunctions())); + } + + private static string GenerateApplyExtensions() + => $$""" + #nullable enable + + namespace Funcky.Extensions; + + public static partial class FuncExtensions + { + {{string.Join("\n\n ", GenerateApplyMethods(extensionMethod: true))}} + } + """; + + private static string GenerateApplyFunctions() + => $$""" + #nullable enable + + namespace Funcky; + + public static partial class Functional + { + {{string.Join("\n\n ", GenerateApplyMethods(extensionMethod: false))}} + } + """; + + private static IEnumerable GenerateApplyMethods(bool extensionMethod) + => (from parameterCount in Enumerable.Range(2, count: MaxParameterCount) + from unitParameters in Enumerable.Range(0, count: parameterCount).PowerSet() + let unitParameters_ = unitParameters.ToImmutableArray() + where unitParameters_.Length != 0 && unitParameters_.Length != parameterCount + select GenerateApplyMethod(parameterCount, unitParameters_, extensionMethod)); + + private static string GenerateApplyMethod(int parameterCount, ImmutableArray unitParameters, bool extensionMethod) + { + var returnType = ReturnType(unitParameters); + var typeParameters = string.Join(", ", TypeParameters(parameterCount)); + var @this = extensionMethod ? "this " : string.Empty; + var funcType = FuncType(TypeParameters(parameterCount)); + var parameters = string.Join(", ", Parameters(parameterCount, unitParameters)); + var lambdaParameters = string.Join(", ", LambdaParameters(unitParameters)); + var arguments = string.Join(", ", Arguments(parameterCount, unitParameters)); + return $"public static {returnType} Apply<{typeParameters}>({@this}{funcType} func, {parameters}) => ({lambdaParameters}) => func({arguments});"; + } + + private static IEnumerable TypeParameters(int parameterCount) + => Enumerable.Range(0, count: parameterCount) + .Select(TypeParameter) + .Concat([ResultTypeParameter]); + + private static string ReturnType(ImmutableArray unitParameters) + => FuncType(unitParameters + .Select(TypeParameter) + .Concat([ResultTypeParameter])); + + private static string FuncType(IEnumerable typeParameters) => $"Func<{string.Join(", ", typeParameters)}>"; + + private static string TypeParameter(int index) => $"T{index + 1}"; + + private static IEnumerable Parameters(int count, ImmutableArray unitParameters) + => Enumerable.Range(0, count).Select(index => Parameter(index, unitParameters)); + + private static string Parameter(int index, ImmutableArray unitParameters) + => $"{ParameterType(index, unitParameters)} {ParameterName(index)}"; + + private static string ParameterName(int index) => $"p{index + 1}"; + + private static string ParameterType(int index, ImmutableArray unitParameters) + => unitParameters.Contains(index) + ? "Unit" + : TypeParameter(index); + + private static IEnumerable LambdaParameters(ImmutableArray unitParameters) + => unitParameters.Select(LambdaParameterName); + + private static string LambdaParameterName(int index) => $"p{index + 1}_"; + + private static IEnumerable Arguments(int count, ImmutableArray unitParameters) + => Enumerable.Range(0, count).Select(index => Argument(index, unitParameters)); + + private static string Argument(int index, ImmutableArray unitParameters) + => unitParameters.Contains(index) + ? LambdaParameterName(index) + : ParameterName(index); +} diff --git a/Funcky.SourceGenerator/Funcky.SourceGenerator.csproj b/Funcky.SourceGenerator/Funcky.SourceGenerator.csproj index 0963508f..8f6acfcb 100644 --- a/Funcky.SourceGenerator/Funcky.SourceGenerator.csproj +++ b/Funcky.SourceGenerator/Funcky.SourceGenerator.csproj @@ -14,4 +14,7 @@ + + + diff --git a/Funcky.Test/FunctionalClass/ApplyTest.cs b/Funcky.Test/FunctionalClass/ApplyTest.cs new file mode 100644 index 00000000..da38a0a6 --- /dev/null +++ b/Funcky.Test/FunctionalClass/ApplyTest.cs @@ -0,0 +1,21 @@ +using static Funcky.Discard; + +namespace Funcky.Test.FunctionalClass; + +public class ApplyTest +{ + [Fact] + public void CanApplyParametersInAnyOrder() + { + var func = Linear0; + var f1 = Fn(Linear0).Apply(__, __, 10); + var f2 = func.Apply(2, __, 7); + var f3 = Apply(Fn(Linear0), 42, __, __); + Assert.Equal(Linear0(10, 2, 10), f1(10, 2)); + Assert.Equal(Linear0(2, 10, 7), f2(10)); + Assert.Equal(Linear0(42, 10, 2), f3(10, 2)); + } + + private static int Linear0(int a, int b, int c) + => a + (b * c); +} diff --git a/Funcky/PublicAPI.Unshipped.txt b/Funcky/PublicAPI.Unshipped.txt index b9b4d823..45bdf2f4 100644 --- a/Funcky/PublicAPI.Unshipped.txt +++ b/Funcky/PublicAPI.Unshipped.txt @@ -1,8 +1,112 @@ #nullable enable Funcky.Extensions.JsonSerializerOptionsExtensions Funcky.Extensions.OrderedDictionaryExtensions +static Funcky.Extensions.FuncExtensions.Apply(this System.Func! func, Funcky.Unit p1, Funcky.Unit p2, Funcky.Unit p3, Funcky.Unit p4, T5 p5) -> System.Func! +static Funcky.Extensions.FuncExtensions.Apply(this System.Func! func, Funcky.Unit p1, Funcky.Unit p2, Funcky.Unit p3, T4 p4, Funcky.Unit p5) -> System.Func! +static Funcky.Extensions.FuncExtensions.Apply(this System.Func! func, Funcky.Unit p1, Funcky.Unit p2, Funcky.Unit p3, T4 p4, T5 p5) -> System.Func! +static Funcky.Extensions.FuncExtensions.Apply(this System.Func! func, Funcky.Unit p1, Funcky.Unit p2, T3 p3, Funcky.Unit p4, Funcky.Unit p5) -> System.Func! +static Funcky.Extensions.FuncExtensions.Apply(this System.Func! func, Funcky.Unit p1, Funcky.Unit p2, T3 p3, Funcky.Unit p4, T5 p5) -> System.Func! +static Funcky.Extensions.FuncExtensions.Apply(this System.Func! func, Funcky.Unit p1, Funcky.Unit p2, T3 p3, T4 p4, Funcky.Unit p5) -> System.Func! +static Funcky.Extensions.FuncExtensions.Apply(this System.Func! func, Funcky.Unit p1, Funcky.Unit p2, T3 p3, T4 p4, T5 p5) -> System.Func! +static Funcky.Extensions.FuncExtensions.Apply(this System.Func! func, Funcky.Unit p1, T2 p2, Funcky.Unit p3, Funcky.Unit p4, Funcky.Unit p5) -> System.Func! +static Funcky.Extensions.FuncExtensions.Apply(this System.Func! func, Funcky.Unit p1, T2 p2, Funcky.Unit p3, Funcky.Unit p4, T5 p5) -> System.Func! +static Funcky.Extensions.FuncExtensions.Apply(this System.Func! func, Funcky.Unit p1, T2 p2, Funcky.Unit p3, T4 p4, Funcky.Unit p5) -> System.Func! +static Funcky.Extensions.FuncExtensions.Apply(this System.Func! func, Funcky.Unit p1, T2 p2, Funcky.Unit p3, T4 p4, T5 p5) -> System.Func! +static Funcky.Extensions.FuncExtensions.Apply(this System.Func! func, Funcky.Unit p1, T2 p2, T3 p3, Funcky.Unit p4, Funcky.Unit p5) -> System.Func! +static Funcky.Extensions.FuncExtensions.Apply(this System.Func! func, Funcky.Unit p1, T2 p2, T3 p3, Funcky.Unit p4, T5 p5) -> System.Func! +static Funcky.Extensions.FuncExtensions.Apply(this System.Func! func, Funcky.Unit p1, T2 p2, T3 p3, T4 p4, Funcky.Unit p5) -> System.Func! +static Funcky.Extensions.FuncExtensions.Apply(this System.Func! func, Funcky.Unit p1, T2 p2, T3 p3, T4 p4, T5 p5) -> System.Func! +static Funcky.Extensions.FuncExtensions.Apply(this System.Func! func, T1 p1, Funcky.Unit p2, Funcky.Unit p3, Funcky.Unit p4, Funcky.Unit p5) -> System.Func! +static Funcky.Extensions.FuncExtensions.Apply(this System.Func! func, T1 p1, Funcky.Unit p2, Funcky.Unit p3, Funcky.Unit p4, T5 p5) -> System.Func! +static Funcky.Extensions.FuncExtensions.Apply(this System.Func! func, T1 p1, Funcky.Unit p2, Funcky.Unit p3, T4 p4, Funcky.Unit p5) -> System.Func! +static Funcky.Extensions.FuncExtensions.Apply(this System.Func! func, T1 p1, Funcky.Unit p2, Funcky.Unit p3, T4 p4, T5 p5) -> System.Func! +static Funcky.Extensions.FuncExtensions.Apply(this System.Func! func, T1 p1, Funcky.Unit p2, T3 p3, Funcky.Unit p4, Funcky.Unit p5) -> System.Func! +static Funcky.Extensions.FuncExtensions.Apply(this System.Func! func, T1 p1, Funcky.Unit p2, T3 p3, Funcky.Unit p4, T5 p5) -> System.Func! +static Funcky.Extensions.FuncExtensions.Apply(this System.Func! func, T1 p1, Funcky.Unit p2, T3 p3, T4 p4, Funcky.Unit p5) -> System.Func! +static Funcky.Extensions.FuncExtensions.Apply(this System.Func! func, T1 p1, Funcky.Unit p2, T3 p3, T4 p4, T5 p5) -> System.Func! +static Funcky.Extensions.FuncExtensions.Apply(this System.Func! func, T1 p1, T2 p2, Funcky.Unit p3, Funcky.Unit p4, Funcky.Unit p5) -> System.Func! +static Funcky.Extensions.FuncExtensions.Apply(this System.Func! func, T1 p1, T2 p2, Funcky.Unit p3, Funcky.Unit p4, T5 p5) -> System.Func! +static Funcky.Extensions.FuncExtensions.Apply(this System.Func! func, T1 p1, T2 p2, Funcky.Unit p3, T4 p4, Funcky.Unit p5) -> System.Func! +static Funcky.Extensions.FuncExtensions.Apply(this System.Func! func, T1 p1, T2 p2, Funcky.Unit p3, T4 p4, T5 p5) -> System.Func! +static Funcky.Extensions.FuncExtensions.Apply(this System.Func! func, T1 p1, T2 p2, T3 p3, Funcky.Unit p4, Funcky.Unit p5) -> System.Func! +static Funcky.Extensions.FuncExtensions.Apply(this System.Func! func, T1 p1, T2 p2, T3 p3, Funcky.Unit p4, T5 p5) -> System.Func! +static Funcky.Extensions.FuncExtensions.Apply(this System.Func! func, T1 p1, T2 p2, T3 p3, T4 p4, Funcky.Unit p5) -> System.Func! +static Funcky.Extensions.FuncExtensions.Apply(this System.Func! func, Funcky.Unit p1, Funcky.Unit p2, Funcky.Unit p3, T4 p4) -> System.Func! +static Funcky.Extensions.FuncExtensions.Apply(this System.Func! func, Funcky.Unit p1, Funcky.Unit p2, T3 p3, Funcky.Unit p4) -> System.Func! +static Funcky.Extensions.FuncExtensions.Apply(this System.Func! func, Funcky.Unit p1, Funcky.Unit p2, T3 p3, T4 p4) -> System.Func! +static Funcky.Extensions.FuncExtensions.Apply(this System.Func! func, Funcky.Unit p1, T2 p2, Funcky.Unit p3, Funcky.Unit p4) -> System.Func! +static Funcky.Extensions.FuncExtensions.Apply(this System.Func! func, Funcky.Unit p1, T2 p2, Funcky.Unit p3, T4 p4) -> System.Func! +static Funcky.Extensions.FuncExtensions.Apply(this System.Func! func, Funcky.Unit p1, T2 p2, T3 p3, Funcky.Unit p4) -> System.Func! +static Funcky.Extensions.FuncExtensions.Apply(this System.Func! func, Funcky.Unit p1, T2 p2, T3 p3, T4 p4) -> System.Func! +static Funcky.Extensions.FuncExtensions.Apply(this System.Func! func, T1 p1, Funcky.Unit p2, Funcky.Unit p3, Funcky.Unit p4) -> System.Func! +static Funcky.Extensions.FuncExtensions.Apply(this System.Func! func, T1 p1, Funcky.Unit p2, Funcky.Unit p3, T4 p4) -> System.Func! +static Funcky.Extensions.FuncExtensions.Apply(this System.Func! func, T1 p1, Funcky.Unit p2, T3 p3, Funcky.Unit p4) -> System.Func! +static Funcky.Extensions.FuncExtensions.Apply(this System.Func! func, T1 p1, Funcky.Unit p2, T3 p3, T4 p4) -> System.Func! +static Funcky.Extensions.FuncExtensions.Apply(this System.Func! func, T1 p1, T2 p2, Funcky.Unit p3, Funcky.Unit p4) -> System.Func! +static Funcky.Extensions.FuncExtensions.Apply(this System.Func! func, T1 p1, T2 p2, Funcky.Unit p3, T4 p4) -> System.Func! +static Funcky.Extensions.FuncExtensions.Apply(this System.Func! func, T1 p1, T2 p2, T3 p3, Funcky.Unit p4) -> System.Func! +static Funcky.Extensions.FuncExtensions.Apply(this System.Func! func, Funcky.Unit p1, Funcky.Unit p2, T3 p3) -> System.Func! +static Funcky.Extensions.FuncExtensions.Apply(this System.Func! func, Funcky.Unit p1, T2 p2, Funcky.Unit p3) -> System.Func! +static Funcky.Extensions.FuncExtensions.Apply(this System.Func! func, Funcky.Unit p1, T2 p2, T3 p3) -> System.Func! +static Funcky.Extensions.FuncExtensions.Apply(this System.Func! func, T1 p1, Funcky.Unit p2, Funcky.Unit p3) -> System.Func! +static Funcky.Extensions.FuncExtensions.Apply(this System.Func! func, T1 p1, Funcky.Unit p2, T3 p3) -> System.Func! +static Funcky.Extensions.FuncExtensions.Apply(this System.Func! func, T1 p1, T2 p2, Funcky.Unit p3) -> System.Func! +static Funcky.Extensions.FuncExtensions.Apply(this System.Func! func, Funcky.Unit p1, T2 p2) -> System.Func! +static Funcky.Extensions.FuncExtensions.Apply(this System.Func! func, T1 p1, Funcky.Unit p2) -> System.Func! static Funcky.Extensions.JsonSerializerOptionsExtensions.GetTypeInfoOrNone(this System.Text.Json.JsonSerializerOptions! options, System.Type! type) -> Funcky.Monads.Option static Funcky.Extensions.OrderedDictionaryExtensions.IndexOfOrNone(this System.Collections.Generic.OrderedDictionary! dictionary, TKey key) -> Funcky.Monads.Option static Funcky.Extensions.ParseExtensions.ParseIPNetworkOrNone(this string? candidate) -> Funcky.Monads.Option static Funcky.Extensions.ParseExtensions.ParseIPNetworkOrNone(this System.ReadOnlySpan candidate) -> Funcky.Monads.Option +static Funcky.Functional.Apply(System.Func! func, Funcky.Unit p1, Funcky.Unit p2, Funcky.Unit p3, Funcky.Unit p4, T5 p5) -> System.Func! +static Funcky.Functional.Apply(System.Func! func, Funcky.Unit p1, Funcky.Unit p2, Funcky.Unit p3, T4 p4, Funcky.Unit p5) -> System.Func! +static Funcky.Functional.Apply(System.Func! func, Funcky.Unit p1, Funcky.Unit p2, Funcky.Unit p3, T4 p4, T5 p5) -> System.Func! +static Funcky.Functional.Apply(System.Func! func, Funcky.Unit p1, Funcky.Unit p2, T3 p3, Funcky.Unit p4, Funcky.Unit p5) -> System.Func! +static Funcky.Functional.Apply(System.Func! func, Funcky.Unit p1, Funcky.Unit p2, T3 p3, Funcky.Unit p4, T5 p5) -> System.Func! +static Funcky.Functional.Apply(System.Func! func, Funcky.Unit p1, Funcky.Unit p2, T3 p3, T4 p4, Funcky.Unit p5) -> System.Func! +static Funcky.Functional.Apply(System.Func! func, Funcky.Unit p1, Funcky.Unit p2, T3 p3, T4 p4, T5 p5) -> System.Func! +static Funcky.Functional.Apply(System.Func! func, Funcky.Unit p1, T2 p2, Funcky.Unit p3, Funcky.Unit p4, Funcky.Unit p5) -> System.Func! +static Funcky.Functional.Apply(System.Func! func, Funcky.Unit p1, T2 p2, Funcky.Unit p3, Funcky.Unit p4, T5 p5) -> System.Func! +static Funcky.Functional.Apply(System.Func! func, Funcky.Unit p1, T2 p2, Funcky.Unit p3, T4 p4, Funcky.Unit p5) -> System.Func! +static Funcky.Functional.Apply(System.Func! func, Funcky.Unit p1, T2 p2, Funcky.Unit p3, T4 p4, T5 p5) -> System.Func! +static Funcky.Functional.Apply(System.Func! func, Funcky.Unit p1, T2 p2, T3 p3, Funcky.Unit p4, Funcky.Unit p5) -> System.Func! +static Funcky.Functional.Apply(System.Func! func, Funcky.Unit p1, T2 p2, T3 p3, Funcky.Unit p4, T5 p5) -> System.Func! +static Funcky.Functional.Apply(System.Func! func, Funcky.Unit p1, T2 p2, T3 p3, T4 p4, Funcky.Unit p5) -> System.Func! +static Funcky.Functional.Apply(System.Func! func, Funcky.Unit p1, T2 p2, T3 p3, T4 p4, T5 p5) -> System.Func! +static Funcky.Functional.Apply(System.Func! func, T1 p1, Funcky.Unit p2, Funcky.Unit p3, Funcky.Unit p4, Funcky.Unit p5) -> System.Func! +static Funcky.Functional.Apply(System.Func! func, T1 p1, Funcky.Unit p2, Funcky.Unit p3, Funcky.Unit p4, T5 p5) -> System.Func! +static Funcky.Functional.Apply(System.Func! func, T1 p1, Funcky.Unit p2, Funcky.Unit p3, T4 p4, Funcky.Unit p5) -> System.Func! +static Funcky.Functional.Apply(System.Func! func, T1 p1, Funcky.Unit p2, Funcky.Unit p3, T4 p4, T5 p5) -> System.Func! +static Funcky.Functional.Apply(System.Func! func, T1 p1, Funcky.Unit p2, T3 p3, Funcky.Unit p4, Funcky.Unit p5) -> System.Func! +static Funcky.Functional.Apply(System.Func! func, T1 p1, Funcky.Unit p2, T3 p3, Funcky.Unit p4, T5 p5) -> System.Func! +static Funcky.Functional.Apply(System.Func! func, T1 p1, Funcky.Unit p2, T3 p3, T4 p4, Funcky.Unit p5) -> System.Func! +static Funcky.Functional.Apply(System.Func! func, T1 p1, Funcky.Unit p2, T3 p3, T4 p4, T5 p5) -> System.Func! +static Funcky.Functional.Apply(System.Func! func, T1 p1, T2 p2, Funcky.Unit p3, Funcky.Unit p4, Funcky.Unit p5) -> System.Func! +static Funcky.Functional.Apply(System.Func! func, T1 p1, T2 p2, Funcky.Unit p3, Funcky.Unit p4, T5 p5) -> System.Func! +static Funcky.Functional.Apply(System.Func! func, T1 p1, T2 p2, Funcky.Unit p3, T4 p4, Funcky.Unit p5) -> System.Func! +static Funcky.Functional.Apply(System.Func! func, T1 p1, T2 p2, Funcky.Unit p3, T4 p4, T5 p5) -> System.Func! +static Funcky.Functional.Apply(System.Func! func, T1 p1, T2 p2, T3 p3, Funcky.Unit p4, Funcky.Unit p5) -> System.Func! +static Funcky.Functional.Apply(System.Func! func, T1 p1, T2 p2, T3 p3, Funcky.Unit p4, T5 p5) -> System.Func! +static Funcky.Functional.Apply(System.Func! func, T1 p1, T2 p2, T3 p3, T4 p4, Funcky.Unit p5) -> System.Func! +static Funcky.Functional.Apply(System.Func! func, Funcky.Unit p1, Funcky.Unit p2, Funcky.Unit p3, T4 p4) -> System.Func! +static Funcky.Functional.Apply(System.Func! func, Funcky.Unit p1, Funcky.Unit p2, T3 p3, Funcky.Unit p4) -> System.Func! +static Funcky.Functional.Apply(System.Func! func, Funcky.Unit p1, Funcky.Unit p2, T3 p3, T4 p4) -> System.Func! +static Funcky.Functional.Apply(System.Func! func, Funcky.Unit p1, T2 p2, Funcky.Unit p3, Funcky.Unit p4) -> System.Func! +static Funcky.Functional.Apply(System.Func! func, Funcky.Unit p1, T2 p2, Funcky.Unit p3, T4 p4) -> System.Func! +static Funcky.Functional.Apply(System.Func! func, Funcky.Unit p1, T2 p2, T3 p3, Funcky.Unit p4) -> System.Func! +static Funcky.Functional.Apply(System.Func! func, Funcky.Unit p1, T2 p2, T3 p3, T4 p4) -> System.Func! +static Funcky.Functional.Apply(System.Func! func, T1 p1, Funcky.Unit p2, Funcky.Unit p3, Funcky.Unit p4) -> System.Func! +static Funcky.Functional.Apply(System.Func! func, T1 p1, Funcky.Unit p2, Funcky.Unit p3, T4 p4) -> System.Func! +static Funcky.Functional.Apply(System.Func! func, T1 p1, Funcky.Unit p2, T3 p3, Funcky.Unit p4) -> System.Func! +static Funcky.Functional.Apply(System.Func! func, T1 p1, Funcky.Unit p2, T3 p3, T4 p4) -> System.Func! +static Funcky.Functional.Apply(System.Func! func, T1 p1, T2 p2, Funcky.Unit p3, Funcky.Unit p4) -> System.Func! +static Funcky.Functional.Apply(System.Func! func, T1 p1, T2 p2, Funcky.Unit p3, T4 p4) -> System.Func! +static Funcky.Functional.Apply(System.Func! func, T1 p1, T2 p2, T3 p3, Funcky.Unit p4) -> System.Func! +static Funcky.Functional.Apply(System.Func! func, Funcky.Unit p1, Funcky.Unit p2, T3 p3) -> System.Func! +static Funcky.Functional.Apply(System.Func! func, Funcky.Unit p1, T2 p2, Funcky.Unit p3) -> System.Func! +static Funcky.Functional.Apply(System.Func! func, Funcky.Unit p1, T2 p2, T3 p3) -> System.Func! +static Funcky.Functional.Apply(System.Func! func, T1 p1, Funcky.Unit p2, Funcky.Unit p3) -> System.Func! +static Funcky.Functional.Apply(System.Func! func, T1 p1, Funcky.Unit p2, T3 p3) -> System.Func! +static Funcky.Functional.Apply(System.Func! func, T1 p1, T2 p2, Funcky.Unit p3) -> System.Func! +static Funcky.Functional.Apply(System.Func! func, Funcky.Unit p1, T2 p2) -> System.Func! +static Funcky.Functional.Apply(System.Func! func, T1 p1, Funcky.Unit p2) -> System.Func! static Funcky.Functional.Fn(T value) -> T