CSharp · Console
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
public class Program
{
public static void Main()
{
var eta = Enumerable.Range(3, 2);
var etb = Enumerable.Range(15, 4);
int? nta = 10;
int? ntb = null;
Print(EnumerableApplicative.LiftA2(eta, etb, (a, b) => (a, b))); // Combine
Print(NullableApplicative.LiftA2(nta, nta, (a, b) => (a, b))); // Combine
Print(NullableApplicative.LiftA2(nta, ntb, (a, b) => (a, b))); // Combine
Print(ZipListApplicative.LiftA2(new ZipList<int>(eta), new ZipList<int>(etb), (a, b) => (a, b))); // Combine
}
private static void Print<T>(T value) where T : struct
{
Console.WriteLine(value);
}
private static void Print<T>(T? value) where T :struct
{
Console.WriteLine(value?.ToString() ?? "Null");
}
private static void Print<T>(IEnumerable<T> source)
{
Console.WriteLine($"[{string.Join(", ", source)}]");
}
}
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?)
};
}
public static class ZipListApplicative
{
public static IEnumerable<A> Pure<A>(A a) =>
Enumerable.Repeat(a, int.MaxValue); // вообще тут должен быть бесконечный генератор
public static ZipList<C> LiftA2<A, B, C>(ZipList<A> ta, ZipList<B> tb, Func<A, B, C> map2) =>
new ZipList<C>(ta.Zip(tb, map2));
}
public class ZipList<T> : IEnumerable<T>
{
private readonly IEnumerable<T> _inner;
public ZipList(IEnumerable<T> inner)
{
_inner = inner;
}
public IEnumerator<T> GetEnumerator()
{
return _inner.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return ((IEnumerable)_inner).GetEnumerator();
}
}