Здравствуйте, VladD2, Вы писали:
VD>Итого 70 строк. И вряд ли кто-то будет спорить, что они намного лучше читаются.
Мои 150 выполняют больше работы, но это, как я уже писал, из-за работы по памяти.
К тому же моя иерархия, возможно (из-за незнания Nemerle), строже.
Например у меня некоторые классы в иерархии абстрактные, то есть их нельзя создать.
VD>Причем, заметь, я не менял весь код а добавил всего два фрагмента. Фнукцию Convert:
Практически аналогично и у меня.
VD>К каждому классу иерархии был добавлен соврешенно метод RemoveOneParameterMin().
VD>Он увеличил код и сделал его плохо читаемым.
Спорно что плохочитаемым.
VD>К тому же RemoveOneParameterMin не универсален, а в исходном задании было сказано о том, что требуется универсальное решение, а не для конкретного случая.
Зато появляется доступ к внутренним полям класса, например можно вообще обойтись без публичнных полей.
VD>Не выполнено по сути и задие с добавлением фунций. Ведь у тебя количество параметров не контролируется.
Легко добавляется.
VD>Теперь можно продолжить наши упраженния. Сколько тебе потребуется времени и сил чтобы добавить еще две оптимизирующие трансформации — заменять выражение max(константа, константа) на значение большей из констант. И соответственно min(константа, константа), меньшей? Мне — пол минуты. Я просто добавлю пару образцов и все.
После написания функции Convert для поддержки конвертации, тоже, что-то в этом духе
VD>Заметь, по сути мне нужно было добавить две строки. Тебе же прийдется еще раз менять дизайн всего приложения.
Не придется.
VD>С Посетителем код у тебя может и был бы несколько больше, но все же не пришлось бы каждый раз курочить все классы ради подобных вещей.
Да, но похоже у посетителя, таже проблема, что и с общим методом в корневом классе. При добавлении классов в иерархию, ошибка не обработки, какого-либо класса переносится в runtime.
VD>Ну, и естественно, что без паттерн-матчинга как бы ты не извивался, но твой код все равно будет больше и непонятнее.
Все-таки вопрос привычки.
Вот код:
using System;
delegate Expr Converter(Expr expr);
abstract class Expr
{
public abstract override string ToString();
public abstract double Eval();
public virtual Expr Convert(Converter converter) { return converter(this); }
}
class Lit: Expr
{
private double value;
public Lit(double value) { this.value = value; }
public override string ToString() { return value.ToString(); }
public override double Eval() { return value; }
}
abstract class Oper: Expr
{
protected Expr first, second;
public Expr First { get { return first; } }
public Expr Second { get { return second; } }
public Oper(Expr first, Expr second)
{
this.first = first;
this.second = second;
}
}
class Plus: Oper
{
public Plus(Expr first, Expr second): base(first, second) {}
public override string ToString() { return first.ToString() + "+" + second.ToString(); }
public override double Eval() { return first.Eval() + second.Eval(); }
public override Expr Convert(Converter converter) { return converter(new Plus(first.Convert(converter), second.Convert(converter))); }
}
class Minus: Oper
{
public Minus(Expr first, Expr second): base(first, second) {}
public override string ToString() { return first.ToString() + "-" + second.ToString(); }
public override double Eval() { return first.Eval() - second.Eval(); }
public override Expr Convert(Converter converter) { return converter(new Minus(first.Convert(converter), second.Convert(converter))); }
}
class Mul: Oper
{
public Mul(Expr first, Expr second): base(first, second) {}
public override string ToString() { return first.ToString() + "*" + second.ToString(); }
public override double Eval() { return first.Eval() * second.Eval(); }
public override Expr Convert(Converter converter) { return converter(new Mul(first.Convert(converter), second.Convert(converter))); }
}
class Div: Oper
{
public Div(Expr first, Expr second): base(first, second) {}
public override string ToString() { return first.ToString() + "/" + second.ToString(); }
public override double Eval() { return first.Eval() / second.Eval(); }
public override Expr Convert(Converter converter) { return converter(new Div(first.Convert(converter), second.Convert(converter))); }
}
abstract class Call: Expr
{
protected string name;
protected Expr[] arguments;
public Call(string name, params Expr[] arguments)
{
this.name = name;
this.arguments = arguments;
}
public override string ToString() { return name + "(" + String.Join(", ", Array.ConvertAll<Expr, string>(arguments, System.Convert.ToString)) + ")"; }
}
abstract class TwoParameterCall: Call
{
public TwoParameterCall(string name, params Expr[] arguments): base(name, arguments) {}
public Expr First { get { return arguments[0]; } }
public Expr Second { get { return arguments[1]; } }
}
class Min: TwoParameterCall
{
public Min(Expr first, Expr second): base("Min", first, second) {}
public override double Eval() { return Math.Min(arguments[0].Eval(), arguments[1].Eval()); }
public override Expr Convert(Converter converter) { return converter(new Min(arguments[0].Convert(converter), arguments[1].Convert(converter))); }
}
class Max: TwoParameterCall
{
public Max(Expr first, Expr second): base("Max", first, second) {}
public override double Eval() { return Math.Max(arguments[0].Eval(), arguments[1].Eval()); }
public override Expr Convert(Converter converter) { return converter(new Max(arguments[0].Convert(converter), arguments[1].Convert(converter))); }
}
class Foo: Call
{
public Foo(Expr first): base("Foo", first) {}
public override double Eval() { return arguments[0].Eval(); }
public override Expr Convert(Converter converter) { return converter(new Foo(arguments[0].Convert(converter))); }
}
public class Program
{
public static void Main(string[] arguments)
{
Expr exprWithMulToOne = new Mul(new Lit(2.34), new Lit(1.00));
WriteLine(exprWithMulToOne);
Expr exprWithoutMulToOne = exprWithMulToOne.Convert(RemoveMulToOne);
WriteLine(exprWithoutMulToOne);
Expr exprWithMaxOfLiterals = new Max(new Lit(1.23), new Lit(2.34));
WriteLine(exprWithMaxOfLiterals);
Expr exprWithoutMaxOfLiterals = exprWithMaxOfLiterals.Convert(RemoveMaxOfLiterals);
WriteLine(exprWithoutMaxOfLiterals);
Expr exprWithMinOfLiterals = new Min(new Lit(1.23), new Lit(2.34));
WriteLine(exprWithMinOfLiterals);
Expr exprWithoutMinOfLiterals = exprWithMinOfLiterals.Convert(RemoveMinOfLiterals);
WriteLine(exprWithoutMinOfLiterals);
}
static void WriteLine(Expr expr)
{
Console.WriteLine(String.Format("Expression '{0}' = {1}", expr.ToString(), expr.Eval()));
}
static Expr RemoveMulToOne(Expr expr)
{
Mul mul = expr as Mul; if (mul != null)
{
Lit lit = mul.Second as Lit; if (lit != null && lit.Eval() == 1)
{
return mul.First;
}
}
return expr;
}
static Expr RemoveMaxOfLiterals(Expr expr)
{
Max max = expr as Max; if (max != null)
{
Lit first = max.First as Lit, second = max.Second as Lit; if (first != null && second != null)
{
return new Lit(Math.Max(first.Eval(), second.Eval()));
}
}
return expr;
}
static Expr RemoveMinOfLiterals(Expr expr)
{
Min min = expr as Min; if (min != null)
{
Lit first = min.First as Lit, second = min.Second as Lit; if (first != null && second != null)
{
return new Lit(Math.Min(first.Eval(), second.Eval()));
}
}
return expr;
}
}