Pattern Matching Discriminated Union в C# через кодогенерацию
а реальное использование в какой задаче?
А проверка на exhaustiveness есть? Если нет, легко ли добавить?
В F# они примерно так и реализованы.
А проверка на exhaustiveness есть? Если нет, легко ли добавить?Судя по коду, там нужно все кейсы обработать, в функции Match аргументы же не опциональные.
Чтобы наоборот кейсы игнорировать можно ввести функции Ignore генерик типов Func<T, Result>, Func<T1, T2, Result> и т.д.
А проверка на exhaustiveness есть? Если нет, легко ли добавить?имеется ввиду надо ли писать паттерн для каждого item-а? да, это контролируется компилятором.
Выглядит как переизобретение discriminated union'ов.ну, да, этого и хотелось, только без смены языка
а реальное использование в какой задаче?о том для чего мне это понадобилось напишу позже (сейчас на работу опаздываю ). А сейчас отмечу, что в первом варианте IXxxMatcher назывался IXxxVisitor .
Если взять пример, который уже был на нашем форуме
то вот этот код будет сгенерирован автоматически:
abstract class BinaryNode : INode
{
protected readonly INode left;
protected readonly INode right;
protected BinaryNode(INode left, INode right)
{
this.left = left;
this.right = right;
}
public abstract T ProcessBy<T>(INodeVisitor<T> visitor);
}
class Add : BinaryNode
{
public Add(INode left, INode right) : base(left, right)
{
}
public override T ProcessBy<T>(INodeVisitor<T> visitor)
{
return visitor.OnAdd(left, right);
}
}
class Sub : BinaryNode
{
public Sub(INode left, INode right) : base(left, right)
{
}
public override T ProcessBy<T>(INodeVisitor<T> visitor)
{
return visitor.OnSub(left, right);
}
}
class Mul : BinaryNode
{
public Mul(INode left, INode right) : base(left, right)
{
}
public override T ProcessBy<T>(INodeVisitor<T> visitor)
{
return visitor.OnMul(left, right);
}
}
class Constant : INode
{
readonly double val;
public Constant(double val)
{
this.val = val;
}
public T ProcessBy<T>(INodeVisitor<T> visitor)
{
return visitor.OnConstant(val);
}
}
class VariableX : INode
{
public T ProcessBy<T>(INodeVisitor<T> visitor)
{
return visitor.OnVariableX;
}
}
только без BinaryNode, а он и не нужен.
case a of
| Item1 x => blabla
| _ => otherwise
Аналога "_" нет. А оно нужно? Это же по сути противоречит exhaustiveness, мы добавили Item4 и нам компилятор не показывает все места, где идет ветвление, а прелесть exhaustiveness в том, что мы явно должны прописывать все случае, причем даже те, которые появляются в будущем.
А оно нужно?Главное просто этого не хотеть.
Главное просто этого не хотеть.Речь идет не о желании или нежелании, есть обоснование почему это плохо, см. пост выше.
а прелесть exhaustiveness в том, что мы явно должны прописывать все случае, причем даже те, которые появляются в будущем.Хорошо-хорошо. Напиши мне, пожалуйста, исчерпывающее определение функции, определяющей, является ли целое число нулем.
целые числа определяются как Discriminated Union?
data Int = ... | -2 | -1 | 0 | 1 | 2 | ...
Мы ведь не обсуждаем, что в шарпе опять можно придумать кривой костыль для какой-то давно всеми используемой фичи, который пригоден только для семидесяти пяти сотых случая, правда?
bool IsZero(int x)
{
return x == 0;
}
Какая прелесть!
мы же не обсуждаем, что в каких-то языках можно теоретические изъебы выписывать, правда? Не хочешь приводить примера из реальной практики, тогда лучше промолчи.
Не хочешь приводить примера из реальной практики, тогда лучше промолчи.Ебтать.
Расскажи мне, пожалуйста, какой тебе нужен реальный пример, чтобы ты не превратил его в цепочку ифов.
Можно поподробнее.
давай так. Ты чего хочешь показать/доказать?
имеется ввиду надо ли писать паттерн для каждого item-а? да, это контролируется компилятором.— несколько странное требование.
несколько странное требование.Можно это переформулировать в более конструктивные термины? Сложно вести конструктивный разговор в терминах "не хотеть", "странное". Не инженерные это термины.
Можно это переформулировать в более конструктивные термины?Можно, только я подозреваю, что ты все равно не поймешь.
Можно, только я подозреваю, что ты все равно не поймешь.неумение объяснить часто свидетельствует о том, что ты сам не понимаешь
а реальное использование в какой задаче?Приvер 1. Реализация Workflow:
public interface IStateMatcher<out T>
{
T State1;
T State2;
T State3;
}
public interface ITransitionMatcher<out T>
{
T State1ToState2(IState fromState, IState toState);
T State1ToState3(IState fromState, IState toState);
T State2ToState3(IState fromState, IState toState);
}
public static IEnumerable<ITransition> GetTransitions(this IState state)
{
return state.Match(
state1: => new []
{
Transition.State1ToState2(state, State.State2
Transition.State1ToState3(state, State.State3
},
state2: => new []
{
Transition.State2ToState3(state, State.State3
},
state3: => new ITransition[] { }
);
}
Пример 2. По вот такому
1. выгружать объекты в XML (Matcher1);
2. генерировать XSD схему (Matcher2);
3. загружать объекты из XML (Matcher3).
public interface ITransitionMatcher<out T>
{
T Transition(State1 fromState, State2 toState);
T Transition(State1 fromState, State3 toState);
T Transition(State2 fromState, State3 toState);
}
Мы ведь не обсуждаем, что в шарпе опять можно придумать кривой костыль для какой-то давно всеми используемой фичи, который пригоден только для семидесяти пяти сотых случая, правда?оказывается всё ни так просто . В случае C# и кодогенерации, вот такой поддерживается без проблем, а в твоем фичастом языке без костылей как такое реализуется? Надеюсь, ты способен не только играться в песочнице с целыми числами и продемонстрируешь свои аргументы на реальном примере.
Изюминка тут в том, что требуется разрешить overloading членов discriminated union по аргументам. Если такое разрешено в языке, то тогда как такие члены буду указываться вне match-а?
В случае кодогенерации поступаем просто, если overloading есть, то члены скрыты в виде приватных классов, если overloading-а нет, то классы публичны.
Я правильно понимаю, что этот подход не позволяет использовать составные шаблоны? Если так, то весь смысл паттерн матчинга теряется.
Я правильно понимаю, что этот подход не позволяет использовать составные шаблоны? Если так, то весь смысл паттерн матчинга теряется.там у пор на связку pattern matching-а с discriminated union
Оставить комментарий
6yrop
Определяем интерфейсПосле кодогенерации доступен вот такой Pattern Matching:
Кодогенерация генерирует вот такую простыню. Фишка в том, что всё уже определено в интерфейсе IXxxMatcher.
P.S. в компиляторе C# в framework 4.0 есть небольшой баг, который пофиксили, я проверил на framework 4.5