CSharp · Console
using System;
using System.Collections.Generic;
using System.Linq;
public class Program
{
public static void Main()
{
var range = Enumerable.Range(1, 10);
Console.WriteLine(MapAnyFunctorEnumerable(range, x => x).SequenceEqual(range)); // выведет True
int? nullableTen = 10;
int? nullableNull = null;
Console.WriteLine(MapAnyFunctorNullable(nullableTen, x => x) == nullableTen); // выведет True
Console.WriteLine(MapAnyFunctorNullable(nullableNull, x => x) == nullableNull); // выведет True
}
static IEnumerable<B> MapAnyFunctorEnumerable<A, B>(IEnumerable<A> source, Func<A, B> map) =>
EnumerableApplicative.LiftA2(source, EnumerableApplicative.Pure(0), (a, _) => map(a));
static B? MapAnyFunctorNullable<A, B>(A? source, Func<A, B> map) where A : struct where B : struct =>
NullableApplicative.LiftA2(source, NullableApplicative.Pure(0), (a, _) => map(a));
}
public static class EnumerableApplicative
{
public static IEnumerable<A> Pure<A>(A a) => new[] { a };
public static IEnumerable<C> LiftA2<A, B, C>(IEnumerable<A> ta, IEnumerable<B> tb, Func<A, B, C> map2) =>
ta.SelectMany(a => tb.Select(b => map2(a, b)));
}
public static class NullableApplicative
{
public static A? Pure<A>(A a) where A : struct => a;
public static C? LiftA2<A, B, C>(A? ta, B? tb, Func<A, B, C> map2) where A : struct where B : struct where C : struct =>
(ta, tb) switch
{
(A a, B b) => map2(a, b),
_ => default(C?)
};
}