Finq 1.0.0-alpha-01

This is a prerelease version of Finq.
dotnet add package Finq --version 1.0.0-alpha-01
NuGet\Install-Package Finq -Version 1.0.0-alpha-01
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Finq" Version="1.0.0-alpha-01" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add Finq --version 1.0.0-alpha-01
#r "nuget: Finq, 1.0.0-alpha-01"
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install Finq as a Cake Addin
#addin nuget:?package=Finq&version=1.0.0-alpha-01&prerelease

// Install Finq as a Cake Tool
#tool nuget:?package=Finq&version=1.0.0-alpha-01&prerelease

Finq

⚠️ This is a work in progress. The API for Finq is not yet stable and is subject to change. Use at your own risk. It is nonetheless being published to gather feedback and allow for experimentation, both of which should help shape the final API.

Finq is a library that allows functions to be written using LINQ, as if you never had lambda (=>) in C#:

var f = // : Func<int, int>
    from x in Funq.Arg.Int32()
    select x * 2;

var g = // : Func<int, string>
    from x in f
    select $"{x + 2}";

Console.WriteLine(g(20)); // prints: "42"

Note that the function types resulting from using Finq are still the ones you are familiar with; this is, the type of f in the above example is still Func<int, int>, and the type of g is Func<int, string>. f and g are still instantiations of the generic Fun<,> and you can therefore think of Finq as a way to write functions in a more declarative style, using LINQ.

With Finq, you can also use LINQ where a regular function is expected:

static string Join<T>(string delimiter, IEnumerable<T> xs, Func<T, string> fs) =>
    string.Join(delimiter, from x in xs select fs(x));

var s = Join(Environment.NewLine,
             [1, 2, 3, 4, 5],
             from x in Funq.Arg.Int32()
             select $"{x} => {x * Math.PI:0.0000}");

Console.WriteLine(s);

Prints:

1 => 3.1416
2 => 6.2832
3 => 9.4248
4 => 12.5664
5 => 15.7080

The LINQ in the above example is equivalent to writing x => $"{x} => {x * Math.PI:0.0000}", but it reads longer and can run considerably slower so the goal of Finq is not to offer a replacement. However, it can be useful in some situations. For example, suppose you have the following function, that takes as an argument, a curried function:

static T Foo<T>(Func<int, Func<int, T>> f) => f(20)(2);

In C# (up to and including version 13 at the time of writing), this function cannot be called without explicitly specifying the type of T. Doing so:

Console.WriteLine(Foo(x => y => $"{x * 2 + y}")); // compilation error (CS0411)

results in compilation error CS0411:

The type arguments for method 'method' cannot be inferred from the usage. Try specifying the type arguments explicitly.

The C# compiler is unable to infer that the type of T is int from the lambda expression. Instead, you have to write:

Console.WriteLine(Foo<string>(x => y => $"{x * 2 + y}")); // prints: 42

However, with Finq, you can write:

var f = // : Func<int, Func<int, int>>
    from x in Funq.Arg.Int32()
    select
        from y in Funq.Arg.Int32()
        select x * 2 + y;

Console.WriteLine(Foo(f)); // prints: 42

It's also impossible to explicitly specify the type of T when the type is anonymous, but

var f = // : Func<int, Func<int, ?>>
    from x in Funq.Arg.Int32()
    select
        from y in Funq.Arg.Int32()
        select new
        {
            X = x,
            Y = y,
            Calc = x * 2 + y
        };

Console.WriteLine(Foo(f)); // prints: { X = 20, Y = 2, Calc = 42 }

Finq can also come in handy when you want to model functions as a reader functor and more. For more on this, see the “The Reader functor” blog post by Mark Seemann (aka @ploeh), and specifically the section “Raw functions”.

Finq's Funq.Arg ship with a number of common argument types, such as Int32, String, Double, Boolean, etc., but you can add your own to the mix by writing an extension method for IArg.

For ad-hoc specification of the argument type, use Funq.ArgOf<T>.Return():

var f = // : Func<int, int>
    from x in Funq.ArgOf<int>().Return()
    select x * 2;

Finq sticks to functions that take a single argument. If multiple arguments are needed then use a tuple or, preferably the parameter object pattern.

Finq also supports fallible functions via LINQ's where clause:

var positive = // : Func<int, (bool, int)>
    from x in Funq.Arg.Int32()
    where x > 0
    select x; // evaluated only if positive

foreach (var input in new[] { -1, 0, 1 })
{
    var ok = positive.TryInvoke(input, out var result);
    Console.WriteLine($"{nameof(ok)} = {ok}; {nameof(result)} = {result}");
}

Prints:

ok = False; result = 0
ok = False; result = 0
ok = True; result = 1

Using where changes the function return type from some T to the tuple (bool, T), where the first (Boolean) element of the tuple is true if the second element is valid and false otherwise. See Optuple for more background on this pattern.

Product Compatible and additional computed target framework versions.
.NET net6.0 is compatible.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net6.0

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
1.0.0-alpha-01 45 6/10/2024