Re[7]: Функциональное программирование в Nemerle
От: Аноним  
Дата: 17.05.07 17:49
Оценка:
Здравствуйте, 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;
    }
}
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.