Sorry, it used to be some retired garbage in Countable and uncountable sets. Now and here it is clean.
P.S. I would not like to say that this stuff is about to replace functional programming :) No, it is just about predicates becoming a full featured objects, so you can do math on them in the form of sets. We are always adding indirection over indirection in software development...
using System;
using System.Collections.Generic;
using System.Linq;
using System.Collections;
using static System.Console;
using static System.String;
class Program
{
static void Main(string[] args)
{
var NullOrEmpty = new Set<string>(string.IsNullOrEmpty);
var NullOrWhiteSpace = new Set<string>(string.IsNullOrWhiteSpace);
var WhiteSpace = NullOrWhiteSpace - NullOrEmpty;
WriteLine(WhiteSpace * " "); // True
foreach (var s in !WhiteSpace * "Abba")
WriteLine(s); // Abba
var LowIncome = new Set<int>(i => i < 30000);
var HighIncome = new Set<int>(i => i > 140000);
var MiddleIncome = !LowIncome * !HighIncome;
var salaries = new[] { 25000, 40000, 35000, 80000, 65000, 120000, 200000 };
WriteLine(Join(",", salaries - MiddleIncome)); // 25000, 200000
WriteLine(Join(",", salaries * (LowIncome + HighIncome))); // 25000, 200000
WriteLine(Join(",", salaries * !LowIncome)); // 40000,35000,80000,65000,120000,200000
}
}
class Set<T>
{
public Set(Predicate<T> predicate)
{
Predicate = predicate;
}
public static Enumerable<T> operator *(Set<T> left, T right) =>
left.Predicate(right) ? new Enumerable<T>(right) : Enumerable<T>.Empty;
public static Enumerable<T> operator *(T left, Set<T> right) =>
right.Predicate(left) ? new Enumerable<T>(left) : Enumerable<T>.Empty;
public static Set<T> operator *(Set<T> left, Set<T> right) =>
new Set<T>(i => left.Predicate(i) && right.Predicate(i));
public static Enumerable<T> operator *(Set<T> left, IEnumerable<T> right) =>
new Enumerable<T>(right.Where(i => left.Predicate(i)));
public static Enumerable<T> operator *(IEnumerable<T> left, Set<T> right) =>
new Enumerable<T>(left.Where(i => right.Predicate(i)));
public static Set<T> operator +(Set<T> left, T right) =>
new Set<T>(i => left.Predicate(i) || right.Equals(i));
public static Set<T> operator +(T left, Set<T> right) =>
new Set<T>(i => left.Equals(i) || right.Predicate(i));
public static Set<T> operator +(Set<T> left, Set<T> right) =>
new Set<T>(i => left.Predicate(i) || right.Predicate(i));
public static Set<T> operator +(Set<T> left, IEnumerable<T> right) =>
new Set<T>(i => left.Predicate(i) || right.Contains(i));
public static Set<T> operator +(IEnumerable<T> left, Set<T> right) =>
new Set<T>(i => left.Contains(i) || right.Predicate(i));
public static Set<T> operator -(Set<T> left, T right) =>
new Set<T>(i => left.Predicate(i) && !right.Equals(i));
public static Set<T> operator -(T left, Set<T> right) =>
new Set<T>(i => left.Equals(i) && !right.Predicate(i));
public static Set<T> operator -(Set<T> left, Set<T> right) =>
new Set<T>(i => left.Predicate(i) && !right.Predicate(i));
public static Set<T> operator -(Set<T> left, IEnumerable<T> right) =>
new Set<T>(i => left.Predicate(i) && !right.Contains(i));
public static Enumerable<T> operator -(IEnumerable<T> left, Set<T> right) =>
new Enumerable<T>(left.Where(i => !right.Predicate(i)));
public static Set<T> operator !(Set<T> set) =>
new Set<T>(i => !set.Predicate(i));
Predicate<T> Predicate { get; }
}
class Enumerable<T> : IEnumerable<T>
{
public static readonly Enumerable<T> Empty = new Enumerable<T>();
public static implicit operator bool(Enumerable<T> intersection) => intersection.Any();
public Enumerable(params T[] items)
{
Items = items;
}
public Enumerable(IEnumerable<T> items)
{
Items = items;
}
public IEnumerator<T> GetEnumerator() => Items.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
IEnumerable<T> Items { get; }
}
var predicate = myPredicate.And(otherPredicate)
andcollection.Where(predicate.Not())
are more verbose, but they're also much easier to understand (in the context of C#). \$\endgroup\$+
and-
to&
and|
- it looks much better now. But the same time, good lambda language to help with composition might be useful, yes... \$\endgroup\$