Статически типизированный корректный список минусов в C#
Я задал себе глупый вопрос и уже несколько часов ломаю себе голову безрезультатно.
Допустим, по какой-то причине вы хотите реализовать cons-ячейку в C# (десятого правила Гринспуна должно быть достаточно). Поскольку он находится в C#, вы хотите, чтобы он был статически типизирован. Что-то вроде этого должно быть достаточно:
interface ICons<T, U>
{
T Left { get; }
U Right { get; }
}
struct Cons<T, U> : ICons<T, U>
{
public T Left { get; }
public U Right { get; }
public Cons(T left, U right)
{
Left = left;
Right = right;
}
}
struct Nil : ICons<Nil, Nil>
{
public Nil Left => this;
public Nil Right => this;
}
Теперь есть static void VisitList<T>(? list, Action<T> action)
метод, который принимает правильно сформированный список T
и делает что-то с каждым элементом. Хорошо сформированный список T
это Nil
или минус ячейка, которая имеет T
как его левый элемент и правильно сформированный список T
как его правильный элемент. Теперь мы можем заменить ?
с реальным типом (да, представьте, что есть Either
не-монада): static void VisitList<T, U>(Either<Nil, ICons<T, U>> list, Action<T> action) where U : Either<Nil, ICons<T, U>>
,
Невозможный вопрос: как, черт возьми, вы строите значение, которое вы можете передать этому методу? Кто-нибудь может написать рабочий фрагмент? Остальная часть примера кода приведена ниже.
class Either<T, U>
{
public bool IsRight { get; }
public bool IsLeft => !IsRight;
public T Left { get; }
public U Right { get; }
public Either(T left)
{
IsRight = false;
Right = default(U);
Left = left;
}
public Either(U right)
{
IsRight = true;
Left = default(T);
Right = right;
}
public static implicit operator Either<T, U>(T value) => new Either<T, U>(value);
public static implicit operator Either<T, U>(U value) => new Either<T, U>(value);
}
class Program
{
static void VisitList<T, U>(Either<Nil, ICons<T, U>> list, Action<T> action)
where U : Either<Nil, ICons<T, U>>
{
while (list.IsRight) {
action(list.Right.Left);
list = list.Right.Right;
}
}
static void Main(string[] args)
{
VisitList(/*put your well-formed cons list here*/, WriteLine);
ReadKey(true);
}
}