Re[8]: Функциональное программирование в Nemerle
От: VladD2 Российская Империя www.nemerle.org
Дата: 17.05.07 20:34
Оценка:
Здравствуйте, <Аноним>, Вы писали:

А>Мои 150 выполняют больше работы, но это, как я уже писал, из-за работы по памяти.


Больше? Он не делал то что от него требовалось. И друго полезного тоже ничего не делает.

А>К тому же моя иерархия, возможно (из-за незнания Nemerle), строже.


Серьезно? Ну, сделай ее менее строгой. Хотя что-то я не заметил там какой-то строгости. Недоработки вот видны сразу. Например, контроль количества параметров у фунций отсуствует. Можно такую несуразность как Min() с одинм параметром сделать.

А>Например у меня некоторые классы в иерархии абстрактные, то есть их нельзя создать.


Это проблемы твоей реализации и выбронного тбой подхода. Сделай по другому. Главное, чтобы по фунциональности было тоже самое.

VD>>Причем, заметь, я не менял весь код а добавил всего два фрагмента. Фнукцию Convert:

А>Практически аналогично и у меня.

У тебя код не делал то что нужно.

VD>>К каждому классу иерархии был добавлен соврешенно метод RemoveOneParameterMin().

VD>>Он увеличил код и сделал его плохо читаемым.
А>Спорно что плохочитаемым.

Это спорно только для тебя. И то потому что ты любиль спорить и не любишь призновать своей не правоты (сам такй, по этому знаю не по наслышке ).

Заметь, люди которые знают оба зыка откровенно помеялись над твоим кодом.

К тому же если все так хорошо, что же ты переписал код как только увидел мой вариант?

VD>>К тому же RemoveOneParameterMin не универсален, а в исходном задании было сказано о том, что требуется универсальное решение, а не для конкретного случая.

А>Зато появляется доступ к внутренним полям класса, например можно вообще обойтись без публичнных полей.

Да уж это неверотное приемущество, вот только этого не требовалось по условию задачи и не ясно что оно дает.

VD>>Не выполнено по сути и задие с добавлением фунций. Ведь у тебя количество параметров не контролируется.

А>Легко добавляется.

То-то я гляжу, все так легко, что дня не хвает на реализацию.

VD>>Теперь можно продолжить наши упраженния. Сколько тебе потребуется времени и сил чтобы добавить еще две оптимизирующие трансформации — заменять выражение max(константа, константа) на значение большей из констант. И соответственно min(константа, константа), меньшей? Мне — пол минуты. Я просто добавлю пару образцов и все.

А>После написания функции Convert для поддержки конвертации, тоже, что-то в этом духе

Что же ты ее не написал в этом же духе сразу? И как выглядит код твоих трансформаций? Заметь я привел совсем примитивные примеры образцов. Они у тебя уже порождают кучу кода. А даже небольшое их усложнение приведет к настоящей горе кода. Причем совершенно нечитаемого.

Сравни:
static Expr RemoveMaxOfLiterals(Expr expr)
{
  Max max = expr as Max;
  if (max != null)
  {
    Lit first = max.First as Lit;
    Lit second = max.Second as Lit;
    if (first != null && second != null)
      return new Lit(Math.Max(first.Eval(), second.Eval()));
  }
  return expr;
}

и
| Call("max", [Lit(x), Lit(y)]) => Lit(Math.Max(x, y))

Кстати, использовать Eval() для доступа к значениям литералов плохой подход. В будущем поведение может измениться и этот код превратится в ошибочный, а компилятор снова не сможет ничего подсказать.

VD>>Заметь, по сути мне нужно было добавить две строки. Тебе же прийдется еще раз менять дизайн всего приложения.

А>Не придется.

Да? А как понимать, то что ты полностью переписал свой код и отказался от так защищаемого тбой RemoveOneParameterMin()?

Ты уже начиташь сам себе противоречить и своими же действиями опровергать свои же слова .

VD>>С Посетителем код у тебя может и был бы несколько больше, но все же не пришлось бы каждый раз курочить все классы ради подобных вещей.

А>Да, но похоже у посетителя, таже проблема, что и с общим методом в корневом классе. При добавлении классов в иерархию, ошибка не обработки, какого-либо класса переносится в runtime.

Отнюдь. Как раз посетители отлично выявляют необработанные классы иерархии, если конечно, правильно их готовить.

VD>>Ну, и естественно, что без паттерн-матчинга как бы ты не извивался, но твой код все равно будет больше и непонятнее.

А>Все-таки вопрос привычки.

Серьезно? Ну, я почти на верняка пишу на C# дольше тебя (начал еще в 2000-ном когда первые превью появились), но вот почему-то никак не могу привыкнуть к тому, что вместо:
def expr = expr.Convert(_ => { 
    | Mul(x, Literal(1.0))                  => x 
    | Call("max", [Literal(x), Literal(y)]) => Literal(Math.Max(x, y))
    | Call("mix", [Literal(x), Literal(y)]) => Literal(Math.Min(x, y))
    | e                                     => e });

я вынужден писать:
static Expr Transform(Expr expr)
{
    return RemoveMulToOne(RemoveMaxOfLiterals(RemoveMinOfLiterals(expr)));
}

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;
        Lit second = max.Second as Lit;
        if (first != null && second != null)
            return new Lit(Math.Max(first., second.Eval()));
    }
    return expr;
}

static Expr RemoveMinOfLiterals(Expr expr)
{
    Min min = expr as Min;
    if (min != null)
    {
        Lit first = min.First as Lit;
        Lit second = min.Second as Lit;
        if (first != null && second != null)
            return new Lit(Math.Min(first.Eval(), second.Eval()));
    }
    return expr;
}

...

expr = expr.Convert(Transform);


Расскажи, как ты к такому привыкаешь?

Я даже могу тебе подсказать, как сократить еще по строчки в каждой из функий. Например, RemoveMinOfLiterals можно записать так:
static Expr RemoveMinOfLiterals(Expr expr)
{
  Min min = expr as Min;
  if (min != null)
  {
    if (min.First is Lit && min.Second is Lit)
      return new Lit(Math.Min(min.First.Eval(), min.Second.Eval()));
  }
  return expr;
}

но это ужимки. Код можно оптимизировать до какой-то степени, но не более. Без введения в язык новых вещей вроде паттерн-матчинга ничего ничего радикально изменить нельзя!

А>Вот код:...


Ну, что же. Ты не плохо учишся. Это называется переписать код в близком к функциональному стилю. Заметь, сходу ты такой код порадить не был способен. Пришлось подглядывать за поей версией и тырить от туда идеи. Я же просто писал в выбранном стиле, что называется не думая.

Теперь еще раз разберем полеты.

Объем кода
После устранения в твоем коде совсем уж затариенных в одну строку вещей кода получилось около 200 строк. Причем он еще остался "ужатым". В реальных проетах код будет по рыхлее. Мой код занимает 75 строк.
Получается кода более чем в 2 раза больше. Его вдвое больше при любых других измерения (в словах, в символах и т.п.). Если твой код отформатировать скажем по правилам РСДН, то его станет в трое больше.

Читаемость кода

Вряд ли ты станешь спорить, что теперь наш код иделогически близок. Но вот что лучше читается? На мой взгляд действия собранные вместе и без лишних заголовков функций читается намного лучше. Его и поддерживать проще.
Код правил трансформации даже сранвивать смешно. Три ясных как божий день строчки против порядка 40 строк! И это на примитивных паттернах! Что будет при их уложнении?

Развитие кода
Если нам понадобиться добавить новую операцию обработки кода мне будет достаточно создать новый метод, а тебе придется лазить по всем классам и добавлять в каждый из них по фукнции.
Если прийдется добавить новую ветку AST, то тебе прийдется добавить один класс и реализовать в нем по методу для каждого метода обработки, а мне добавить в каждый метод обработки по записи. Причем компилятор сам подксажет где это нужно сделать.

Если для тебя вывод еще не очевиден, то я уже даже и не знаю что саазать.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.