Функциональное программирование в Nemerle
От: Чистяков Влад (VladD2) Российская Империя www.nemerle.org
Дата: 03.03.07 17:23
Оценка: 1315 (27) +1 -1
Статья:
Функциональное программирование в Nemerle
Автор(ы): Чистяков Влад (VladD2)
Дата: 03.03.2007
Язык программирования Nemerle заинтересовал многих в первую очередь своей мощнейшей подсистемой мак-росов. Однако и без них Nemerle предоставляет ряд су-щественных улучшений по сравнению с традиционными, императивными языками программирования (такими как Java, C# и C++).
Nemerle, кроме традиционного императивного програм-мирования, поддерживает функциональное программи-рование. Это выражается в наличии конструкций, упро-щающих манипуляцию функциями, построение и анализ сложных структур данных и т.п.
К сожалению, если вы не использовали возможности, присущие функциональным языкам ранее, то вам будет трудно оценить, насколько Nemerle может оказаться вам полезным в реальной повседневной работе. Данная статья призвана в неформальной форме продемонс-трировать это.


Авторы:
Чистяков Влад (VladD2)

Аннотация:
Язык программирования Nemerle заинтересовал многих в первую очередь своей мощнейшей подсистемой макросов. Однако и без них Nemerle предоставляет ряд существенных улучшений по сравнению с традиционными, императивными языками программирования (такими как Java, C# и C++).
Nemerle, кроме традиционного императивного программирования, поддерживает функциональное программирование. Это выражается в наличии конструкций, упрощающих манипуляцию функциями, построение и анализ сложных структур данных и т.п.
К сожалению, если вы не использовали возможности, присущие функциональным языкам ранее, то вам будет трудно оценить, насколько Nemerle может оказаться вам полезным в реальной повседневной работе. Данная статья призвана в неформальной форме продемонстрировать это.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[15]: Функциональное программирование в Nemerle
От: WolfHound  
Дата: 22.05.07 08:59
Оценка: +1 :))) :))
Здравствуйте, konsoletyper, Вы писали:

K>PS: модераторы, куда вы смотрите. Это же явная провокация.

А нам пофлеймить охота.

K>Не сомневаюсь, что это очередное воплощение Kolhoz/GNU Zaurus. Баньте его к чёртовой матери!

Это точно не Колхоз. Колхоз гораздо умнее.
И уж точно Колхоз не станет защищать C#. Про C# Колхоз скорее скажет что-то типа: "Недоязычек для быдлокодеров."
... << RSDN@Home 1.2.0 alpha rev. 673>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[6]: Функциональное программирование в Nemerle
От: VladD2 Российская Империя www.nemerle.org
Дата: 15.05.07 21:24
Оценка: 26 (4) +1
Здравствуйте, <Аноним>, Вы писали:

А>Не мог вечером зайти в форум, какая-то ошибка, связанная с Dictionary Key, поэтому вечером писал по-памяти, что прочитал с утра, так что требования не соблюдены точно, но достаточно изоморфны.


Ладно, не важно. Главное, что ты теперь сможешь оценить альтернативное решение.

А>150 строк, пока в c# не разочаровался.


Ну, что же... неплохой результат. А сколько тебе потребовалось времени на изменения?

Ну, а теперь решение на вариантах и паттерн-матчинге:
using System;
using System.Console;
using Nemerle.Utility;
using Expr;

public variant Expr
{
  | Literal { value : double; }
  | Call    { name  : string; parms : list[Expr]; }
  | Plus    { expr1 : Expr;   expr2 : Expr; }
  | Minus   { expr1 : Expr;   expr2 : Expr; }
  | Mul     { expr1 : Expr;   expr2 : Expr; }
  | Div     { expr1 : Expr;   expr2 : Expr; }
  
  public override ToString() : string
  {
    match (this)
    {
      | Literal(value)    => value.ToString()
      | Call(name, parms) => $"$name(..$parms)"
      | Plus(e1, e2) with op = "+" | Minus(e1, e2) with op = "-" 
      | Mul (e1, e2) with op = "*" | Div  (e1, e2) with op = "/" 
                          => $"$e1 $op $e2"
    }
  }

  public Eval() : double
  {
    match (this)
    {
      | Literal(value)            => value
      | Plus (e1, e2)             => e1.Eval() + e2.Eval()
      | Minus(e1, e2)             => e1.Eval() - e2.Eval()
      | Mul  (e1, e2)             => e1.Eval() * e2.Eval()
      | Div  (e1, e2)             => e1.Eval() / e2.Eval()
      | Call("max", [arg1, arg2]) => Math.Max(arg1.Eval(), arg2.Eval())
      | Call("min", [arg1, arg2]) => Math.Min(arg1.Eval(), arg2.Eval())
      | Call("foo", [arg1])       => arg1.Eval() // добавили поддержку фунции foo() с одним параметром
      | Call(_, _)   => throw InvalidOperationException(this.ToString());
    }
  }

  public Convert(transform : Expr -> Expr) : Expr // добавили поддержку трансформации выражений
  {
    def res = transform(this);
    match (res)
    {
      | Literal           => res
      | Plus (e1, e2)     => Plus (e1.Convert(transform), e2.Convert(transform))
      | Minus(e1, e2)     => Minus(e1.Convert(transform), e2.Convert(transform))
      | Mul  (e1, e2)     => Mul  (e1.Convert(transform), e2.Convert(transform))
      | Div  (e1, e2)     => Div  (e1.Convert(transform), e2.Convert(transform))
      | Call(name, parms) => Call(name, parms.Map(_.Convert(transform)))
    }
  }
}

module Program
{
  Main() : void
  {
    def expr = Mul(Plus(Literal(1.23), Call("max", [Literal(1), Literal(2)])), Literal(1));
    WriteLine("До трансформации");
    WriteLine($"Expression '$expr' = $(expr.Eval())");

    def expr = expr.Convert(fun(e : Expr) { | Mul(x, Literal(1.0)) => x | _ => e });
    WriteLine("После трансформации");
    WriteLine($"Expression '$expr' = $(expr.Eval())");
    WriteLine("..."); _ = ReadLine();
  }
}


Итого 70 строк. И вряд ли кто-то будет спорить, что они намного лучше читаются.

Причем, заметь, я не менял весь код а добавил всего два фрагмента. Фнукцию Convert:
public Convert(transform : Expr -> Expr) : Expr // добавили поддержку трансформации выражений
{
    def res = transform(this);
    match (res)
    {
        | Literal           => res
        | Plus (e1, e2)     => Plus (e1.Convert(transform), e2.Convert(transform))
        | Minus(e1, e2)     => Minus(e1.Convert(transform), e2.Convert(transform))
        | Mul  (e1, e2)     => Mul  (e1.Convert(transform), e2.Convert(transform))
        | Div  (e1, e2)     => Div  (e1.Convert(transform), e2.Convert(transform))
        | Call(name, parms) => Call(name, parms.Map(_.Convert(transform)))
    }
}

и одну строчку в функцию Eval() чтобы добавить обработку функции foo().


Теперь давай проанализируем что получилось.
К каждому классу иерархии был добавлен соврешенно метод RemoveOneParameterMin(). Он увеличил код и сделал его плохо читаемым. К тому же RemoveOneParameterMin не универсален, а в исходном задании было сказано о том, что требуется универсальное решение, а не для конкретного случая.
Не выполнено по сути и задие с добавлением фунций. Ведь у тебя количество параметров не контролируется.

Теперь можно продолжить наши упраженния. Сколько тебе потребуется времени и сил чтобы добавить еще две оптимизирующие трансформации — заменять выражение max(константа, константа) на значение большей из констант. И соответственно min(константа, константа), меньшей? Мне — пол минуты. Я просто добавлю пару образцов и все. Вот измененный код метода Main() делающий эти оптимизации:
module Program
{
  Main() : void
  {
    def expr = Mul(Plus(Literal(1.23), Call("max", [Literal(1), Literal(2)])), Literal(1));
    WriteLine("До трансформации");
    WriteLine($"Expression '$expr' = $(expr.Eval())");

    def expr = expr.Convert(fun(e : Expr) { 
      | 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 });
    WriteLine("После трансформации");
    WriteLine($"Expression '$expr' = $(expr.Eval())");
    WriteLine("..."); _ = ReadLine();
  }
}

Консольный вывод:
До трансформации
Expression '1.23 + max(1, 2) * 1' = 3.23
После трансформации
Expression '1.23 + 2' = 3.23
...

Заметь, по сути мне нужно было добавить две строки. Тебе же прийдется еще раз менять дизайн всего приложения.
С Посетителем код у тебя может и был бы несколько больше, но все же не пришлось бы каждый раз курочить все классы ради подобных вещей.
Ну, и естественно, что без паттерн-матчинга как бы ты не извивался, но твой код все равно будет больше и непонятнее.
И знаешь почему? Потому ты говоришь компилятору "как надо делать", а я "что надо делать".
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[10]: Функциональное программирование в Nemerle
От: lonli Беларусь  
Дата: 16.05.07 10:54
Оценка: :))) :)
Здравствуйте, VladD2, Вы писали:

VD>Вот только все это делается паттерн-матчингом намного лучше.


Блин я в нем попробовал после пива разобраться. После часа безуспешных попыток вспомнил как туземцы съедали печень и сердце, чтобы получить силу. VladD2, я хочу съесть твой моск
Цинизм ненавижу за его общедоступность. ©Ф.Раневская
Re[16]: Функциональное программирование в Nemerle
От: Аноним  
Дата: 20.05.07 14:21
Оценка: -2 :))
Здравствуйте, konsoletyper, Вы писали:

K>Здравствуйте, <Аноним>, Вы писали:


K>Обратили-обратили. Даже минус поставили.


K>Всё потому, что ты даже не удосужился понять, что такое паттерн-матчинг.

Чувствую, я понял паттерн матчинг гораздо лучше многих приверженцев Nemerle, раз смог привести уже несколько более или менее соответствующих ему аналогов на C#.

K>Кстати, на неконструктивные замечания я отвечать не намерен.

Не умеете, пока, понимаю. Впрочем тут ничего особо сложного, смотрите хотя бы как ловко я отвечаю на неконструктив, старательно сводя его на конструктив.

Вот хотя бы в данном сообщении:

Мне сообщили — "не удосужился понять нечто". Явный неконструктив.
А что вообще значит понимание? Если человек только заучил определение, то это еще не понимание. Нужно рассказать другими словами, привести аналоги из иных систем.
Вот я и ответил, не просто, что "понял нечто", что было бы не более конструктивно, чем исходное замечание, хотя и в этом случае я имел бы моральное право привести неконструктив в ответ на конструктив (око за око), однако я также пояснил как убедиться, что действительно "понял нечто".
Re[3]: Функциональное программирование в Nemerle
От: Аноним  
Дата: 29.05.07 20:48
Оценка: :))) :)
Здравствуйте, rameel, Вы писали:

R>

Доктор, я слепой. Денег не вижу. (с)

Рисование денег, оставлено в качестве упражнения.
Variant<> сделать совсем легко, а вот Pattern<> сильно потяжелее.
Иногда я даже удивляюсь, что смог его сделать.
Re[5]: Функциональное программирование в Nemerle
От: anonym469  
Дата: 31.05.07 16:38
Оценка: -4
Здравствуйте, VladD2, Вы писали:

VD>Просто автор "забыл" привести две тонны кода эмулируюих паттерн матчинг.

Тот же автор, также забыл без всяких кавычек привести код, реализующий паттерн матчинг и варианты из компилятора Nemerle.

VD>не мало кода,

Существенного кода пока не более 30 строк. Посмотрим, что будет если мне приведут более сложные образцы.

VD>но он будет еще и тормозным

Это есть, но код пока достаточно прост, а оптимизация производительности делается в последнюю очередь.

VD>и не универсальным.

Достаточно универсален. Это видно по тому, что в Replace передается тип Expr.

VD>Дело в том, что паттерн-матчинг — это не очень тривиальная вещь.

Сильно зависит от грамматики паттерна.

VD>Достичь того же самого эмуляцией невозможно.

Тут отчасти соглашусь, однако напоминаю, что речь шла о пятикратном преимуществе по размеру кода.
А для доказательства эффективности Nemerle и не надо было городить никакой калькулятор, а просто сравнить String.Format("{0}", o) и "$o".

VD>Любое усложнение образцов будет усложнять задачу на порядки.

Пока примеров сложных образцов не увидел.
Re[6]: Функциональное программирование в Nemerle
От: ie Россия http://ziez.blogspot.com/
Дата: 13.06.07 07:56
Оценка: 2 (1) +2
Здравствуйте, Кэр, Вы писали:


Кэр>Мне действительно интересно, как предлагается оформлять следующую логику в Nemerle:

Кэр> Кэр>Как данная логика должна быть оформлена в функциональном стиле? Вопрос скорее всего от малой практики использования того же pattern-matching'а. Но мне как новичку интересно

Pattern-matching тут как-то не к месту. Как-то так:
    public M(s : string, i : int, dt : DateTime) : IList[string]
        requires i > 0                           otherwise throw ArgumentException("i")
        requires dt.Year > 1950 && dt.Year <2010 otherwise throw ArgumentException("dt")
    {
        mutable e = try { E.Parse(typeof (E), s) :> E } catch { _ => E.Unknown }

        List()
    }

Немного подправил форматирование. Мне кажется так оно будет выглядеть лучше.
... << RSDN@Home 1.2.0 alpha rev. 0>>
Превратим окружающую нас среду в воскресенье.
Re[11]: Функциональное программирование в Nemerle
От: Аноним  
Дата: 18.05.07 21:28
Оценка: -2 :)
Здравствуйте, IT, Вы писали:

IT>Здравствуйте, <Аноним>, Вы писали:


IT>Не сможешь, там от силы пять строчек можно добавить для улучшения читабельности. А вот твой код с первого взгляда выглядит как попытка ужать посильнее и впихнуть побольше. Такие вещи таким способом не делаются. Пиши нормально, так чтобы другие глаза не ломали о твои нагромождения кода и твой код, даже больше в строчках, будут читаться гораздо лучше.


Тогда и у меня пять строчек. А свой код я могу еще процентов на 30 (120 строк вместо 160 ) сократить, сохранив читабельность.

using System;
using System.Console;
using Nemerle.Utility;
using Expr;

public variant Expr
{
  | Literal 
    { 
      value : double; 
    }
  | Call    
    { 
        name  : string; 
        parms : list[Expr]; 
    }
  | Plus    
    { 
        expr1 : Expr;   
        expr2 : Expr; 
    }
  | Minus   
    { 
        expr1 : Expr;   
        expr2 : Expr; 
    }
  | Mul     
    { 
        expr1 : Expr;   
        expr2 : Expr; 
    }
  | Div     
    { 
        expr1 : Expr;   
        expr2 : Expr; 
    }
  
  public override ToString() : string
  {
    match (this)
    {
      | Literal(value)    => 
      {
        value.ToString()
      }
      | Call(name, parms) => 
      {
        $"$name(..$parms)"
      }
      | Plus(e1, e2) with op = "+" 
      | Minus(e1, e2) with op = "-" 
      | Mul (e1, e2) with op = "*" 
      | Div  (e1, e2) with op = "/" 
      {
        => $"$e1 $op $e2"
      }
    }
  }

  public Eval() : double
  {
    match (this)
    {
      | Literal(value) => 
      {
        value
      }
      | Plus (e1, e2) => 
      {
        e1.Eval() + e2.Eval()
      }
      | Minus(e1, e2) => 
      {
        e1.Eval() - e2.Eval()
      }
      | Mul  (e1, e2) => 
      {
          e1.Eval() * e2.Eval()
      }
      | Div  (e1, e2) => 
      {
        e1.Eval() / e2.Eval()
      }
      | Call("max", [arg1, arg2]) => 
      {
        Math.Max(arg1.Eval(), arg2.Eval())
      }
      | Call("min", [arg1, arg2]) => 
      {
        Math.Min(arg1.Eval(), arg2.Eval())
      }
      | Call("foo", [arg1]) => 
      {
        arg1.Eval() // добавили поддержку фунции foo() с одним параметром
      }
      | Call(_, _) => 
      {
        throw InvalidOperationException(this.ToString());
      }
    }
  }

  public Convert(transform : Expr -> Expr) : Expr // добавили поддержку трансформации выражений
  {
    def res = transform(this);
    match (res)
    {
      | Literal => 
      {
        res
      }
      | Plus(e1, e2) => 
      {
        Plus(e1.Convert(transform), e2.Convert(transform))
      }
      | Minus(e1, e2) => 
      {
        Minus(e1.Convert(transform), e2.Convert(transform))
      }
      | Mul(e1, e2) => 
      {
        Mul(e1.Convert(transform), e2.Convert(transform))
      }
      | Div(e1, e2) => 
      {
        Div(e1.Convert(transform), e2.Convert(transform))
      }
      | Call(name, parms) => 
      {
        Call(name, parms.Map(_.Convert(transform)))
      }
    }
  }
}

module Program
{
  Main() : void
  {
    def expr = Mul(Plus(Literal(1.23), Call("max", [Literal(1), Literal(2)])), Literal(1));
    WriteLine("До трансформации");
    WriteLine($"Expression '$expr' = $(expr.Eval())");

    def expr = expr.Convert(fun(e : Expr) 
    { 
        | Mul(x, Literal(1.0)) => x 
        | _ => e 
    });
    WriteLine("После трансформации");
    WriteLine($"Expression '$expr' = $(expr.Eval())");
    WriteLine("..."); _ = ReadLine();
  }
}
Re[14]: Функциональное программирование в Nemerle
От: Аноним  
Дата: 19.05.07 20:21
Оценка: -1 :))
Здравствуйте, VladD2, Вы писали:

VD>Здравствуйте, IT, Вы писали:


VD>Собственно именно это и происхордит на протяжении всего разговора с Аноним 150. Демонстрация упертости. Бессмысленной и беспощадной.

Я правильно понимаю, что вы решили не замечать реализацию паттерн матчинга в C# и быстренько свернуть разговор.
Я, конечно, конкретный код реализации матчинга не привел, хотя он у меня и есть, а привел пример использования.
Re[12]: Функциональное программирование в Nemerle
От: WolfHound  
Дата: 21.05.07 19:16
Оценка: +3
Здравствуйте, <Аноним>, Вы писали:

VD>>и их не надо искть по туче классов.

А>Считаю, что код надо хранить поближе к данным, которые он обрабатывает.
Это догма. Догмы до добра не доводят.
Иногда это так. Иногда иначе.
В случае с АСТ однозначно иначе.

VD>>И что будет? Будет такое же 2-5 кратное упрощение работы.

А>Гм, ну как "protected override Expr Convert(Converter converter)" сократится до пары нажатий, я вижу, а где intellisense также сократит код на Nemerle не вижу.
А>Что тут среда подсказать может? "| Plus (e1, e2) => Plus (e1.Convert(transform), e2.Convert(transform))" Ну параметры, так она и для C# подскажет.
Ну про то что тебе еще надо написать
return converter(new Plus(first.Convert(converter), second.Convert(converter)));
ты как обыно забыл...
Вот только тут собрались флеймеры со стажем и так просто нас не провести...

А>Хорошо смеется тот кто смеется последним. Народная мудрость.

Нет. Хорошо смеется тот кто смется как сферическая лошадь в вакууме.

VD>>Он верно работал с самого начала.

А>А поправка Wolfhaund? Код, работал не правильно.
Мелкая бага. Заметь поправка не изменила колличество строк.

VD>>С чем? Это как раз тот случай когда ты губо попираешь принципы инкапсуляции. Eval() должен вычислять, а не возвращать значение. Испоьзование частнрых знаний, о том, что для некоторого типа Eval() реализован так, что может заменить эксессор свойства как раз и является нарушением инкапсуляции, так как ты опирашся на знания о реализации абстрактного метода.

А>Продолжаю оставаться несогласным. <<< Это пример неконструктива.
Типа тут гдето от тебя есть конструктив? Извини не вижу.

А>Легкость к изменениям программы, а не взглядов. Они впрочем у меня, тоже широкие.

Легкость это полное переписывание? Ну да когда 200-300 строк то переписать действительно легко, а когда больше...

А>А я не про методы, я про классы. В иерархию добавляется новый класс, в нем реализуется метод для посетителя. Но в самом посетителе, например для представления в виде строки, не добавляется проверка на новый класс. Ошибка вылетает только во время выполнения. Как, кстати, и в Nemerle в некоторых случаях.

Ясно. С тем как реализуются посетители не знаком.
Объясняю для тех кто не знает как реализуют посетитель:
interface IVisiter
{
    void accept(A a);
    void accept(B b);
}
interface IVisitable
{
    void visit(IVisiter visiter);
}
class A : IVisitable
{
    public void visit(IVisiter visiter)
    {
        visiter.accept(this);
    }
}
class B : IVisitable
{
    public void visit(IVisiter visiter)
    {
        visiter.accept(this);
    }
}
class ToStringVisiter : IVisiter
{
    void accept(A a)
    {
    ...
    }
    
    void accept(B b)
    {
    ...
    }
}
class EvalVisiter : IVisiter
{
    void accept(A a)
    {
    ...
    }

    void accept(B b)
    {
    ...
    }
}
class SomeElseVisiter : IVisiter
{
    void accept(A a)
    {
    ...
    }

    void accept(B b)
    {
    ...
    }
}

А теперь внимание вопрос:
Скомпилируется ли программа если добавить класс:
class C : IVisitable
{
    public void visit(IVisiter visiter)
    {
        visiter.accept(this);
    }
}


VD>>А вот этот код
Автор:
Дата: 17.05.07
не твой ли? Смотри как от полных имен не осталось и следа! Даже Literal был в совершенно не очевидный Lit переименован. Это тоже, так сказать, проявление широты взглядов?

А>Немерлисты, научили меня плохому.
И где в коде Влада неуместные сокращения?

А>Гм, не я понимаю, встречаются длинные строки, но чтобы все были 150 символьные? Против трех строк не против, но как уже говорил предлагаю тогда считать размер кода без ведущих пробелов или количество нажатий в Visual Studio (это впрочем тяжело подсчитать)

Код читают чаще чем пишут. Следовательно код должен легко читаться так что твои сравнения без ведущих пробелов и тп просто не имеют отношения к жизни.

А>А у меня есть мнение, что не одна строка на Nemerle, а четыре,

А у меня есть мнение что при правильном форматирование не 7 строк на C#, а 22
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)));
    }
}


А>только они размазаны по коду. Вот глаза-то придется поломать

Не размазаны, а сгрупированны по действию. Но не по объекту.
Просто другой принцип группировки. Иногда (например в данном случае) болие предпочтительный.

А>
А>| Minus { expr1 : Expr;   expr2 : Expr; }
А>| Minus(e1, e2) with op = "-" 
А>| Minus(e1, e2) => e1.Eval() - e2.Eval()
А>| Minus(e1, e2) => transform(Minus(e1.Convert(transform), e2.Convert(transform)))
А>

А>2 * 4 > 7
Почему 4 понятно, а вот почему 2 * 4 уже нет.

А>Также сопоставление претендует на универсальность и немного громоздко. А можно упростить до:

1)У Влада было так
| Call("max", [Literal(x), Literal(y)]) => Literal(Math.Max(x, y))


2)Попробуй написать аналог этого
| Call("max", [Mul(Literal(x), Literal(m)), Div(Literal(y), Literal(d))]) => Literal(Math.Max(x * m, y / d))
... << RSDN@Home 1.2.0 alpha rev. 673>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[17]: Функциональное программирование в Nemerle
От: Аноним  
Дата: 23.05.07 06:58
Оценка: +1 -1 :)
Здравствуйте, konsoletyper, Вы писали:

K>Здравствуйте, <Аноним>, Вы писали:


А>>Спорить с вами konsoletyper, иногда все равно, что отнимать конфету у ребенка, слишком легко.


K>А вот твои "вы" воспринимаются как ироничное снисхождение, попытка выставить себя интеллигентом.

Продолжу неконструктивно обращаться на вы. Кстати, что мешает, столь же иронично снисходительно отвечать и мне?

K>А то вона как какой-нибудь 15-летний молокосос начитается твоих бредней и будет потом всю жизнь Nemerle ненавидеть. А вдруг из него лет через 10-15 вышел бы крутой спец по ФЯ?

Да ну, если одной ветки от Анонима достаточно для дискредитации Nemerle и ФЯ, значит язык и сам подход слабые.
Я, кстати, так не считаю.

K>Нет, либо тебя надо банить с полным отсечением ветки, либо дискредитировать. Правда, последнее вряд ли получится

Спасибо за похвалу.

K>Да какой компилятор они там пишут? Так, поделки. И то, компилятор — это в лучшем случае. А так — интерпретатор какого-нибудь недопаскаля. Да и пишут они по старинке на каком нибудь C++.


K>Это я распознаю как уход от ответа. Вместо ответа на вопрос начинаются уточнения "что конкретно имели в виду?". Так играть можно до бесконечности. Хотя суть вопроса была всем ясна — тут высшей математики. Так что я делаю единственный возможный вывод — ты полный профан в плане написания компиляторов. Так что в таком споре:

Это был ответ в стиле, что если не указано, какого рода компилятор имеется ввиду, то я их написал сотни.

K>можно смело доверять опыту Wolfhound'у, а не тебе. Так же можно доверять опыту, например, разработчиков Nemerle, которые до него спроектировали не один язык и написали компиляторы для них.

Wolfhound в своей защите не участвует, поэтому вам для начала, надо было бы указать какие компиляторы он разработал.
Что касается разработчиков Nemerle, то легко скачать исходный код Nemerle. И что мы там видим, например, в AST.n?
И варианты разносят на несколько строк, и данные инкапсулируют в классах. Так что многие разработчики Nemerle за меня в этих двух вопросах.
Версия Nemerle майская если что.

K>У тебя отсутствует код сопоставления с образцом. В версии для Nemerle он присуствует. Будь добр, добавь к своему коду сопоставление с образцом и покажи, что ты набираешь.

Я набираю over и выбираю какой метод переопределить. Описание метода вставляется по нажатию enter.

K>>>И вообще, надо не забывать, что код труднее читать, чем писать. Я на сниппетах тебе такого нагородить на brainfuck могу, что ты потом всю оставшуюся жизнь в нём разбираться будешь.

K>Вот ты как раз и даешь пример трудно понимаемого кода на C#.
Мысль то была в другом. Да код чаще читают, чем пишут, но разве код при написании и при чтении должен совпадать?
Вот уже приводилось, что набирается с клавиатуры при использовании intellisence.
ret con(new Pl(fir.(con), sec.(con));

Если ввести этот текст непосредственно в notepad разве можно легко понять что имеется ввиду? Особенно, через некоторое время.
Тем не менее в среде с intellisence он трансформируется во вполне читаемый код.
Также например и с вводом тел метода в одну строчку, после написания можно его автоматически отформатировать в нужный вид.
Мало, что ли форматтеров доступно...


K>Нет уж, согласно твоему подходу должно быть так:

K>
K>if (cond1)
K>{

K>    body
    
K>}
K>

Согласно моему? А где я приводил такой код?

K>>>Кстати, допустимо всё это записать и так:

K>>>Так что твоя арифметика никому ничего не доказывает.
А>>Ситуация обратная. Сначала мне приводят форматирование на C# (например с множеством пустых строк), а я просто применяю примерно такой же стиль к Nemerle (что уже оказывается особо тяжким преступлением). Стили же приведенных вами фрагментов практически диаметрально противоположны.

K>Вот именно, что ты применяешь такой стиль формально. Фактически, ты нарушаешь своим подходом читадельность.

Понял, когда форматируют мой код на C# поступают неформально, когда я форматирую также код на Nemerle, я поступаю формально.
Хотя если посмотреть на код AST.n можно ужаснуться количеству формалистов, среди разработчиков Nemerle.

K>Про гениальность никто не говорил.

Но про невменяемость-то говорили? А что это как не сумасшествие, а гениальность бывает идет с ним рука об руку.

K>Это твои собственные домыслы. На лицо неограниченное самомнение и мания величия.

Гм? Я, кажется, отказался от приписываемой мне гениальности, где же тут неограниченное самомнение и мания величия?

K>У тебя уже неоднократно просили привети код метода Match, а ты этого не сделал, как всегда, ловко уйдя от ответа.

Как я уже писал, этот код помогает мне ощущать интеллектуальное превосходство.
Впрочем, может быть сделаю ASP.NET приложение, в котором можно будет вводить выражение, образец для сопоставления и выводить итог сопоставления.

K>А это значит только одно — никакого паттерн-матчинга ты не изобрёл.

А я где-то говорил, что изобрел? Отнюдь, просто реализовал.

K>В том числе, твоё утверждение про то, что ты понял паттерн-матчинг лучше нас

Пока у меня есть к этому основания. Пока тут ключевое слово. Вполне может быть, что меня опровергнут, пока же опровержения очень слабы типа
K> — откровенная ложь.

K>И про паттерн-матчинг я тебе объяснять не собираюсь. Что это такое, и так прекрасно описано в статье.

Так ли прекрасно? Я волне допускаю, что он нечто более сильное. То же, что описано в статье и на C# доступно.

K>Да, все мы идиоты, а один ты Великий!

Почему один? Я же писал, что многие могут восстановить.

K>Куда уж нам, ничтожным, до вас, до изобретателей паттерн-матчинга для C#.

Какой же изобретатель? Скромный реализатор.
Re: Функциональное программирование в Nemerle
От: Кэр  
Дата: 30.05.07 13:43
Оценка: -2 :)
День добрый,

здесь в коде выделены жирным элементы, которые призваны улучшить читаемость кода:

def isBraceMatch()
{
  def lex = engine.GetLexer(_source);
    // без new данный вызов легко спутать с вызовом метода,
    // а различать вызов метода и конструктора нужно по многим причинам
  def stack = new Stack();
  stack.Push(Token.EndOfFile());

    // очень несложно поставить возвращаемый тип данных, тем более,
    // что меняться в будующем он вряд ли будет, а читаемость кода резко
    // возрастает - сразу понятно, как именно нужно относится к содержимому
  def scan(toc : Token) : bool
  {
        // это общее возражение на бесповоротный отказ от return - для конечного 
        // результата в стэке рекурсии очень полезно оставить флажок "а здесь
        // мы начали раскручивать стэк в обратном направлении"
    | EndOfFile           => return stack.Count == 1

    | BeginBrace             // {
    | BeginRound             // (
    | BeginSquare            // [
    | BeginQuote          => // <[
      stack.Push(toc);
      scan(lex.GetToken())

    | EndBrace            => check(_ is Token.BeginBrace)  // }
    | EndRound            => check(_ is Token.BeginRound)  // )
    | EndSquare           => check(_ is Token.BeginSquare) // ]
    | EndQuote            => check(_ is Token.BeginQuote)  // ]>
    | _                   => scan(lex.GetToken());
  }
  and check(predicate)
  {
      if (stack.Count > 0 && predicate(stack.Peek()))
      {
        stack.RemoveLast();
                // честное слово, очень многие люди оценят здесь return :)
        return scan(lex.GetToken())
      }
      else
        return false
  }

    // и здесь тоже - просто как флаг говорящий, что работа функции
    // официально закончена
  return scan(lex.GetToken());
}


без претензий на самое объективное мнение, но с твердой субъективной позицией

p.s. статья — отличная
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[3]: Функциональное программирование в Nemerle
От: Кэр  
Дата: 31.05.07 11:54
Оценка: -1 :))
Здравствуйте, VladD2, Вы писали:

VD>От догм и предрассудков лучше избавляться.


Угу, то что ты подписываешь меня на догматическое мышление я уже понял В рассуждениях на самом деле не было ни одного отправного пункта — а вот в других языках так поэтому надо делать именно так. Рассуждения начинаются с нуля. Опровергай их тоже с нуля, не вешая на меня ярлыки Вполне допускаю, что могу быть неправ.

VD>Кстати, есть один вопрос:

VD>
VD>    | EndOfFile           => return stack.Count == 1
VD>        ...
VD>    | EndRound            => check(_ is Token.BeginRound)  // )
VD>

VD>А почему в первой строчке return понадобился, а во второй нет?

Как раз по тем причинам, что я указывал выше — return обозначает то место, где начнет разворачиваться стэк вызовов функций.
Такой return
VD>
VD>    | EndRound            => return check(_ is Token.BeginRound)  // )
VD>

лишний. Здесь просто вычисления идут вглубь по стэку вызова.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re: небольшие правки
От: Иванков Дмитрий Россия  
Дата: 09.05.07 07:29
Оценка: 35 (2)
ЧВV> с незаменяемыми полями
вероятно все же неизменяемыми, ... хотя

ЧВV> отряд не заменит потери бойца

так даже больше нравится, но вроде бы по контексту должна быть классика

ЧВV> Так, все поля Variant Option ... обязаны быть публичными, и по умолчанию являются изменяемыми

опечатка, "не" пропущено

ЧВV> но в основном их применение обычно обосновано и происходит из-за того, что программист просто пока не привык использовать неизменяемые структуры данных.

аналогично

ЧВV> Если функция начинается с выражения match, ...

все же точнее будет "Если тело функции состоит из выражения match, ..."
Re[3]: Функциональное программирование в Nemerle
От: konsoletyper Россия https://github.com/konsoletyper
Дата: 30.05.07 16:01
Оценка: 35 (1) +1
Здравствуйте, Кэр, Вы писали:

Кэр>konsoletyper, смелее, можно словами


OK.

Про new тебе уже сказали. Кроме того, хочу добавить, что и в C# можно банально объявить конструктор как protected и заставлять создавать объекты через статический метод, так что создание объекта — это не прерогатива одного лишь конструктора. Да и понятие "создание объекта" — вещь весьма условная и работающая только при ортодоксальном ООП. Вот здесь
Автор: konsoletyper
Дата: 17.05.07
я немного пофлеймил по этому поводу. В частности, в "функциональных" вещах типа Compiler-compiler
Автор: konsoletyper
Дата: 31.03.07
удобнее рассматривать множество объектов как нечто метофизическое, а конструктор — как функцию, дающую доступ к одному из объектов множества. Можно, в принципе, и в чём-то вроде GUI так же относиться ко всему (тогда конструктор кроме этого добавляет к объекту некий неопределяемый "identity"), но, ИМХО, это неудобно. Вообще, использовать new или нет — дело привычки, и, поверь, когда привыкнешь не писать new, обратно отвыкнуть будет труднее.

По поводу : bool. Nemerle тем и славен, что у него есть вывод типов. Однако, это не сказывается на читабельности, т.к. вывод типов на уровне методов отключён. А узнать тип возвращаемого значения достаточно просто — надо глянуть на возвращаемое значение. Кстати, как человек, имеющий опыт программирования на питоне и пхп, могу сказать, что быстро оценил эту полезную фичу Nemerle.

По поводу return. Важно понимать, что в Nemerle ты не можешь что-то сделать и вернуть. Ты можешь просто описать функцию, которая что-то возвращает. Всякие match и if — это не операторы, а выражения, т.е. любая из ветвей этих конструкция должна содержать некоторое выражение. Это выражение вычисляется. В частности выражение { a; b; ...; c } означает, что перед вычислением данного выражения исполняются (вычисляются) a, b и ..., а потом вычисляется c, которое и есть результат вычисления всего выражения. Это похоже на begin в scheme.
... << RSDN@Home 1.2.0 alpha rev. 672>>
Re[6]: Функциональное программирование в Nemerle
От: ie Россия http://ziez.blogspot.com/
Дата: 01.06.07 03:58
Оценка: 4 (1) +1
Здравствуйте, Кэр, Вы писали:

Кэр>>>И вообще если уж говорить про принципиальные отличия: внутри обычного метода можно использовать вызовы виртуальных методов, внутри конструктора нельзя — так что думать о них как о близнецах-братьях очень не рекомендуется.


Ты ИМХО сам запутался в своих мыслях, а может я просто не могу понять их ход
Поэтому давай по порядку, с каким из этих утверждений ты не согласен и почему?
1. Думать о них как о близнецах-братьях не стоит пишущему конструктор.
2. Думать о них как о близнецах-братьях можно использующему конструктор.

VD>>1. Ты глубого заблуждаешся. В дотнете без проблем можно вызвать виртуальные методы из констроторов и финалайзеров.

Кэр>Как ты думаешь, что произойдет, если создать экземпляр Derived класса?
Кэр>
Кэр>public abstract class Base
Кэр>    {
Кэр>        public Base()
Кэр>        {
Кэр>            Log("Instance created");
Кэр>        }

Кэр>        public abstract void Log(string message);
Кэр>    }

Кэр>    public class Derived : Base
Кэр>    {
Кэр>        public Derived()
Кэр>        {
Кэр>             //_logMessages = new StringBuilder();
Кэр>        }

Кэр>        private StringBuilder _logMessages = new StringBuilder();

Кэр>        public override void Log(string message)
Кэр>        {
Кэр>            _logMessages.Append(message);
Кэр>            Console.WriteLine(message);
Кэр>        }
Кэр>    }
Кэр>


1. Это не запрещает использовать вызовы виртуальных методов, просто делать это надо с осторожностью и пониманием дела. И РеШарпер подсвечивая виртуальные вызовы в конструкторе, делает очень правильно, заставляя еще и еще обратить внимание на источник возможных проблем.
2. Похожий код я иногда даю людям на собеседовании. И прошу человека выявить проблему и исправить ее. Причем, ожидаю не то, что он избавится от виртуального вызова в конструкторе, а сделает те действия, что я выделил выше.

VD>>2. А это уже никого не трогает. Точнее трогает того кто создает этот метод/конструктор. Ты работаешь с черным ящиком. Собственно это и есть инкапсуляция.

Кэр>С этим не спорю. Я говорил о том, что в целом нельзя относится к конструктору и к методу, как к одному и тому же.

Ну нет же, споришь. Если я пишу конструктор, то да, я должен отновится к нему по другому, если я его использую, то какая мне разница — конструктор это, банальный метод или локальная функция. NRE ведь не только в конструкторах с виртуальными методами может вылитеть.
... << RSDN@Home 1.2.0 alpha rev. 0>>
Превратим окружающую нас среду в воскресенье.
Re[4]: Функциональное программирование в Nemerle
От: Кэр  
Дата: 31.05.07 01:12
Оценка: 1 (1) +1
Здравствуйте, konsoletyper, Вы писали:

K>Кроме того, хочу добавить, что и в C# можно банально объявить конструктор как protected и заставлять создавать объекты через статический метод, так что создание объекта — это не прерогатива одного лишь конструктора.

А я между прочим этого и не утверждал.

K>Да и понятие "создание объекта" — вещь весьма условная и работающая только при ортодоксальном ООП. Вот здесь
Автор: konsoletyper
Дата: 17.05.07
я немного пофлеймил по этому поводу. В частности, в "функциональных" вещах типа Compiler-compiler
Автор: konsoletyper
Дата: 31.03.07
удобнее рассматривать множество объектов как нечто метофизическое, а конструктор — как функцию, дающую доступ к одному из объектов множества. Можно, в принципе, и в чём-то вроде GUI так же относиться ко всему (тогда конструктор кроме этого добавляет к объекту некий неопределяемый "identity"), но, ИМХО, это неудобно. Вообще, использовать new или нет — дело привычки, и, поверь, когда привыкнешь не писать new, обратно отвыкнуть будет труднее.

Повторюсь — я не осозновал, что в Nemerle конструктор не обязательно возвращает новый объект. С учетом специфики работы конструктора в .Net (в частности в силу отсутвия его собрата — деструктора) это может быть и вполне оправдано. Но опять же — это радикальное отличие от остальных .Net языков. Так что этому пожалуй стоит уделить особое внимание для "начинающих на Nemerle".

K>По поводу : bool. Nemerle тем и славен, что у него есть вывод типов. Однако, это не сказывается на читабельности, т.к. вывод типов на уровне методов отключён. А узнать тип возвращаемого значения достаточно просто — надо глянуть на возвращаемое значение.

Вот именно, что нужно вглядываться в контекст, чтобы получить принципиальное знание. Если бы функция была чуть сложнее — например, она бы делегировала все исходы другим функциям — пришлось бы смотреть, что возрвращают те функции. Совершенно лишний шаг при чтении кода. При том, что по сути — от умолчания : bool код ничего не выигрывает.

K>По поводу return. Важно понимать, что в Nemerle ты не можешь что-то сделать и вернуть. Ты можешь просто описать функцию, которая что-то возвращает. Всякие match и if — это не операторы, а выражения, т.е. любая из ветвей этих конструкция должна содержать некоторое выражение. Это выражение вычисляется. В частности выражение { a; b; ...; c } означает, что перед вычислением данного выражения исполняются (вычисляются) a, b и ..., а потом вычисляется c, которое и есть результат вычисления всего выражения. Это похоже на begin в scheme.

Ну и что? Это никак не противоречит тому, что выставления return в том месте, где возращается уже конечное значение (некоторое value-значение или объект) — повышает читабельность кода.
Re[5]: Функциональное программирование в Nemerle
От: Аноним  
Дата: 15.05.07 19:16
Оценка: :))
Здравствуйте, VladD2, Вы писали:

VD>Понимаю, что мышление человека инерно. По этому предлагаю начать с малого. Давай расширим оба примера поддержкой фунций с 3 и 5 параметрами. Причем на этот раз ты продемонстриуешь свое решение первым.


VD>Вторая здачка будет интереснее. Произвольная трансформация выражений. Берем исходное выражение применяем к нему некоторую функцию в параметах которой задем условия трасформации и получаем на выходе трансформированное (оптимизированное выражение). Для простоты, в качестве теста, будем использовать следующую оптимизацию — если выражение преставляет из себя "<любое выражение> * 1", то заменяем его на "<любое выражение>". Причем подразумевается, что это всего лишь один из возможных вариантов замены. Другими словами вызвав код вида:

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

Не мог вечером зайти в форум, какая-то ошибка, связанная с Dictionary Key, поэтому вечером писал по-памяти, что прочитал с утра, так что требования не соблюдены точно, но достаточно изоморфны.

150 строк, пока в c# не разочаровался.

using System;
using System.Text;
using System.Collections;
using System.Collections.Generic;

abstract class Expression
{
  public abstract double Eval();
  public abstract override string ToString();
  public abstract void RemoveOneParameterMin(ref Expression expression);
}

class Literal : Expression
{
  double value;
  public Literal(double value) { this.value = value; }
  public override double Eval() { return value; }
  public override string ToString() { return value.ToString(); }
  public override void RemoveOneParameterMin(ref Expression expression) { }
}

abstract class Operation : Expression
{
  protected Expression first, second;
  public Expression First { get { return first; } }
  public Expression Second { get { return second; } }
  public Operation(Expression first, Expression second) 
  { 
    this.first = first;
    this.second = second;
  }
  public override void RemoveOneParameterMin(ref Expression expression)
  {
    first.RemoveOneParameterMin(ref first);
    second.RemoveOneParameterMin(ref second);
  }
}

class Addition : Operation
{
  public Addition(Expression first, Expression second) : base(first, second) { }
  public override double Eval() { return first.Eval() + second.Eval(); }
  public override string ToString() { return first.ToString() + " + " + second.ToString(); }
}

class Subtraction : Operation
{
  public Subtraction(Expression first, Expression second) : base(first, second) { }
  public override double Eval() { return first.Eval() - second.Eval(); }
  public override string ToString() { return first.ToString() + " - " + second.ToString(); }
}

class Multiplication : Operation
{
  public Multiplication(Expression first, Expression second) : base(first, second) { }
  public override double Eval() { return first.Eval() * second.Eval(); }
  public override string ToString() { return first.ToString() + " * " + second.ToString(); }
}

class Division : Operation
{
  public Division(Expression first, Expression second) : base(first, second) { }
  public override double Eval() { return first.Eval() / second.Eval(); }
  public override string ToString() { return first.ToString() + " / " + second.ToString(); }
}

abstract class Call : Expression
{
  protected Expression[] expressions;
  public Expression[] Expressions { get { return expressions; } }
  public Call(params Expression[] expressions) { this.expressions = expressions; }
  protected string Join(string splitter)
  {
    if (expressions.Length == 0) return "";
    StringBuilder stringBuilder = new StringBuilder();
    foreach (Expression expression in expressions)
    {
      stringBuilder.Append(expression.ToString());
      stringBuilder.Append(splitter);
    }
    return stringBuilder.Remove(stringBuilder.Length - splitter.Length, splitter.Length).ToString();
  }
  public override void RemoveOneParameterMin(ref Expression expression)
  {
    for (int index = 0; index < expressions.Length; index++ )
    {
      expression.RemoveOneParameterMin(ref expressions[index]);
    }
  }
}

abstract class AtLeastOneParameterCall : Call
{
  public AtLeastOneParameterCall(Expression first, params Expression[] expressions) : 
    base(AtLeastOneParameterCall.Concat(first, expressions)) { }
  private static Expression[] Concat(Expression first, params Expression[] expressions)
  {
    List<Expression> list = new List<Expression>(expressions);
    list.Insert(0, first);
    return list.ToArray();
  }
  protected delegate void CompareValues(double current, ref double value);
  protected double FindValue(CompareValues compareValues)
  {
    double value = expressions[0].Eval();
    for (int index = 1; index < expressions.Length; index++)
    {
      compareValues(expressions[index].Eval(), ref value);
    }
    return value;
  }
}

class Min : AtLeastOneParameterCall
{
  public Min(Expression first, params Expression[] expressions) : base(first, expressions) { }
  public override string ToString() { return "Min(" + Join(", ") + ")"; }
  public override double Eval() { return FindValue(ChooseMin); }
  private void ChooseMin(double current, ref double value) { if (current < value) value = current; }
  public override void RemoveOneParameterMin(ref Expression expression)
  {
    if (expressions.Length == 1) 
    { 
      expression = expressions[0]; 
    }
    else 
    {
      base.RemoveOneParameterMin(ref expression); 
    }
  }
}

class Max : AtLeastOneParameterCall
{
  public Max(Expression first, params Expression[] expressions) : base(first, expressions) { }
  public override string ToString() { return "Max(" + Join(", ") + ")"; }
  public override double Eval() { return FindValue(ChooseMax); }
  private void ChooseMax(double current, ref double value) { if (current > value) value = current; }
}

public class Program
{
  public static void Main(string[] arguments)
  {
    // Min(1.23, 2.34 + Min(3.45))
    Expression expression = new Min(new Literal(1.23), new Addition(new Literal(2.34), new Min(new Literal(3.45))));
    Console.WriteLine("Expression '{0}' - {1}.", expression.ToString(), expression.Eval());
    expression.RemoveOneParameterMin(ref expression);
    Console.WriteLine("Expression '{0}' - {1}.", expression.ToString(), expression.Eval());
    Console.ReadLine();
  }
}
Re[8]: Функциональное программирование в Nemerle
От: IT Россия linq2db.com
Дата: 17.05.07 17:56
Оценка: +2
Здравствуйте, <Аноним>, Вы писали:

А>Мои 150 выполняют больше работы


Можно мои 2 цента? Спасибо!

Хочешь я твои 150 легко превращу в 300 просто убрав искусственное сжатие кода, предназначенное исключительно для экономии строк?
... << RSDN@Home 1.2.0 alpha rev. 0>>
Если нам не помогут, то мы тоже никого не пощадим.
Re[9]: Функциональное программирование в Nemerle
От: Аноним  
Дата: 18.05.07 21:03
Оценка: -1 :)
Здравствуйте, IT, Вы писали:

IT>Хочешь я твои 150 легко превращу в 300 просто убрав искусственное сжатие кода, предназначенное исключительно для экономии строк?

Главное, не забыть при этом, что я могу аналогичный код на Nemerle легко превратить в 150.
Re[12]: Функциональное программирование в Nemerle
От: IT Россия linq2db.com
Дата: 18.05.07 22:00
Оценка: +2
Здравствуйте, <Аноним>, Вы писали:

А>
А>using System;
А>using System.Console;
А>using Nemerle.Utility;
А>using Expr;

А>public variant Expr
А>{
А>  | Literal 
А>    { 
А>      value : double; 
А>    }
А>  | Call    
А>    { 
А>        name  : string; 
А>        parms : list[Expr]; 
А>    }
А>  | Plus    
А>    { 
А>        expr1 : Expr;   
А>        expr2 : Expr; 
А>    }
А>  | Minus   
А>    { 
А>        expr1 : Expr;   
А>        expr2 : Expr; 
А>    }
А>  | Mul     
А>    { 
А>        expr1 : Expr;   
А>        expr2 : Expr; 
А>    }
А>  | Div     
А>    { 
А>        expr1 : Expr;   
А>        expr2 : Expr; 
А>    }
А>

Здесь ты не добавил читабельности. Здесь ты её убил.

Пожалуйста, не надо считать других за идиотов и демонстрировать упёртость. Твой C# код по читабельности от приведённого Владом даже рядом никогда не стоял. Это может быть не очевидно только человеку, которому истина уже ни к чему, которому главное доказать, не важно что, лишь бы доказать. Это не продуктивно и не конструктивно.
... << RSDN@Home 1.2.0 alpha rev. 0>>
Если нам не помогут, то мы тоже никого не пощадим.
Re[11]: Функциональное программирование в Nemerle
От: Аноним  
Дата: 19.05.07 19:38
Оценка: :))
Здравствуйте, VladD2, Вы писали:

VD>Компилятор отслеживает, что match отлавливает все вариации. Если какой-то вариант не отлавливается выдается предупрждение. Если его прогнорировать и в рантайме появится тако паттерн, то вылетет исключение говорящее, что сопоставление с образцом не удалось. Делать так естественно не стоит. По этому если паттерны не покрывают все вариации, то нужно добвлять паттерн отлавливаеющий все что осталось. В данном случае он отлавливает все ошибки связнаные с неверным числом парметров у фукнции.


А вот и преимущество абстрактных классов.
В моем коде вообще нельзя создать Call с каким угодно количеством параметров, хоть правильным, хоть не правильным.
Похоже быстрота написания иерархии, через варианты в Nemerle влечет за собой необходимость дополнительных проверок да еще и в runtime.
Какие еще проблемы вылезут в дальнейшем, кто знает...
Re[15]: Функциональное программирование в Nemerle
От: Аноним  
Дата: 20.05.07 14:50
Оценка: -2
Здравствуйте, konsoletyper, Вы писали:

K>Здравствуйте, <Аноним>, Вы писали:


K>Отличный пример софистики и демагогии. Нуль конструкрива.

Чувствую, не знаете значения ни демагогии, ни конструктива.
Если под софистикий понимается умение мудро вести спор, то с благодарностью принимаю в свой адрес.

По поводу демагогии:
Демагог прежде всего обращается к широким массам.
То есть речь в таком стиле —
Разработчики! Изучайте Nemerle будете производительнее в работе. А я скромный разработчик Nemerle на службе у разработчиков.
или
Участники форума, свободные люди! Вам на форуме нужна свобода выражать свое мнение. А я буду модератором защищающим свободу на форуме, голосуйте за меня.

Конечно, любое выступление на форуме, можно посчитать демагогическим ибо в потенциале, его могут прочитать очень много людей.
Но нужно ли считать его демагогическим если идет обращение к одному человеку?

По поводу конструктива:

А. Легко доведу код на C# до 300 строк переформатированием еще и читабельность увеличится.
B. Тогда я доведу код на Nemerle до 150.
A. Не сможешь.
B. Вот пожалуйста.
A. Код утратил читабельность.
B. Возможно, но мне не привели пример кода с улучшенной читабельностью на C#.

Кто более конструктивен, если, конечно, вынести за скобки личные симпатии, давнее знакомство, общие деловые интересы и т.д. и т.п. .

K>Ты вообще понимаешь слово "читабельный", или просто издеваешься над собеседниками?

Пригодный к чтению. Естественно, что это не универсальная категория — кто-то легко читает код определенного вида на Perl, кто-то с трудом.
Поэтому необходимы примеры и определенные договоренности.
Как связана краткость кода, с читабельностью кода?
Читабелен ли максимально краткий код?
Краток ли максимально читабельный?
Где границы краткости, при которой начинает падать читабельность?
Где границы читабельности, при которой начинает падать краткость?
И т.д. и т.п.
Я при этом не требовал математически строгого определения, мне достаточно было примера.
Re[15]: Функциональное программирование в Nemerle
От: VladD2 Российская Империя www.nemerle.org
Дата: 22.05.07 22:53
Оценка: +2
Здравствуйте, konsoletyper, Вы писали:

K>PS: модераторы, куда вы смотрите. Это же явная провокация. Не сомневаюсь, что это очередное воплощение Kolhoz/GNU Zaurus. Баньте его к чёртовой матери!


Смотрим сюда. Я уже перестал отвечать этому троллю и забанил его первый IP-шник. Но товаришь похоже лезет или через прокси прошлый IP был 213.221.57.*, а предыдущий, забаненый 85.249.254.*. Правда все из Питера. Так что может просто динамика.

В общем, проще снести все к черту и не обращать внимание на этого тролля.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[20]: Функциональное программирование в Nemerle
От: Sinclair Россия https://github.com/evilguest/
Дата: 24.05.07 03:26
Оценка: +2
Здравствуйте, <Аноним>, Вы писали:

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

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

Предлагаю завязать с оффтопом и троллингом. Или это такая пропаганда Nemerle путем чорного пеара его противников? Здесь в основном народ-то искушенный, так что переливания из пустого в порожнее и попытки сделать вид что "здесь я не нарочно нарушил стандарт форматирования исходников на C#" только забавляют. Не забавляет затянутость этой шутки.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[7]: Функциональное программирование в Nemerle
От: WolfHound  
Дата: 17.05.07 14:07
Оценка: 10 (1)
Здравствуйте, VladD2, Вы писали:

VD>
VD>  public Convert(transform : Expr -> Expr) : Expr // добавили поддержку трансформации выражений
VD>  {
VD>    def res = transform(this);
VD>    match (res)
VD>    {
VD>      | Literal           => res
VD>      | Plus (e1, e2)     => Plus (e1.Convert(transform), e2.Convert(transform))
VD>      | Minus(e1, e2)     => Minus(e1.Convert(transform), e2.Convert(transform))
VD>      | Mul  (e1, e2)     => Mul  (e1.Convert(transform), e2.Convert(transform))
VD>      | Div  (e1, e2)     => Div  (e1.Convert(transform), e2.Convert(transform))
VD>      | Call(name, parms) => Call(name, parms.Map(_.Convert(transform)))
VD>    }
VD>  }

VD>    def expr = expr.Convert(fun(e : Expr) { | Mul(x, Literal(1.0)) => x | _ => e });
VD>

ИМХО у тебя тут ошибочка.

Ибо выражение
Mul(Mul(Literal(5), Literal(1)), Literal(1))

Будет преобразовано в
Mul(Literal(5), Literal(1))

Я бы написал так:
  public Convert(transform : Expr -> Expr) : Expr // добавили поддержку трансформации выражений
  {
    def res = match (this)
    {
      | Literal           => this
      | Plus (e1, e2)     => Plus (e1.Convert(transform), e2.Convert(transform))
      | Minus(e1, e2)     => Minus(e1.Convert(transform), e2.Convert(transform))
      | Mul  (e1, e2)     => Mul  (e1.Convert(transform), e2.Convert(transform))
      | Div  (e1, e2)     => Div  (e1.Convert(transform), e2.Convert(transform))
      | Call(name, parms) => Call(name, parms.Map(_.Convert(transform)))
    }
        transform(res);
  }

Тогда это выражение будет преобразовано в Literal(5)
... << RSDN@Home 1.2.0 alpha rev. 673>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[15]: Функциональное программирование в Nemerle
От: VladD2 Российская Империя www.nemerle.org
Дата: 20.05.07 19:50
Оценка: 3 (1)
Здравствуйте, <Аноним>, Вы писали:

А>Я правильно понимаю, что вы решили не замечать реализацию паттерн матчинга в C# и быстренько свернуть разговор.


Скорее я отныне решил не замечать тебя, потому как имею обширный и печательный опыт общения с упертыми спорщиками, которым познание истины не интересно как класс, а интересен сам процесс спора.

Информации вполне достаточно, остальные, если захотят, разберутся.

А>Я, конечно, конкретный код реализации матчинга не привел


Конечно. Потому и обсуждать нечего.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[5]: Функциональное программирование в Nemerle
От: konsoletyper Россия https://github.com/konsoletyper
Дата: 31.05.07 12:16
Оценка: 2 (1)
Здравствуйте, Кэр, Вы писали:

K>>Да и понятие "создание объекта" — вещь весьма условная и работающая только при ортодоксальном ООП. Вот здесь
Автор: konsoletyper
Дата: 17.05.07
я немного пофлеймил по этому поводу. В частности, в "функциональных" вещах типа Compiler-compiler
Автор: konsoletyper
Дата: 31.03.07
удобнее рассматривать множество объектов как нечто метофизическое, а конструктор — как функцию, дающую доступ к одному из объектов множества. Можно, в принципе, и в чём-то вроде GUI так же относиться ко всему (тогда конструктор кроме этого добавляет к объекту некий неопределяемый "identity"), но, ИМХО, это неудобно. Вообще, использовать new или нет — дело привычки, и, поверь, когда привыкнешь не писать new, обратно отвыкнуть будет труднее.

Кэр>Повторюсь — я не осозновал, что в Nemerle конструктор не обязательно возвращает новый объект. С учетом специфики работы конструктора в .Net (в частности в силу отсутвия его собрата — деструктора) это может быть и вполне оправдано. Но опять же — это радикальное отличие от остальных .Net языков. Так что этому пожалуй стоит уделить особое внимание для "начинающих на Nemerle".

Ну, я сам не особо разбираюсь в нюансах работы компилятора Nemerle. Но дело не в том, что реально возвращается конструктором, а как это значение интерпретируется человеком. Если просто читать программу в "фнукциональном" режиме, то использование new начинает казаться неоправданным.

K>>По поводу : bool. Nemerle тем и славен, что у него есть вывод типов. Однако, это не сказывается на читабельности, т.к. вывод типов на уровне методов отключён. А узнать тип возвращаемого значения достаточно просто — надо глянуть на возвращаемое значение.

Кэр>Вот именно, что нужно вглядываться в контекст, чтобы получить принципиальное знание. Если бы функция была чуть сложнее — например, она бы делегировала все исходы другим функциям — пришлось бы смотреть, что возрвращают те функции. Совершенно лишний шаг при чтении кода. При том, что по сути — от умолчания : bool код ничего не выигрывает.

Да нет, никаких проблем с этим не возникает. Обычно, если грамотно называть функции и переменные, производить декомпозицию, то всё становится более менее очевидным. В худшем случае никто не мешает навиести курсор на функцию и получить хинт. Советую заодно присмотреться к динмически-типизированным языкам вроде PHP и Python, где при правильном проектировании и документировании таких проблем не возникает. Пролемы в них возникают при отладке, а вот в ML-образных языках мы получаем такую же лаконичность и не теряем в удобстве отладки (потенциально).

K>>По поводу return. Важно понимать, что в Nemerle ты не можешь что-то сделать и вернуть. Ты можешь просто описать функцию, которая что-то возвращает. Всякие match и if — это не операторы, а выражения, т.е. любая из ветвей этих конструкция должна содержать некоторое выражение. Это выражение вычисляется. В частности выражение { a; b; ...; c } означает, что перед вычислением данного выражения исполняются (вычисляются) a, b и ..., а потом вычисляется c, которое и есть результат вычисления всего выражения. Это похоже на begin в scheme.

Кэр>Ну и что? Это никак не противоречит тому, что выставления return в том месте, где возращается уже конечное значение (некоторое value-значение или объект) — повышает читабельность кода.

Опять же, значение не возвращается, а вычисляется. И это совершенно разные вещи. Вообще, если ты ещё не сомтрел на Scheme, то советую почитать SICP, там все эти вещи хорошо описаны (ой, сейчас Влад на меня зарычит, но я всё же твёрдо останусь при мнении, что SICP — отличное руководство по ФП для начинающих).

А так попытаюсь сам объяснить. В ИП программа состоит из набора инструкций, которые последовательно друг за другом исполняются. Иногда последовательноть может несколько нарушится (if, break, return, etc), чтобы опять потом продолжиться. Процедура тоже выполняется последовательно, пока не встретится return.

В ФЯ никакой последовательности нет. Например, результат вычисления if или match не обяззательно возвращать из функции, можно присвоить его какой-нибудь переменной. Советую посмотреть в рефлекторе на код, в который разворачиваются if'ы, в которых используются "переменные", объявленные при помощи def, и тоже вычисляющиеся при помощи if. Гарантирую, тебя ожидает много интересного.

Вот как вообще можно прийти к ФЯ. Пусть у нас имеется простейший калькулятор, считающий мат. выражения вроде:

2 * 3 + 5 / 7;


Теперь мы хотим модифицировать калькулятор. Нужно, чтобы во-первых, пользователь мог ввести набор "внешних" по отношению данных, кроме того, особо сложные формулы записывать в строчку неудобно, потому нам понадобятся "внутренние" (связанные) переменные. Заодно, мы хотели бы иметь возможность вернуть набор значений. Вот "программа" для модифицированного калькулятора:

d = b ^ 2 — 4 * a * c;
((-b — sqr(d)) / (2 * a), (-b + sqr(d)) / (2 * a))

далее, для расчёта формулы могут понадобитья более сложные вещи, которые часто встречаются в различных задачах. Так что мы вводим возможность записывать собственные функции. Например, если какой-то фокрмуле используется тангенс, который отсутствует в стандартном наборе функций, чтобы не писать всюду sin(x) / cos(x) мы записываем

tg(x) = sin(x) / cos(x)


и далее используем в нашей формуле более краткую и очевидную форму.

Наконец, некоторые вещи не выразишь в виде всяких sin, cos, +, -, etc. Пусть, например, нужно записать функцию, вычисляющую модуль числа. Для этого нужно расширить наш язык:

abs(x) = if (x > 0) x else -x


abs(x) =
    when x > 0 => x
    when x < 0 => -x


Для математиков привычнее второй выриант, он напоминает одну большую фигурную скобку. А первый вариант является своего рода сокращением второго специально для случаев, когда есть два взаимо исключающийх условия.

Вот примерно такого небольшого языка достаточно, чтобы считать весьма нетривиальные для простенького калькулятора вещи, например, факториал

factorial(x) =
    when x = 0 => 1
    when x > 0 => x * factorial(x - 1)


Ну а дельше мы можем понапихать в наш калькулятор всяких других вкусностей типа паттерн-матчинга, вложенных функций, лямбд и т.п. И получим полноценный чистый ФЯ. Но в нём будет проблема — нельзя в нём сделать что-то императивное. Потому уместно будет сделать доп. инструкцию imperative { }, где в фигурных скобках располагается код, выполняющий что-то императивное, а значением конструкции будет последнее выражение в ней. Правда, всё это оверхед, и потому разработчики Nemerle решили, что блок, залючённый в фигурные скобки, будет содержать как сложенные переменные, нигде больше не использующиеся (типа let x = ... in ... в OCaml), и императивный код. Причём нет особой разницы между императивными и чистыми функциями, просто вводится доп. тип данных void, которому принадлежит одно значение (). Собственно, () является знгачением функций вроде присваивания (=) или Console.WriteLine().
... << RSDN@Home 1.2.0 alpha rev. 672>>
Re[4]: Функциональное программирование в Nemerle
От: nikov США http://www.linkedin.com/in/nikov
Дата: 30.05.07 14:35
Оценка: 1 (1)
Здравствуйте, Кэр, Вы писали:

Кэр>В том-то и дело, что не равно. Метод может вернуть существующую копию объекта, конструктор всегда даст новый объект.


В Nemerle вызов конструктора не всегда возвращает новый объект.
Re[7]: Функциональное программирование в Nemerle
От: Кэр  
Дата: 30.05.07 14:46
Оценка: 1 (1)
Здравствуйте, nikov, Вы писали:

N>>>В Nemerle вызов конструктора не всегда возвращает новый объект.


Кэр>>Обалдеть А зачем это сделано?


N>По-моему, очевидно... Для экономии объектов.


А, ну да
Имхо, это одна из вещей, которую надо вешать на пороге при входе в Nemerle. Типа — не забудьте пригнуться
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[8]: Функциональное программирование в Nemerle
От: Аноним  
Дата: 15.05.07 19:10
Оценка: :)
Здравствуйте, VladD2, Вы писали:

VD>Следующим шагом будет избавление от большого количества методов в телах АСТ-классов и группировка их в одном месте, то есть реализация паттерна Посетитель. Так поступают 99% создателей компиляторов использующих ООЯ. И я их понимаю.


Похоже, Посетитель — плохой паттерн.
Re[9]: Функциональное программирование в Nemerle
От: konsoletyper Россия https://github.com/konsoletyper
Дата: 15.05.07 20:17
Оценка: +1
Здравствуйте, <Аноним>, Вы писали:

VD>>Следующим шагом будет избавление от большого количества методов в телах АСТ-классов и группировка их в одном месте, то есть реализация паттерна Посетитель. Так поступают 99% создателей компиляторов использующих ООЯ. И я их понимаю.


А>Похоже, Посетитель — плохой паттерн.


Нет, похоже, что C# — не самый продвинутый язык. А ортодоксальное следование ООП (да и вообще чему-либо) — не самая лучшая идея. Вот именно поэтому приходится реализовывать посетителя, т.к. он является наилучшим компромиссом в данной ситуации.
... << RSDN@Home 1.2.0 alpha rev. 672>>
Re: Функциональное программирование в Nemerle
От: FDSC Россия consp11.github.io блог
Дата: 16.05.07 19:05
Оценка: -1
Здравствуйте, Чистяков Влад (VladD2), Вы писали:

ЧВV>Статья:

ЧВV>Функциональное программирование в Nemerle
Автор(ы): Чистяков Влад (VladD2)
Дата: 03.03.2007
Язык программирования Nemerle заинтересовал многих в первую очередь своей мощнейшей подсистемой мак-росов. Однако и без них Nemerle предоставляет ряд су-щественных улучшений по сравнению с традиционными, императивными языками программирования (такими как Java, C# и C++).
Nemerle, кроме традиционного императивного програм-мирования, поддерживает функциональное программи-рование. Это выражается в наличии конструкций, упро-щающих манипуляцию функциями, построение и анализ сложных структур данных и т.п.
К сожалению, если вы не использовали возможности, присущие функциональным языкам ранее, то вам будет трудно оценить, насколько Nemerle может оказаться вам полезным в реальной повседневной работе. Данная статья призвана в неформальной форме продемонс-трировать это.


Честно скажу: старался читать внимательно и прочитал даже чуть больше половины После чего у меня перегорел последний защитный предохранитель и я понял: "Влад опять рассказывает фичи Немерле по отдельности...".

P.S. Для тех, кто не понял. Опять не рассказали, как думать так, что бы использовать возможности Nemerle, зато привели кучу примеров, какие возможности у него есть. Короче говоря, как правильно было сказано, для того, что бы понять преимущества Немерле, нужно начать на нём правильно писать программы, но вот как правильно их писать я так и не понял в очередной раз.

Кода в статье слишком много... воды бы побольше.... хочется услышать чего-то общего, каких-то графических схем, сравнения, скажем, структуры (не кода) программы на C# 1.1 и Nemerle, потому что всякие там вещи по типу "смотрится лучше" и "написать что-то(_, x) вместо определения вспомогательной функции" всё-таки не производит впечатления, если учесть, что нужно для этого переходить на язык, интеграция которого к VisualStudio требует скачать огромную SDK... неудобства пока перевешивают удобства. Хотя, конечно, те же замыкания — это жутко приятно


P.P.S. Летом, на досуге, может ещё раз прочитаю... может пойму что-нибудь
Re[2]: Функциональное программирование в Nemerle
От: konsoletyper Россия https://github.com/konsoletyper
Дата: 16.05.07 19:50
Оценка: +1
Здравствуйте, FDSC, Вы писали:

ЧВV>>Статья:

ЧВV>>Функциональное программирование в Nemerle
Автор(ы): Чистяков Влад (VladD2)
Дата: 03.03.2007
Язык программирования Nemerle заинтересовал многих в первую очередь своей мощнейшей подсистемой мак-росов. Однако и без них Nemerle предоставляет ряд су-щественных улучшений по сравнению с традиционными, императивными языками программирования (такими как Java, C# и C++).
Nemerle, кроме традиционного императивного програм-мирования, поддерживает функциональное программи-рование. Это выражается в наличии конструкций, упро-щающих манипуляцию функциями, построение и анализ сложных структур данных и т.п.
К сожалению, если вы не использовали возможности, присущие функциональным языкам ранее, то вам будет трудно оценить, насколько Nemerle может оказаться вам полезным в реальной повседневной работе. Данная статья призвана в неформальной форме продемонс-трировать это.


FDS>Честно скажу: старался читать внимательно и прочитал даже чуть больше половины После чего у меня перегорел последний защитный предохранитель и я понял: "Влад опять рассказывает фичи Немерле по отдельности...".


Это Влад рассказывает про фичи Немерле, которые он заимствовал из других ФЯ.

FDS>Кода в статье слишком много... воды бы побольше.... хочется услышать чего-то общего, каких-то графических схем, сравнения, скажем, структуры (не кода) программы на C# 1.1 и Nemerle, потому что всякие там вещи по типу "смотрится лучше" и "написать что-то(_, x) вместо определения вспомогательной функции" всё-таки не производит впечатления, если учесть, что нужно для этого переходить на язык, интеграция которого к VisualStudio требует скачать огромную SDK... неудобства пока перевешивают удобства. Хотя, конечно, те же замыкания — это жутко приятно


Какое SDK? Сейчас Блудов Павел раз в месяц выкладывает инсталлятор, и ничего (кроме инсталлятора, 2Мб) качать не нужно. Правда, есть неудобство — Интеграция пока жутко глючит. Но это всё же гораздо удобнее, чем в Блокноте.
... << RSDN@Home 1.2.0 alpha rev. 672>>
Re[9]: Функциональное программирование в Nemerle
От: Аноним  
Дата: 18.05.07 20:54
Оценка: -1
Здравствуйте, VladD2, Вы писали:

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

Так же легко повернуть, что и код на Nemerle не делает, того что от него требовалось, и другого полезного ничего не делает.

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

Что несуразного в Min с одним параметром? Не больше чем в умножении на 1. К тому же добавить контроль количества параметров очень легко, что я и показал в следующем коде. А так у меня даже был Min с любым количеством параметров, не помню только выкладывал или нет.

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

Серьезно не понимаю, зачем добиваться той же функциональности с точностью до миллиметра. Разговор с моей стороны идет, что по объему кода никакого пятикратного преимущества у Nemerle нет, а есть максимум двухкратное, как по количеству строк, так и по объему файла за вычетом ведущих проблелов. А уж если сравнивать по количеству нажатий на кнопки в среде оснащенной Intellisense'ом.

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

Это на Nemerle не делал то что нужно

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

Всего второй раз говорю здесь о Nemerle, а уже любитель спорить. Что касается правоты/не правоты, то я не любитель бинарной логики.
На вопрос вполне может быть несколько ответов.

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

Пускай, я пока не смеюсь.

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

А откуда такая уверенность. Я переписал, код как только получил доступ к форуму и смог посмотреть на исходные условия. Да и что в твоем примере такого существенного?

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

Инкапсуляция всегда небесполезна.

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

Пишу, в основном, после работы. Кстати, стараюсь никогда не оправдыватся, но, ха-ха, вчера у меня прорвало счетчик воды в квартире и половину ее залило, к счастью без особых последствий, но пять 15 литровых ведер воды, я с пола собрал.

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

Я подумал, подумал и написал сопоставление с образцом на C#.

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

С этим не согласен. К тому же добавить свойство — всего одна дополнительная строка, а работа с литералами у меня и так типизированная.

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

Я сделал это только чтобы не спорить по, на мой взгляд, ничтожному поводу. К тому же я прочитал, что нужен вынос конвертации в отдельные функции.

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

Отнюдь, я просто показал широту своих взглядов и легкость к изменениям.

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

В таком случае хотелось бы увидеть пример правильно приготовленного, на иерархии буквально из одного двух классов.

VD>Серьезно? Ну, я почти на верняка пишу на C# дольше тебя (начал еще в 2000-ном когда первые превью появились), но вот почему-то никак не могу привыкнуть к тому, что вместо:

Я тоже начал в 2000 с бета версий, правда, тогда в основном упирал на VB.NET, ну да в контексте .NET это не так важно.
И оценка на brainbench у нас примерно одинаковая по C#.

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


VD>Я даже могу тебе подсказать, как сократить еще по строчки в каждой из функий.

Мысль неплохая.

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


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

Да ничего там не пришлось подглядывать. Говорю же, написал, сразу после отправки версии с методами в классе, когда прочитал условия задачи.
У меня к тому же есть отличие, не надо проводить повторную конвертацию, если в результате первой конвертации в выражении получились, образцы подходящие для условий конвертации. Впрочем, можешь заявить, что это я у WolfHound подглядел.

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


VD>Объем кода

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

VD>

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

VD>Вряд ли ты станешь спорить, что теперь наш код иделогически близок. Но вот что лучше читается? На мой взгляд действия собранные вместе и без лишних заголовков функций читается намного лучше. Его и поддерживать проще.
C# неплохо читается, можно по отдельности классы разбирать.

VD>Развитие кода

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

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

Так и мне подскажет. Набираешь override (даже несколько букв) вот и готово тело метода.

А вот код сопоставления по образцу:
  static Expr RemoveMulToOne(Expr expr)
  {
    Mul mul = null; Expr first = null; Lit lit = null;
    if (new Pattern<Mul, Expr, Lit>().Match<Expr>(expr, ref mul, ref first, ref lit))
    {
      if (lit.Eval() == 1) return first;
    }
    return expr;
  }

  static Expr RemoveMaxOfLiterals(Expr expr)
  {
    Max max = null; Lit lit1 = null; Lit lit2 = null;
    if (new Pattern<Max, Lit, Lit>().Match<Expr>(expr, ref max, ref lit1, ref lit2))
    {
      return new Lit(Math.Max(lit1.Eval(), lit2.Eval()));
    }
    return expr;
  }
Re[10]: Функциональное программирование в Nemerle
От: IT Россия linq2db.com
Дата: 18.05.07 21:19
Оценка: +1
Здравствуйте, <Аноним>, Вы писали:

IT>>Хочешь я твои 150 легко превращу в 300 просто убрав искусственное сжатие кода, предназначенное исключительно для экономии строк?

А>Главное, не забыть при этом, что я могу аналогичный код на Nemerle легко превратить в 150.

Не сможешь, там от силы пять строчек можно добавить для улучшения читабельности. А вот твой код с первого взгляда выглядит как попытка ужать посильнее и впихнуть побольше. Такие вещи таким способом не делаются. Пиши нормально, так чтобы другие глаза не ломали о твои нагромождения кода и твой код, даже больше в строчках, будут читаться гораздо лучше.
... << RSDN@Home 1.2.0 alpha rev. 0>>
Если нам не помогут, то мы тоже никого не пощадим.
Re[6]: книга?
От: VladD2 Российская Империя www.nemerle.org
Дата: 18.05.07 22:49
Оценка: +1
Здравствуйте, <Аноним>, Вы писали:

А>VladD2, а вы не думали издать книгу про Nemerle и вообще по функциональным языкам?

А>Чисто Ваших статей только по Nemerle (из тех что в открытом доступе) набралось уже на 125 страниц формата А4, т.е. распечатать конечно можно но это будет ворох бумаги, что крайне неудобно. Хочется именно книгу.
А>Если присоединить туда обзорные статьи по ФП в целом, по Haskell, Erlang, Scala (это будет полезно, для обзора и для сравнения возможностей языков), то получится еще столько же. Ну и еще "связующий" текст, что-то из стандарта языка, побольше примеров и т.д.

Создание кник требует времени. А его и так на другие задачи не хватает.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[13]: Функциональное программирование в Nemerle
От: Аноним  
Дата: 19.05.07 19:59
Оценка: :)
Здравствуйте, IT, Вы писали:

IT>Здесь ты не добавил читабельности. Здесь ты её убил.

Отлично, с учетом того, что это был выстрел вслепую, так как мне не было показано, во что должен превратиться мой код после увеличения количества строк до 300, для, возможного, увеличения читабельности. Причем я по-честному не стал приводить свою версию кода на Nemerle в своем первом ответе на обещание увеличить мой код до 300 строк. Однако это не привело к показу кода, поэтому я счел нужным первым перевести разговор в конкретную плоскость, с конкретным кодом и конкретными цифрами. В ответ я получил обиду, что не так переформатировал код, но так и не получил в ответ образец как надо было переформатировать мой код чтобы он занимал 300 строк, чтобы я на основании этого образца мог бы переформатировать код на Nemerle.

IT>Пожалуйста, не надо считать других за идиотов и демонстрировать упёртость.

Пожалуйста, не надо считать, что я готов спорить с идиотами. Плохо (но и это не абсолютная догма) когда упертость в споре, это прежде всего повтор своей позиции без аргументации этой позиции и без обсуждения выдвинутых контраргументов по своей позиции. А кодга приводится конкретный код и новые аргументы, обсуджаются контраргументы, что плохого в такой упертости?

IT>которому истина уже ни к чему, которому главное доказать, не важно что, лишь бы доказать

Честно говоря, слабо понимаю, как это истина может быть не важна, когда она доказывается.
Re[15]: Функциональное программирование в Nemerle
От: Аноним  
Дата: 20.05.07 15:12
Оценка: -1
Здравствуйте, konsoletyper, Вы писали:

K>Здравствуйте, <Аноним>, Вы писали:


K>В Nemerle, обрати внимание, такая практика существует только по отношению к вариантам.

Обращаю внимание, что при паттерн матчинге декларация тоже на одной строке в Nemerle.
Ведь код типа
match 
{
   | Call(expr1, expr2)


это и есть декларация двух, возможно разнотипных, переменных expr1 и expr2 на одной строке

K>Так что судить могу по абстрактному понятию "читабельность".

Ого, уже абстрактное.

K>Потому что варианты унаследованы Nemerle от ML, где такое практикуется почти 30 лет. И это вполне обоснованная практика. Я не сильно разбираюсь в тонкостях computer science.

K>Так вот, в вариантах размещение нескольких "деклараций" на одной строке читабельность повышает. В классах же — понижает. Думаю, всё это связано с тем, что классы поддерживают ООП-парадигму, так что должны походить на чёрный ящик, потому для них требуется пространное описание структуры. Варианты же — вещь ортогональная ООП, они, наоборот, максимально открыты, чтобы по ним было проще сопостовлять по образцу.

Понимаю, Nemerle — хороший язый, ML — хороший язык (30 лет!) им можно декларации на одной строке размещать.
А вот C# плохой язык ему нельзя.
Re[16]: Функциональное программирование в Nemerle
От: Аноним  
Дата: 20.05.07 21:09
Оценка: :)
Здравствуйте, VladD2, Вы писали:

VD>Скорее я отныне решил не замечать тебя, потому как имею обширный и печательный опыт общения с упертыми спорщиками, которым познание истины не интересно как класс, а интересен сам процесс спора.

А как можно спорить не познавая истину в той или иной степени?
Возможно это не та истина, что обсуждалась в начале спора, возможно ее заметно или незаметно подменили, разбили на несколько более мелких истин, возможно и не собираемых в целое...

VD>Конечно. Потому и обсуждать нечего.

А пример использования? По нему вполне можно восстановить примерный код реализации.
Мне тоже небезынтересно проверить знание C# для спорящих со мной.

Также, хочу заметить, что вместе с сопоставлением по образцу код уложился в те самые 250 строк кода на C#, о котором количестве шла речь в исходной статье.
Re[16]: Функциональное программирование в Nemerle
От: VladD2 Российская Империя www.nemerle.org
Дата: 20.05.07 22:53
Оценка: +1
Здравствуйте, <Аноним>, Вы писали:

K>>Отличный пример софистики и демагогии. Нуль конструкрива.

А>Чувствую, не знаете значения ни демагогии, ни конструктива.
А>Если под софистикий понимается умение мудро вести спор, то с благодарностью принимаю в свой адрес.

Вот это она и есть софистика или иными словами демогогия.
Прекрасно понимаю, что ты и сам это знешь. Но тем кто не так подкован в данном вопросе советую сходить и почитать определение терминов Софизм и Софисты. Конкретно:

Вырождение софистики началось уже в IV в. до н. э. (Евтидем и др.). Софисты постепенно превращались в фокусников, берущихся с помощью софизмов и др. способов (подробно описанных Аристотелем в «Софистических опровержениях») защищать или опровергать любые мнения.


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

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

А>По поводу демагогии:

А>Демагог прежде всего обращается к широким массам.

Демагогия — это прежде всего "набор ораторских и полемических приемов и средств, позволяющих ввести аудиторию в заблуждение и склонить ее на свою сторону". А "обращение к массам" — это "ораторское искуство". Уверен, что и эта ошибка не была случайной, а продолжение то же линии демагогии.

А>Конечно, любое выступление на форуме, можно посчитать демагогическим ибо в потенциале, его могут прочитать очень много людей.

А>Но нужно ли считать его демагогическим если идет обращение к одному человеку?

Не стоти рассчитывать, что такой наивный подлог прокатит в данном месте. Ты не на тех нарвался. Толи и демагиги не редкость на больших форумах. И лечим мы их очнь просто — баним к чертям. А тех кто еще и ник не удосуживается завести банем по IP-пишникам.

А>По поводу конструктива:


А>А. Легко доведу код на C# до 300 строк переформатированием еще и читабельность увеличится.

А>B. Тогда я доведу код на Nemerle до 150.
А>A. Не сможешь.
А>B. Вот пожалуйста.
А>A. Код утратил читабельность.
А>B. Возможно, но мне не привели пример кода с улучшенной читабельностью на C#.

А то ты сам не знаешь что такое читабельный код. Код вылетающий за пределы экрана (превышающий 100 символов в ширину) и попытки впихнуть в одну строку много определений ухудшают читабельность.

В том что ты можешь разести код содержащий 150 токенов на 150 строк ни у кого сомнений не вызвает, в прочем точно так же как ни у кого не вызвает сомнений то что ты жулик, так как сравнивашь код хорошо отформатированный и отлично читающийся с форменной кашей.
Если пойти по твоему пути, то можно провести обратный эксперемент и превратить в такую же кашу и код на Немерле. Например, так:
using System;
using System.Console;
using Nemerle.Utility;
using Expr;

public variant Expr
{
 | Literal { value : double; } | Call { name : string; parms : list[Expr]; } | Plus { expr1 : Expr; expr2 : Expr; } 
 | Minus { expr1 : Expr; expr2 : Expr; } | Mul { expr1 : Expr; expr2 : Expr; }| Div { expr1 : Expr; expr2 : Expr;
}
 
 public override ToString() : string
 {
   match (this) { | Literal(value) => value.ToString() | Call(name, parms) => $"$name(..$parms)" | Plus(e1, e2) with op = "+" 
   | Minus(e1, e2) with op = "-" | Mul (e1, e2) with op = "*" | Div (e1, e2) with op = "/" => $"$e1 $op $e2" }
 }

 public Eval() : double
 {
   match (this) { | Literal(value) => value | Plus (e1, e2) => e1.Eval() + e2.Eval() | Minus(e1, e2) => e1.Eval() - e2.Eval() 
   | Mul (e1, e2) => e1.Eval() * e2.Eval() | Div (e1, e2) => e1.Eval() / e2.Eval() | Call("max", [arg1, arg2]) => Math.Max(arg1.Eval(), arg2.Eval())
   | Call("min", [arg1, arg2]) => Math.Min(arg1.Eval(), arg2.Eval()) | Call("foo", [arg1]) => arg1.Eval() | Call(_, _) => throw InvalidOperationException(this.ToString());
   }
 }

 public Convert(transform : Expr -> Expr) : Expr // добавили поддержку трансформации выражений
 {
   transform(match (this) { | Literal => this | Plus (e1, e2) => Plus (e1.Convert(transform), e2.Convert(transform))
   | Minus(e1, e2) => Minus(e1.Convert(transform), e2.Convert(transform)) | Mul (e1, e2) => Mul (e1.Convert(transform), e2.Convert(transform))
   | Div (e1, e2) => Div (e1.Convert(transform), e2.Convert(transform)) | Call(name, parms) => Call(name, parms.Map(_.Convert(transform)))
   })
 }
}

module Program
{
 Main() : void
 {
   def expr = Mul(Mul(Plus(Literal(1.23), Call("max", [Literal(1), Literal(2)])), Literal(1)), Literal(1));
   WriteLine($"До трансформации\nExpression '$expr' = $(expr.Eval())");

   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 });
   WriteLine($"После трансформации\nExpression '$expr' = $(expr.Eval())");
 }
}

Итого 46 строк. Выглядит конечно хреново, но не хуже чем твои:
    public override string ToString() { return name + "(" + String.Join(", ", Array.ConvertAll<Expr, string>(arguments, System.Convert.ToString)) + ")"; }


K>>Ты вообще понимаешь слово "читабельный", или просто издеваешься над собеседниками?

А>Пригодный к чтению.

Еще одна лож. Пригодным к чтению можно счесть почти любой текст. А "читабельный" означает "который удобно и легко читать".
Конечно и это категория не универсальная, но уж строки в 150 символов точно нельзя счесть читабельными.

И потом забавляет сама идей свести все к спору о чем-то вроде относительности понятий вместо того, чтобы признать, что этот ужатый до безобразия код один фиг в двое больше оригинала. И в том, что как бы ты не извращался, но сложные паттерны всегд будут намного понятнее чем их эмуляция на C# который просто не имеет для этого должных средств.

Но все это пустое. Ты не собирашся вести честную дискуссию с цель найти истину. Ты уже продемонстрировал всем, что грязными демогагическими приемами пыташся оспорить совершенно очевидные вещи.

А>Как связана краткость кода, с читабельностью кода?


Прямой связи тут нет. Но если не страдает выразительность и два варианта код решают одну и ту же задачу, то более кратикий будет по совместительству и более читабельным.
Но точно известно, что если код содержит несколько определений переменных на додной строке, если он содержит черезчур длинные строки (а 150 символов — это совсем черезчур), то код назвать читабельным нельзя. Так же ухудщают читабельность и содержащиется по всему код незначимые куски вроде "public override Expr Convert(Converter converter) { return " заграмождющие код. Они просто дань традициям ОО-языков.

А>Читабелен ли максимально краткий код?

А>Краток ли максимально читабельный?

Изумительные примеры демагогии. Повторюсь — прямой свзи между краткостью и читбельностью нет. Краткость это отельное достоинство и оно не достикается запихиванием в одну стоку 150 симовол.

Короче, по-русски читабельность называется удобочитаемостью. К сожалению определиние общее, расчитанное на разговорный зяык. Программистское описание есть на английском — readability. Обрати там внимание на послединй пункт (Naming conventions). Вот здесь ты можешь почитать соглашения по кодированию на C# нашей командны.

А>Где границы краткости, при которой начинает падать читабельность?


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

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

А>Где границы читабельности, при которой начинает падать краткость?


Это вообще перл. Читабельность падает когда код превращают в кашу. Не важно увеличивается он при этом в общеме или уменьшается.

А>И т.д. и т.п.

А>Я при этом не требовал математически строгого определения, мне достаточно было примера.

ОК. Записывать вот такие функции:
    public override Expr Convert(Converter converter) { return converter(new Plus(first.Convert(converter), second.Convert(converter))); }

в одну строку — это путь к нчитаемости. Такуая функция должна быть записана хотя бы так:
        public override Expr Convert(Converter converter)
        {
            return converter(new Plus(first.Convert(converter), second.Convert(converter)));
        }

При этом ее следует отбить от других фукнций хотя бы одной пустой строкой, чтобы ее можно было легко разглядеть в коде.
Далее вот это:
    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;
    }

тоже плохочитаемая запись. Писать новый statment на стоке где начинаетс определение переменной — это верный путь к запутыванию кода. Должно быть так:
    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;
    }

Многие сочтут, что определение переменных нужно отделять от if-ов. В прочем, зачем нужны ничего не делающие фигурные скбоки у тела if-а тоже не ясно. Лучше бы на них сэкомномил.

Кстати, о твоих словах, что мол ты используешь полные имена, а кто-то там двух-буквенные согращения. Что-то в последних вариантах у тебя все идентификаторы резо подусохли. Даже Literal укоротился до LIt, что уже на грани читаемости, в то время как все мои были очевидны.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[17]: Функциональное программирование в Nemerle
От: Аноним  
Дата: 21.05.07 16:11
Оценка: -1
Здравствуйте, VladD2, Вы писали:

VD>Вот это она и есть софистика или иными словами демогогия.

А почему определения разные в википедии для софиситики и демагогии?

VD>Прекрасно понимаю, что ты и сам это знешь. Но тем кто не так подкован в данном вопросе советую сходить и почитать определение терминов Софизм и Софисты. Конкретно:

Гм, а мне казалось, софизм, софисты и софистика — разные слова, пусть и однокоренные.
Что интересно, слово софистика есть в википедии, однако две приведенные ссылки, ссылаются на другие слова.

Софи́стика (греч. σοφιστική — умение хитро вести прения)


VD>А ще стоит почитать определение слова Тролль и Троллинг, потому что мы видим перед собой очердного представителя этого нового вида животных расплодившихся по поутине.

Стоит-то стоит, только оно такое обширное, что под троллингом может пониматься практически все. Кстати сравнение оппонента с животным это тоже троллинг.

VD>Демагогия — это прежде всего "набор ораторских и полемических приемов и средств, позволяющих ввести аудиторию в заблуждение и склонить ее на свою сторону". А "обращение к массам" — это "ораторское искуство". Уверен, что и эта ошибка не была случайной, а продолжение то же линии демагогии.


Демаго́г (др.-греч. δημαγωγός, «предводитель народа»)

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

VD>А то ты сам не знаешь что такое читабельный код. Код вылетающий за пределы экрана (превышающий 100 символов в ширину) и попытки впихнуть в одну строку много определений ухудшают читабельность.

Осторожно напоминаю, что речь шла о том, что я убил читабельность в коде на Nemerle.

VD>Если пойти по твоему пути, то можно провести обратный эксперемент и превратить в такую же кашу и код на Немерле. Например, так:

Осторожно напоминаю, что я сделал с кодом на Nemerle нечто обратное приведенному коду. В ответ мне заявили, что я убил читабельность.

VD>Еще одна лож. Пригодным к чтению можно счесть почти любой текст. А "читабельный" означает "который удобно и легко читать".

А где ссылка на википедию? Или кликабельный, это на котором легко и удобно кликать?

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

Осторожно напоминаю, что речь шла о "моем" коде на Nemerle где точно не было никаких 150 символов в строке.

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

Напомните, сравнивал ли я своих оппонентов с демонстрирующими упертость животными? Или использовал, что-то еще более грязное?

VD>Но точно известно, что если код содержит несколько определений переменных на додной строке, если он содержит черезчур длинные строки (а 150 символов — это совсем черезчур), то код назвать читабельным нельзя. Так же ухудщают читабельность и содержащиется по всему код незначимые куски вроде "public override Expr Convert(Converter converter) { return " заграмождющие код. Они просто дань традициям ОО-языков.

Осторожно напоминаю, про что уже напоминал. (Пример рекурсии, если что, или вызова подпрограммы)

VD>Изумительные примеры демагогии. Повторюсь — прямой свзи между краткостью и читбельностью нет. Краткость это отельное достоинство и оно не достикается запихиванием в одну стоку 150 симовол.

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

VD>Более того код не становится кратче если он написан с так чтобы он занимал меньше место. Более краткий код обязан использовать более краткие конструции. Они же боле высокоуровневые.

Краткий код, это краткие конструкции, это я понял

VD>Это вообще перл. Читабельность падает когда код превращают в кашу. Не важно увеличивается он при этом в общеме или уменьшается.

Про кашу из топора слышал, про кашу из кода нет. Чувствую намек на спагетти-код, так он вроде связан с запутанной передачей управления.

VD>в одну строку — это путь к нчитаемости. Такуая функция должна быть записана хотя бы так:

А вот так?
public override Expr Convert(Converter c) { return c(new Plus(first.Convert(c), second.Convert(c))); }

Или так?
public override Expr Convert(Converter converter) { 
    return c(new Plus(first.Convert(converter), second.Convert(converter))); 
}

А если посчитать не по строкам, а по объему кода без ведущих пробелов?
А если учесть, что при наборе в Visual Studio не надо набирать "public override Expr Convert(Converter converter) {", а только набрать over и выбрать вариант для переопределения?

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

С этим не согласен, одна фигурная скобка на строке хорошо выполняет роль отбивки.

VD>Далее вот это:

VD>тоже плохочитаемая запись. Писать новый statment на стоке где начинаетс определение переменной — это верный путь к запутыванию кода. Должно быть так:
Это намек, читающему, что здесь идет не просто выполнение кода, а сопоставление по определенному образцу.

VD>В прочем, зачем нужны ничего не делающие фигурные скбоки у тела if-а тоже не ясно. Лучше бы на них сэкомномил.

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

VD>Кстати, о твоих словах, что мол ты используешь полные имена, а кто-то там двух-буквенные согращения. Что-то в последних вариантах у тебя все идентификаторы резо подусохли. Даже Literal укоротился до LIt, что уже на грани читаемости, в то время как все мои были очевидны.

Как ни крути Lit трехбуквенное. Уж молчу про Operation и AtLeastTwoArgumentsCall
Re[11]: Функциональное программирование в Nemerle
От: Аноним  
Дата: 21.05.07 17:14
Оценка: -1
Здравствуйте, VladD2, Вы писали:

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

Так и мой делает, что было в моих условиях задачи.

А>>Что несуразного в Min с одним параметром?

VD>То что это функция вычисляющая минимальное значение. Глупо вычислять минимальное значение когда вариантов ровно один.
А>> Не больше чем в умножении на 1.
VD>Умножение на 1 может получиться в следствии применения другой оптимизации. Если ты заметил, то их там можно добавлять хоть тысячу.
И такой Min может получиться в следствии применения другой оптимизации, которая уберет остальные аргументы.
Напоминаю, у меня был Min со смногим количеством параметров и я его выкладывал.

VD>Не выкладывал. Но этого никто не просил.

Я тут давно прошу признать, что сравнение Nemerle и C# по объему кода было нечестным в статье, хоть бы кто послушал.

VD>Сравнивать можно только программы решающие одни и те же задачи. А то я тебе напишу программу "x()" и отмажусь тем, что "не понимаю, зачем добиваться той же функциональности".

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

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

Ага, если он abstract в базовом, еще как подскажет. Даже скомпилировать не даст.

VD>и их не надо искть по туче классов.

Считаю, что код надо хранить поближе к данным, которые он обрабатывает.

VD>Граматные программисты

Стараюсь не цеплятся к правописанию, ибо сам грешен, но тут не могу не отметить. Считайте троллингом.

VD>И что будет? Будет такое же 2-5 кратное упрощение работы.

Гм, ну как "protected override Expr Convert(Converter converter)" сократится до пары нажатий, я вижу, а где intellisense также сократит код на Nemerle не вижу.
Что тут среда подсказать может? "| Plus (e1, e2) => Plus (e1.Convert(transform), e2.Convert(transform))" Ну параметры, так она и для C# подскажет.

VD>Ты вменяемый?

Надеюсь.

VD>А тебе над чем смеяться то? Они смеются над тем как ты краткий и очевидны код (который даже ты вроде как понял) ты патшся сравнивать со своей кашей.

Хорошо смеется тот кто смеется последним. Народная мудрость.

VD>В условиях задачи не сказно как надо делать. Там сказано, что нужно делать.

Там было сказано, что код изменений будет "внешним".

VD>Он верно работал с самого начала.

А поправка Wolfhaund? Код, работал не правильно.

VD>В конкретном случае бесполезно все, что не приносит пользы для этого случая. Все данные AST-классов должны быть доступны публично. Их тлько желательно сделать неизменяемыми. Это и делается автоматически в вариантах Немерле и вызывает нагромождения кода на C#. В общем, это банально более удобное решения конкретной задачи.


VD>Кстати, не всегда получается.

Рад, что заметил мою шутку, там даже ха-ха было вставлено

VD>С чем? Это как раз тот случай когда ты губо попираешь принципы инкапсуляции. Eval() должен вычислять, а не возвращать значение. Испоьзование частнрых знаний, о том, что для некоторого типа Eval() реализован так, что может заменить эксессор свойства как раз и является нарушением инкапсуляции, так как ты опирашся на знания о реализации абстрактного метода.

Продолжаю оставаться несогласным. <<< Это пример неконструктива.

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

Кажется, я принял это решение не после слов konsoletyper. А после прочтения условий, впрочем не важно.

VD>Где ты изменил взгляд?

Легкость к изменениям программы, а не взглядов. Они впрочем у меня, тоже широкие.

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

А я не про методы, я про классы. В иерархию добавляется новый класс, в нем реализуется метод для посетителя. Но в самом посетителе, например для представления в виде строки, не добавляется проверка на новый класс. Ошибка вылетает только во время выполнения. Как, кстати, и в Nemerle в некоторых случаях.

VD>А кто-то тупо обошел этот вопрос и начал развивать пенесометрийную тему. Демагогия однако.

Пенисометрия обычно начинается с того у кого длиннее (или кто раньше начал писать на C#). Я же отметил, что у меня если и короче то не на много (многие ли способны сказать такое! вот оно подлинное хладнокровие и уверенность в себе).

VD>А вот этот код
Автор:
Дата: 17.05.07
не твой ли? Смотри как от полных имен не осталось и следа! Даже Literal был в совершенно не очевидный Lit переименован. Это тоже, так сказать, проявление широты взглядов?

Немерлисты, научили меня плохому.

VD> Ой, умаор! Да ничего другого и не приходится. Еще приходится скролировтаь код чтобы разглядеть, что там у тебя за горизонтом тварится. И при это всевремы ломать глаза, так как выцепить значемый код из 150-символьных строк ой как не просто. Уж лучше бы фукнция 3 строки занимала.

Гм, не я понимаю, встречаются длинные строки, но чтобы все были 150 символьные? Против трех строк не против, но как уже говорил предлагаю тогда считать размер кода без ведущих пробелов или количество нажатий в Visual Studio (это впрочем тяжело подсчитать)

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

Ну так ООП для больших проектов и задумывался.

VD>Ведь в любом случае одна строка:

VD>
VD>  | Minus   { expr1 : Expr;   expr2 : Expr; }
VD>

VD>соотвествует как минимум:
VD>
VD>class Minus: Oper
VD>{
VD>    public Minus(Expr first, Expr second): base(first, second) {}
VD>    public override string ToString() { return first.ToString() + "-" + second.ToString(); }
VD>    public override double Eval() { return first.Eval() - second.Eval(); }
VD>    public override Expr Convert(Converter converter) { return converter(new Minus(first.Convert(converter), second.Convert(converter))); }
VD>}
VD>

VD>7 строкам на шарпе. А еще нужно учеть пустые строки которыми классы отбивают. да и код отбить по человечески:
Гм, гм.
А у меня есть мнение, что не одна строка на Nemerle, а четыре, только они размазаны по коду. Вот глаза-то придется поломать
| Minus { expr1 : Expr;   expr2 : Expr; }
| Minus(e1, e2) with op = "-" 
| Minus(e1, e2) => e1.Eval() - e2.Eval()
| Minus(e1, e2) => transform(Minus(e1.Convert(transform), e2.Convert(transform)))

2 * 4 > 7

VD> Это извини меня чушь какая-то, а не сопоставление с образцом. Ты бы хоть реализацию этого чуда привел бы, а то даже разговаривать не о чем. Ну, и надо заметить, что "это чудо" один фиг не сопоставимо с образцами паттерн-матчинга, ни по объему, ни по удобочитаемости. Это очередное награмождение кода попирающее принципы форматирования в C#.

Попирает, только в декларации на одной строке. Впрочем, кажется, мне разрешили это делать.
Также сопоставление претендует на универсальность и немного громоздко. А можно упростить до:
Max max = null; Lit lit1 = null; Lit lit2 = null;
if (expr.Match<Max, Lit, Lit>(ref max, ref lit1, ref lit2))
    return new Lit(Math.Max(lit1.Eval(), lit2.Eval()))

В чем сильные отличия от:
| Call("max", [Lit(lit1), Lit(lit2)]) 
    => Literal(Math.Max(lit1.Eval(), lit2.Eval()))

?
Три строки вместо двух, да и то за счет декларации.

К тому же возможно в C# 3.0 будет некоторая поддержка кортежей, что позволит и этот пример упростить далее.
Re[17]: Функциональное программирование в Nemerle
От: VladD2 Российская Империя www.nemerle.org
Дата: 21.05.07 22:18
Оценка: :)
Здравствуйте, FDSC, Вы писали:

FDS>P.S. Кстати, вы случайно не преднамеренно путаете этимологию слова (его происхождение) с толкованием (значением) слова?

FDS>(это я по поводу этого
Автор:
Дата: 21.05.07
вашего сообщения, я так понимаю, это тоже вы)


Вспомнился анекдот:

---------------------
— Вы случайно не еврей?
— Вы знаете? Совершенно случаяно...

... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[13]: Функциональное программирование в Nemerle
От: Аноним  
Дата: 22.05.07 07:59
Оценка: :)
Здравствуйте, WolfHound, Вы писали:

WH>Это догма. Догмы до добра не доводят.

Насчет догм считаю также. Насчет кода AST нет.

WH>Ну про то что тебе еще надо написать

WH>
WH>return converter(new Plus(first.Convert(converter), second.Convert(converter)));
WH>
ты как обыно забыл...

Разговор шел про пользу intellisence для Nemerle, а не для C#.
Тем не менее по вышеприведенному коду:
набираю ret, мне подсказывают return
набираю con, мне подсказывают converter
круглая скобка — список параметров
new Pl — подсказывают, new Plus
fir — подсказывают first
точка — выбираю метод Convert из списка.
con — converter

вот примерно, что придется набрать с клавиатуры:
ret con(new Pl(fir.(con), sec.(con));
Что придется набрать с клавиатуры в случае Nemerle пусть напишут знатоки Nemerle.
А код такой примерно:
| Plus(first, second) => converter(Plus(first.Convert(converter), second.Convert(converter))

WH>Вот только тут собрались флеймеры со стажем и так просто нас не провести...

Неужели из хода дискуссии не видно, что я тоже флеймер со стажем?

WH>Мелкая бага. Заметь поправка не изменила колличество строк.

Помню была какая-то байка насчтет фортрана и точки вместо запятой. Там даже количество символов не изменилось, а ракета улетела не туда.

WH>Типа тут гдето от тебя есть конструктив? Извини не вижу.

Нет, тут типа пример неконструкитва от меня. Вопрос мелкий, а я продолжаю стоять на своем, просто повторяя утверждение, а не доказывая его.

WH>Легкость это полное переписывание? Ну да когда 200-300 строк то переписать действительно легко, а когда больше...

Тогда, естественно, тяжелее. Впрочем пока тут речь шла, как раз о программе из 200-300 строк.

А>>А я не про методы, я про классы. В иерархию добавляется новый класс, в нем реализуется метод для посетителя. Но в самом посетителе, например для представления в виде строки, не добавляется проверка на новый класс. Ошибка вылетает только во время выполнения. Как, кстати, и в Nemerle в некоторых случаях.

WH>Ясно. С тем как реализуются посетители не знаком.
WH>Объясняю для тех кто не знает как реализуют посетитель:
Ключевое слово у меня иерархия. А у вас класс C, не в иерархии
using System;

interface IVisitor
{
    void accept(Expr expr);
}

interface IVisitable
{
    void visit(IVisitor visitor);
}

class Expr: IVisitable
{
    public virtual void visit(IVisitor visitor) { visitor.accept(this); }
}

class WriteVisitor: IVisitor
{
    public void accept(Expr expr)
    {
        Console.WriteLine("This is Expr");
    }
}

class Oper: Expr, IVisitable
{
    public override void visit(IVisitor visitor) { visitor.accept(this); }
}

class Program
{
    public static void Main(string[] arguments)
    {
        Expr expr = new Expr();
        WriteVisitor visitor = new WriteVisitor();
        expr.visit(visitor);
        Oper oper = new Oper();
        oper.visit(visitor);
    }
}

Программа компилируется, а работает неправильно.
А все потому, что в для IVisitor не добавили еще один метод.
Компилятор ничего не подсказывает.

WH>И где в коде Влада неуместные сокращения?


WH>Код читают чаще чем пишут. Следовательно код должен легко читаться так что твои сравнения без ведущих пробелов и тп просто не имеют отношения к жизни.

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

А>>А у меня есть мнение, что не одна строка на Nemerle, а четыре,

WH>А у меня есть мнение что при правильном форматирование не 7 строк на C#, а 22
WH>
WH>class Minus : Oper
WH>{
WH>    public Minus(Expr first, Expr second)
WH>        : base(first, second)
WH>    {}
    
WH>    public override string ToString()
WH>    {
WH>        return first.ToString() + "-" + second.ToString();
WH>    }
    
WH>    public override double Eval()
WH>    {
WH>        return first.Eval() - second.Eval();
WH>    }
    
WH>    public override Expr Convert(Converter converter)
WH>    {
WH>        return converter(new Minus(first.Convert(converter), second.Convert(converter)));
WH>    }
WH>}
WH>

А я тогда, что на Nemerle 11
| Minus 
  { 
      expr1 : Expr;   
      expr2 : Expr; 
  }
| Minus(expr1, expr2) 
    with oper = "-" 
| Minus(expr1, expr2) 
    => expr1.Eval() - expr2.Eval()
| Minus(expr1, expr2) 
    => transform(Minus(expr1.Convert(transform), expr2.Convert(transform)))

2 * 11 = 22
Это я еще не добавил для отбивки пустые строки как в C#, пожалел.

WH>Не размазаны, а сгрупированны по действию. Но не по объекту.

WH>Просто другой принцип группировки. Иногда (например в данном случае) болие предпочтительный.
А иногда (например в данном) более предпочитетельны по объекту. Например можно меньше внутренних полей через свойства выставлять.

WH>Почему 4 понятно, а вот почему 2 * 4 уже нет.

Я много раз писал, что преимущество по объему кода лишь двухкратное.

WH>2)Попробуй написать аналог этого

WH>
WH>| Call("max", [Mul(Literal(x), Literal(m)), Div(Literal(y), Literal(d))]) => Literal(Math.Max(x * m, y / d))
WH>

Всегда пожалуйста
Max max; Mul mul; Div div; Lit x, m, y, d;
if (expr.Match<Max, Mul, Lit, Lit, Div, Lit, Lit>(out max, out mul, out x, out m, out div, out y, out d))
    return new Lit(Math.Max(x * m, y / d);
Re[15]: Функциональное программирование в Nemerle
От: Аноним  
Дата: 22.05.07 16:27
Оценка: :)
Здравствуйте, konsoletyper, Вы писали:

Спорить с вами konsoletyper, иногда все равно, что отнимать конфету у ребенка, слишком легко.
Вот назадавали мне кучу вопросов, а в конце, потребовали от модераторов, чтобы они меня забанили.
Зачем вопросы задавали, спрашивается, если ответов не хотели услышать? Ладно, предположу, что все-таки хотели.

K>Много рабочих компиляторов написал? Ссылки в студию, плиз.

У вас уже поинтересовались, насчет вашего собственного опыта в этом же деле.
Оказывается, вы решили, за Wolfhound вступиться, а нужна ли ему ваша защита, или он сам в случае чего разберется?

K>И попрошу не оправдываться. Если нечем подтвердить свою компетентность в данном вопросе, попрошу демагогии не разводить.

Судья спрашивает у подсудимого — вы признаете себя виновным? И попрошу не оправдываться.
Да и что такого сложного в написании компилятора, в общем смысле, раз уж вы не уточнили какого именно?
И по-моему, в любом программистском ВУЗе, одна из курсовых, обязательно написание компилятора.

K>Где-то так:


K>
K>| Pl(fi, se) => con(Pl(fir.Conv(conv), sec.Conv(conv))
K>

Оп-па, по количеству ввода Nemerle даже превзошел C#.

K>Только тут сразу происходит сопоставление по шаблону. А у тебя только возвращается результат.

Странно почему вам не пришло в голову, как же так возвращается результат, а сопоставление с образцом не происходит. Как же тогда работает программа, если результат возвращается не понятно, при каких условиях? Или все таки и у меня в данном случае есть сопоставление с образцом, только образец простой?

K>И вообще, надо не забывать, что код труднее читать, чем писать. Я на сниппетах тебе такого нагородить на brainfuck могу, что ты потом всю оставшуюся жизнь в нём разбираться будешь.

Код труднее читать, чем писать, могу написать на редком языке, трудно понимаемую программу.
Гм. Не понял. Трудно понимаемую можно и на многих распространенных языках написать.

K>Во-первых, хватит сравнивать тёплое с мягким.

Надо было пояснить, что теплое, а что мягкое. Подозреваю, что одно из них Nemerle, а другое C#. Путать, тогда, действительно не надо.

K>Во-вторых, варианты изначально так спроектирваны, чтобы поля опций записывались на одной строке с объявлением опции.

Понимаю, хорошие варианты хорошо спроектированы, им можно на одной строке. Плохие классы не так спроектированы — им нельзя.
class Mul { public Expr expr1, expr2; }

K>В третьих, with — это неотъемлемая часть образца, так что её не стоит выносить на отдельную строку. Наконец, если образцы достаточно короткие, то допустимо записывать их на одной строке.

Такую часть можно и в классах добавить.
class Oper: Expr
{
  public Oper(Expr expr1, Expr expr2, string sign) {...}
  public override ToString() { return expr1 + sign + expr2;}
}
class Plus: Oper
{
  public Plus(Expr expr1, Expr expr2): base(expr1, expr2, "+") {}
}

тогда для операторов не надо переопределять ToString — 1 строка экономии.
а в Nemerle тем не менее надо еще учесть выражение после => хоть оно и одно для четырех операторов.
Так что, соотношение между размером кода останется тоже.

K>И отбивки между образцами никто не ставит. Это всё равно, что ставить отбивки между if-ом и его телом или меджу различными case'ами в switch'е.

Почему же ставят и часто, при определенном стиле форматирования.
if (условие)
{
    тело
}


K>Вообще, читабельность — понятие субъективное.

Слава богу, я так и думал.

K>Кстати, допустимо всё это записать и так:

K>Так что твоя арифметика никому ничего не доказывает.
Ситуация обратная. Сначала мне приводят форматирование на C# (например с множеством пустых строк), а я просто применяю примерно такой же стиль к Nemerle (что уже оказывается особо тяжким преступлением). Стили же приведенных вами фрагментов практически диаметрально противоположны.

K>Всё-таки ты невменяемый.

Сумашедший гений? Что вы на гениальности не настаиваю, хотя видеть подобный крен в эпитетах приятно.
Впрочем, припоминаю, вы кажется уже хвалили мое умение искусно вести спор.

K>Что-то его функциональность сильно напоминает телепатию.

Не решились сказать, что напоминает сопоставление с образцом, решили сказать, что напоминает телепатию?

K>Кстати, очередные крики, что этот метод можно реконструировать, буду считать неконструктивом. Потому что нужно отвечать на вопрос, а не оправдываться.

Не все могут реконструировать, это я признавал.
Re[16]: Функциональное программирование в Nemerle
От: Аноним  
Дата: 23.05.07 23:47
Оценка: :)
Здравствуйте, Аноним, Вы писали:

K>>Всё-таки ты невменяемый.

А>Сумашедший гений? Что вы на гениальности не настаиваю, хотя видеть подобный крен в эпитетах приятно.
А>Впрочем, припоминаю, вы кажется уже хвалили мое умение искусно вести спор

Never argue with an idiot. He will lower you to his level and beat you with experience.

Как нельзя лучше объясняет твое "умение искусно вести спор".
Re: Функциональное программирование в Nemerle
От: Аноним  
Дата: 29.05.07 19:23
Оценка: -1
Здравствуйте, Чистяков Влад (VladD2), Вы писали:

Обратил внимание, что в примере для Nemerle используются варианты и за счет этого можно успешно перебирать их в match.
Однако для C# также можно сделать подобное

using System;
using PatternMatching;
using Variants;

delegate Expr Convert(Expr expr);

class Variant : Variant<Lit, Plus, Minus, Mul, Div, Max, Min, Foo> {}

abstract class Expr: IMatch
{
  public static implicit operator double(Expr expr) { return expr.Eval(); }
  public double Eval()
  {
    return Variant.Switch<double, Expr>(this,
      delegate(Lit lit) { return lit.Value; },
      delegate(Plus plus) { return plus.First + plus.Second; },
      delegate(Minus minus) { return minus.First - minus.Second; },
      delegate(Mul mul) { return mul.First * mul.Second; },
      delegate(Div div) { return div.First / div.Second; },
      delegate(Max max) { return Math.Max(max.First, max.Second); },
      delegate(Min min) { return Math.Min(min.First, min.Second); },
      delegate(Foo foo) { return foo.Value; });
  }
  public override string ToString()
  {
    return Variant.Switch<string, Expr>(this,
      delegate(Lit lit) { return lit.Value.ToString(); },
      delegate(Plus plus) { return plus.First + " + " + plus.Second; },
      delegate(Minus minus) { return minus.First + " - " + minus.Second; },
      delegate(Mul mul) { return mul.First + " * " + mul.Second; },
      delegate(Div div) { return div.First + " / " + div.Second; },
      delegate(Max max) { return "Max(" + max.First + ", " + max.Second + ")"; },
      delegate(Min min) { return "Min(" + min.First + ", " + min.Second + ")"; },
      delegate(Foo foo) { return "Foo(" + foo.Value + ")"; });
  }
  public Expr Convert(Convert convert)
  {
    return Variant.Switch<Expr, Expr>(this,
      delegate(Lit lit) { return convert(new Lit(lit.Value)); },
      delegate(Plus plus) { return convert(new Plus(plus.First.Convert(convert), plus.Second.Convert(convert))); },
      delegate(Minus minus) { return convert(new Minus(minus.First.Convert(convert), minus.Second.Convert(convert))); },
      delegate(Mul mul) { return convert(new Mul(mul.First.Convert(convert), mul.Second.Convert(convert))); },
      delegate(Div div) { return convert(new Div(div.First.Convert(convert), div.Second.Convert(convert))); },
      delegate(Max max) { return convert(new Max(max.First.Convert(convert), max.Second.Convert(convert))); },
      delegate(Min min) { return convert(new Min(min.First.Convert(convert), min.Second.Convert(convert))); },
      delegate(Foo foo) { return convert(new Foo(foo.Value.Convert(convert))); });
  }
  /*тут секретный метод в одну строку для сопоставления с образцом*/
}
class Lit: Expr
{ 
  public readonly double Value; 
  public Lit(double value) { this.Value = value; }
}
abstract class Oper: Expr
{
  public readonly Expr First, Second;
  public Oper(Expr first, Expr second) 
  { 
    First = first; 
    Second = second; 
  }
  /*тут секретный метод в одну строку для сопоставления с образцом*/
}
class Plus : Oper { public Plus(Expr first, Expr second) : base(first, second) { } }

class Minus : Oper { public Minus(Expr first, Expr second) : base(first, second) { } }

class Mul : Oper { public Mul(Expr first, Expr second) : base(first, second) { } }

class Div : Oper { public Div(Expr first, Expr second) : base(first, second) { } }

class Max : Oper { public Max(Expr first, Expr second) : base(first, second) { } }

class Min : Oper { public Min(Expr first, Expr second) : base(first, second) { } }

class Foo : Expr 
{
  public readonly Expr Value;
  public Foo(Expr value) { Value = value; }
  /*тут секретный метод в одну строку для сопоставления с образцом*/
}
class Program
{
  public static void Main(string[] arguments)
  {
    Convert(new Max(new Mul(new Lit(2), new Lit(1)), new Lit(3)), RemoveMulToOne);
    Convert(new Foo(new Mul(new Lit(1), new Lit(5))), RemoveMulOneTo);
    Convert(new Max(new Lit(5), new Lit(3)), RemoveMaxOfLit);
    Convert(new Max(new Mul(new Lit(2), new Lit(2)), new Div(new Lit(3), new Lit(3))), RemoveSpecialMax);
    Console.ReadLine();
  }
  public static void Convert(Expr expr, Convert convert)
  {
    Console.WriteLine("Expression '{0}' = {1}", expr, expr.Eval());
    Expr converted = expr.Convert(convert);
    Console.WriteLine("Converted expression '{0}' = {1}", converted, converted.Eval());
    Console.WriteLine();
  }
  static Expr RemoveMulToOne(Expr expr)
  {
    return new Pattern<Mul, Expr, Lit>().Replace<Expr>(expr,
      delegate(Mul mul, Expr first, Lit lit) { return lit == 1 ? first : expr; });
  }
  static Expr RemoveMulOneTo(Expr expr)
  {
    return new Pattern<Mul, Lit, Expr>().Replace<Expr>(expr,
      delegate(Mul mul, Lit lit, Expr second) { return lit == 1 ? second : expr; });
  }
  static Expr RemoveMaxOfLit(Expr expr)
  {
    return new Pattern<Max, Lit, Lit>().Replace<Expr>(expr,
      delegate(Max max, Lit lit1, Lit lit2) { return new Lit(Math.Max(lit1, lit2)); });
  }
  static Expr RemoveSpecialMax(Expr expr)
  {
    return new Pattern<Max, Mul, Lit, Lit, Div, Lit, Lit>().Replace<Expr>(expr,
      delegate(Max max, Mul mul, Lit x, Lit m, Div div, Lit y, Lit d) { return new Lit(Math.Max(x * m, y / d)); });
  }
}

Достаточно близкий аналог на Nemerle
using System;
using System.Console;
using Nemerle.Utility;
using Expr;

public variant Expr
{
  | Lit { value : double; }
  | Plus { first : Expr; second : Expr; }
  | Minus { first : Expr; second : Expr; }
  | Mul { first : Expr; second : Expr; }
  | Div { first : Expr; second : Expr; }
  | Max { first : Expr; second : Expr; }
  | Min { first : Expr; second : Expr; }
  | Foo { value : Expr; }
  public override ToString() : string
  {
    match (this)
    {
      | Lit(value) => value.ToString()
      | Plus(first, second) => $"$first + $second"
      | Minus(first, second) => $"$first - $second"
      | Mul (first, second) => $"$first * $second"
      | Div (first, second) => $"$first / $second"
      | Max(first, second) => $"Max($first, $second)"
      | Min(first, second) => $"Min($first, $second)"
      | Foo(value) => $"Foo($value)"
    }
  }
  public Eval() : double
  {
    match (this)
    {
      | Lit(value) => value
      | Plus(first, second) => first.Eval() + second.Eval()
      | Minus(first, second) => first.Eval() - second.Eval()
      | Mul(first, second) => first.Eval() * second.Eval()
      | Div(first, second) => first.Eval() / second.Eval()
      | Max(first, second) => Math.Max(first.Eval(), second.Eval())
      | Min(first, second) => Math.Min(first.Eval(), second.Eval())
      | Foo(value) => value.Eval()
    }
  }
  public Convert(converter : Expr -> Expr) : Expr
  {
    def res = match(this)
    {
      | Lit => this
      | Plus(first, second) => Plus(first.Convert(converter), second.Convert(converter))
      | Minus(first, second) => Minus(first.Convert(converter), second.Convert(converter))
      | Mul(first, second) => Mul(first.Convert(converter), second.Convert(converter))
      | Div(first, second) => Div(first.Convert(converter), second.Convert(converter))
      | Max(first, second) => Max(first.Convert(converter), second.Convert(converter))
      | Min(first, second) => Min(first.Convert(converter), second.Convert(converter))
      | Foo(value) => Foo(value.Convert(converter))
    }
    converter(res)
  }
}
module Program
{
  Main(_ : array [string]) : void
  {
    Convert(Max(Mul(Lit(2), Lit(1)), Lit(3)), RemoveMulToOne);
    Convert(Foo(Mul(Lit(1), Lit(5))), RemoveMulOneTo);
    Convert(Max(Lit(5), Lit(3)), RemoveMaxOfLit);
    Convert(Max(Mul(Lit(2), Lit(2)), Div(Lit(3), Lit(3))), RemoveSpecialMax);
    _ = ReadLine();
  }
  RemoveMulToOne(expr : Expr) : Expr
  {
    match(expr)
    {
      | Mul(first, Lit(1.0)) => first
      | _ => expr
    }
  }
  RemoveMulOneTo(expr : Expr) : Expr
  {
    match(expr)
    {
      | Mul(Lit(1.0), second) => second
      | _ => expr
    }
  }
  RemoveMaxOfLit(expr : Expr) : Expr
  {
    match(expr)
    {
      | Max(Lit(value1), Lit(value2)) => Lit(Math.Max(value1, value2))
      | _ => expr
    }
  }
  RemoveSpecialMax(expr : Expr) : Expr
  {
    match(expr)
    {
      | Max(Mul(Lit(x), Lit(m)), Div(Lit(y), Lit(d))) => Lit(Math.Max(x * m, y / d))
      | _ => expr
    }
  }
  Convert(expr : Expr, converter : Expr -> Expr) : void
  {
    WriteLine($"Expression '$expr' = $(expr.Eval())");
    def converted = expr.Convert(converter);
    WriteLine($"Converted expression '$converted' = $(converted.Eval())");
    WriteLine();
  }
}


Итог:
С# — 120 строк, 5206 байт, 120 символов самая длинная строка
Nemerle — 109 строк, 3368 байт, 91 символ самая длинная строка
Re[2]: Функциональное программирование в Nemerle
От: rameel https://github.com/rsdn/CodeJam
Дата: 29.05.07 19:40
Оценка: +1
Здравствуйте, <Аноним>, Вы писали:

Доктор, я слепой. Денег не вижу. (с)

... << RSDN@Home 1.2.0 alpha rev. 677>>
Re[4]: Функциональное программирование в Nemerle
От: IT Россия linq2db.com
Дата: 30.05.07 15:58
Оценка: +1
Здравствуйте, anonym469, Вы писали:

IT>>получалось примерно такое же г.

A>Компактное г, смею заметить. А не пятикратное г.

Г. оно хоть компактное, хоть не очень, всё равно г.

ЗЫ. Я то этой фигнёй занимался от безнадёги, т.к. меня с C++ на C обратно на какое-то время пересадили. А зачем тебе это надо совсем непонятно.
... << RSDN@Home 1.2.0 alpha rev. 0>>
Если нам не помогут, то мы тоже никого не пощадим.
Re[2]: Функциональное программирование в Nemerle
От: VladD2 Российская Империя www.nemerle.org
Дата: 31.05.07 11:06
Оценка: +1
Здравствуйте, Кэр, Вы писали:

Кэр>здесь в коде выделены жирным элементы, которые призваны улучшить читаемость


От догм и предрассудков лучше избавляться.

Кстати, есть один вопрос:
    | EndOfFile           => return stack.Count == 1
        ...
    | EndRound            => check(_ is Token.BeginRound)  // )

А почему в первой строчке return понадобился, а во второй нет?
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[4]: Функциональное программирование в Nemerle
От: konsoletyper Россия https://github.com/konsoletyper
Дата: 31.05.07 12:29
Оценка: :)
Здравствуйте, Кэр, Вы писали:

VD>>Кстати, есть один вопрос:

VD>>
VD>>    | EndOfFile           => return stack.Count == 1
VD>>        ...
VD>>    | EndRound            => check(_ is Token.BeginRound)  // )
VD>>

VD>>А почему в первой строчке return понадобился, а во второй нет?

Кэр>Как раз по тем причинам, что я указывал выше — return обозначает то место, где начнет разворачиваться стэк вызовов функций.

Кэр>Такой return
VD>>
VD>>    | EndRound            => return check(_ is Token.BeginRound)  // )
VD>>

Кэр>лишний. Здесь просто вычисления идут вглубь по стэку вызова.

Непоследовательно...
... << RSDN@Home 1.2.0 alpha rev. 672>>
Re[7]: Функциональное программирование в Nemerle
От: VladD2 Российская Империя www.nemerle.org
Дата: 31.05.07 13:28
Оценка: +1
Здравствуйте, Кэр, Вы писали:

Кэр>Ты даже готов следить за правильным именованием методов и переменных — лишь бы не указывать небольшую дополнительную информацию. Чем тебе так мешает этот : bool?


В данном случае указание типов особо не мешает. В прочем как и не помогает. И можно смело оставить выбор на умотрение разработчика. Вопрос в том, что довольно бессысленно вводить правило мобъявлять типы везде аргументируя это тем, что мол так понятнее.

Кажется, что в данном месте понятнее? Ну, поставь тип. Кажется, что и так все понятно — не ставь. Делов то.

Кэр>Под возращением я имел ввиду то место, где начинает разворачиваться стэк вызовов. Я понимаю отличие императивного и функционального кода


Если понимашь, то должен понимать, что на фукнцию без return-ов можно смотреть как на одно большое выражение. А выражение более предсказуемо. Его проще читать, так как знаешь, что логика у него вычислительная, а не императивная.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[10]: Функциональное программирование в Nemerle
От: VladD2 Российская Империя www.nemerle.org
Дата: 13.06.07 14:27
Оценка: +1
Здравствуйте, Кэр, Вы писали:

Кэр>От команды мне нужно многое — чтобы она выполнила нужный мне sql, на нужном sql сервере, с нужными параметрами.


Значит ты до сих пон не понял значение слова "абстракция" или не проникся всей важностью этого понятия.

Кэр> Я согласен, что всего узнать нельзя. Просто когда я вижу просто вызов конструктора для обще-известного класса я не полезу в потроха конструктора, чтобы проверить как он инициализируется — если там что-то не так — очень быстро это станет известно.

Кэр>Если же поставкой этого объекта занимается некий неизвестный мне интернальный framework и я первый раз его использую — я не только прочитаю документацию по вызову этого метода, но и скорее всего быстро пробегу по пути инициализации этого объекта.

Это довольно сумбурные рассуждения. У тебя должен выполняеться запрос. Пока это так, и пока он возвращает нужные тебе данные лезть куда бы то нибыло бессмысленно. На этом и основана разработка сложный систем. Иначе из-за мелкого вопроса пришлось бы каждый раз востанавливать в памяти все детали тонкости программы, а это практически невозможно.

Задача программиста уметь выделить нужное место и абстрагироваться от других. Причем это нгужное место тоже должно пониматься как можно более высокоуровенво. Если ты будешь думать о запросе как о наборе отдельных действий (конструктор, параметры, ...), то будешь тратить неприлично много времени на то чтобы въехать в конкретное место программы.

В общем, практика показывает, что конструкторы без new не только не создают проблем для чтения, но и упрощают его. Кода становится меньше и он начинает выглядеть более естественно.

Кэр>Да, при объявлении анонимных функций часто можно опускать типы входящих параметров и результата. Пока это умолчание не становится повсеместным... Но не будем по второму кругу


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

VD>>Вот в C# из конструкторов можно взывать виртуальные метода. На форумах не раз поднимался вопрос об опасности этого. Но еще ни разу я не видел реального случая когда это привело бы к проблемам. Значит проблема надумана. И обсуждать ее смысла нет.


Кэр>Не надо из частного случая и частного опыта выводить общее правило.


Никто этого и не делает. Просто все на свете частный случаи. Я тебе говорю о том, что просто не стоит искать гипотетические проблемы. Они или есть (реально, на практике) или их нет. Тут нужно просто тупо пробовать и смотреть на результат. Мой опыт показывает, что проблем в отсуствии аннотаций типов нет. И я довольно давно пишу на этом языке. Со временем появится статистика. Вот тогда и посмотрим. А мнение людей которые в основном писали только на языках с обязательной и повсеместной аннотацией типов изначально предвзятое. Нужно чтобы прошло хотя бы пол года после того как такие люди начинают использовать язык с выводом типов, чтобы их мнение можно было бы счесть более-менее не предвзятым.

Кэр> Я вот тоже думал, что рассуждения о beforefieldinit аттрибуте при определении ленивого синглтона через static конструктор — рассуждения сугубо теоритические. И вот недавно в проекте наступили на эту проблему весело и с размаху

Кэр>Проблема с вызовом виртуальных методов в конструкторах — тоже себе вполне живая и забывать о ней не стоит.

Тут дело какое? Если на грабли наступают часто и стройными рядами, то это косяк в языке/рантайме и т.п. А если это разовый случай, то это лучше списать на то, что конкретные программисты немного ступили.

Всех проблем не избежать. Более того, то что кажется одному проблемой для другого является очень удобной вещь. Так что клеймить что-то граблями нужно только если на них наступают много народа.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re: Функциональное программирование в Nemerle
От: icWasya  
Дата: 22.03.07 12:40
Оценка:
Здравствуйте, Чистяков Влад (VladD2), Вы писали:

ЧВV>Статья:

ЧВV>Функциональное программирование в Nemerle
Автор(ы): Чистяков Влад (VladD2)
Дата: 03.03.2007
Язык программирования Nemerle заинтересовал многих в первую очередь своей мощнейшей подсистемой мак-росов. Однако и без них Nemerle предоставляет ряд су-щественных улучшений по сравнению с традиционными, императивными языками программирования (такими как Java, C# и C++).
Nemerle, кроме традиционного императивного програм-мирования, поддерживает функциональное программи-рование. Это выражается в наличии конструкций, упро-щающих манипуляцию функциями, построение и анализ сложных структур данных и т.п.
К сожалению, если вы не использовали возможности, присущие функциональным языкам ранее, то вам будет трудно оценить, насколько Nemerle может оказаться вам полезным в реальной повседневной работе. Данная статья призвана в неформальной форме продемонс-трировать это.


ЧВV>Авторы:

ЧВV> Чистяков Влад (VladD2)

А как попасть на эту статью через меню
Статьи->
Nemerle->
Функциональное программирование в Nemerle
Re[2]: Функциональное программирование в Nemerle
От: VladD2 Российская Империя www.nemerle.org
Дата: 22.03.07 13:59
Оценка:
Здравствуйте, icWasya, Вы писали:

W>А как попасть на эту статью через меню

W>Статьи->
W> Nemerle->
W> Функциональное программирование в Nemerle

Чуть позже ее добавят вразделы:
/Статьи/Декларативное программирование/Nemerle и /Статьи/.NET/Nemerle
Сейчас она просто не выложена.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re: Функциональное программирование в Nemerle
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 25.03.07 07:15
Оценка:
Здравствуйте, Чистяков Влад (VladD2), Вы писали:

Здравствуй на нашу пользу, не болей. Ждем статью про макросы
и солнце б утром не вставало, когда бы не было меня
Re[2]: небольшие правки
От: VladD2 Российская Империя www.nemerle.org
Дата: 09.05.07 07:44
Оценка:
Здравствуйте, Иванков Дмитрий, Вы писали:...

Спаисбо, постараемся в ближаейшее время поправить.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re: Функциональное программирование в Nemerle
От: AngeL B. Россия  
Дата: 09.05.07 17:57
Оценка:
Не компилируется пример из статьи. На кусок
// Другой вариант частичного применения. В этот раз первому параметру 
// назначен строковый литерал.
def f = WriteLine("Еще один вариант - '{0}'", _);
f("частичного применения функции");


компилятор у меня матерится следующим образом
in argument #1 of f, needed a array [System.Object]+, got string: string is not a subtype of array [System.Object] [simple require]

версия компилятора 0.9.3.
Что и где не так?
Re[2]: Функциональное программирование в Nemerle
От: Иванков Дмитрий Россия  
Дата: 09.05.07 18:48
Оценка:
Здравствуйте, AngeL B., Вы писали:

AB>Не компилируется пример из статьи. На кусок

AB>
AB>// Другой вариант частичного применения. В этот раз первому параметру 
AB>// назначен строковый литерал.
AB>def f = WriteLine("Еще один вариант - '{0}'", _);
AB>f("частичного применения функции");
AB>


AB>компилятор у меня матерится следующим образом

AB>in argument #1 of f, needed a array [System.Object]+, got string: string is not a subtype of array [System.Object] [simple require]

AB>версия компилятора 0.9.3.

AB>Что и где не так?

Не очень хорошо вышло, в 0.9.3 баг, в trunk версии бага нет, как минимум с r7392 (самое старое что есть под рукой).
Варианты исправления:
1) забрать из svn последнюю версию
2) забрать свежий daily snapshot
3) исправить пример
def f = x : string => WriteLine("Еще один вариант - '{0}'", x);
f("частичного применения функции");


Причем в случаях 1 и 2 даже необязательно собирать компилятор, бинарники в boot там этого бага не имеют.
Re: замыкания
От: x-code  
Дата: 09.05.07 19:12
Оценка:
Здравствуйте, Чистяков Влад (VladD2), Вы писали:

Все отлично, статья очень понравилась, но хотелось бы как-то раскрыть понятие "замыкания" для людей, до этого не имевших дело с ФП. Это что физически такое?
Как я понял — средство упаковки функции вместе с некоторым количеством локальных переменных (аргументов функции и т.п.) в единый объект? Или я не прав?
Re[2]: замыкания
От: _FRED_ Черногория
Дата: 10.05.07 07:13
Оценка:
Здравствуйте, x-code, Вы писали:

XC>Все отлично, статья очень понравилась, но хотелось бы как-то раскрыть понятие "замыкания" для людей, до этого не имевших дело с ФП. Это что физически такое?


Подробнее об этом сказано в других статьях. Пример: Анонимные методы в C# 2.0
Автор(ы): Patrick Smacchia
Дата: 30.07.2006
Статья представляет новое свойство языка C# версии 2.0, называемое анонимными методами.
.

XC>Как я понял — средство упаковки функции вместе с некоторым количеством локальных переменных (аргументов функции и т.п.) в единый объект? Или я не прав?


Примерно, прав.
Help will always be given at Hogwarts to those who ask for it.
Re[2]: Функциональное программирование в Nemerle
От: VladD2 Российская Империя www.nemerle.org
Дата: 10.05.07 09:34
Оценка:
Здравствуйте, AngeL B., Вы писали:

AB>версия компилятора 0.9.3.

AB>Что и где не так?

Компилятор в 0.9.3 имел много багов и недоработок. Этот код проверялся на последней версии.

Можно взять бинарники компилятора из boot-а:
http://nemerle.org/svn/nemerle/trunk/boot

Или попробовать одну из CTP-версий интеграции (к сожалению последняя версия не досутпна, но можно попробовать апрельскую Nemerle APR 2007 CTP (вторая попытка)
Автор: Блудов Павел
Дата: 09.04.07
).

Так же можно собрать компилятор самому, что сложнее, но дает самую последнию версию плюс рабочую версию интеграции.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[2]: замыкания
От: VladD2 Российская Империя www.nemerle.org
Дата: 10.05.07 09:34
Оценка:
Здравствуйте, x-code, Вы писали:

XC>Все отлично, статья очень понравилась, но хотелось бы как-то раскрыть понятие "замыкания" для людей, до этого не имевших дело с ФП. Это что физически такое?

XC>Как я понял — средство упаковки функции вместе с некоторым количеством локальных переменных (аргументов функции и т.п.) в единый объект? Или я не прав?

Именно так. Рассматривать их лучше не как объекты, а как отдельную абстракцию, но взгляд на замыкания как на эдакие инлайн-объекты тоже имеет право на жизнь. Собственно так и делается в компиляторе Nemerle. Но все может измениться. В принципе хороший оптимизирующий компилятор может переписывать код программы устраня как такие невидимые классы, так и вызов метода по ссылки. Но это уже детали реализации компиляторов.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[2]: замыкания
От: nikov США http://www.linkedin.com/in/nikov
Дата: 10.05.07 16:37
Оценка:
Здравствуйте, x-code, Вы писали:

XC>Все отлично, статья очень понравилась, но хотелось бы как-то раскрыть понятие "замыкания" для людей, до этого не имевших дело с ФП. Это что физически такое?


Closure, Замыкание
Re: Функциональное программирование в Nemerle
От: Аноним  
Дата: 14.05.07 10:52
Оценка:
Здравствуйте, Чистяков Влад (VladD2), Вы писали:

По поводу интерпретатора арифметических выражений:

В C# версии реализован паттерн Visitor, а в Nemerle версии нет.
А было бы "замечательно" если бы у каждого варианта был бы метод Accept.

Вот аналог того, что в Nemerle на C#

using System;

abstract class Expression
{
    public virtual double Eval() 
    { 
        Literal literal = this as Literal; 
        if (literal != null) 
        {
            return literal.Value;
        }
        Operation operation = this as Operation; 
        if (operation != null)
        {
            if (this is Min) return Math.Min(operation.First.Eval(), operation.Second.Eval());
            if (this is Max) return Math.Max(operation.First.Eval(), operation.Second.Eval());
            if (this is Plus)  return operation.First.Eval() + operation.Second.Eval();
            if (this is Minus) return operation.First.Eval() - operation.Second.Eval();
            if (this is Mul)   return operation.First.Eval() * operation.Second.Eval();
            if (this is Div)   return operation.First.Eval() / operation.Second.Eval();
        }
        throw new InvalidOperationException(ToString());
    }

    public new virtual string ToString() 
    {
        Literal literal = this as Literal; 
        if (literal != null) 
        {
            return literal.Value.ToString();
        }
        Operation operation = this as Operation; 
        if (operation != null)
        {
            if (this is Min) return "Min(" + operation.First.ToString() + ", " + operation.Second.ToString() + ")";
            if (this is Max) return "Max(" + operation.First.ToString() + ", " + operation.Second.ToString() + ")";
            if (this is Plus)  return operation.First.ToString() + " + " + operation.Second.ToString();
            if (this is Minus) return operation.First.ToString() + " - " + operation.Second.ToString();
            if (this is Mul)   return operation.First.ToString() + " * " + operation.Second.ToString();
            if (this is Div)   return operation.First.ToString() + " / " + operation.Second.ToString();
        }
        throw new InvalidOperationException(base.ToString());
    }
}

class Literal: Expression
{
    private double value;
    public double Value { get { return value; } }
    public Literal(double value) { this.value = value; }
}

abstract class Operation: Expression
{
    private Expression first, second;
    public Expression First { get {return first; } }
    public Expression Second { get {return second; } }
    public Operation(Expression first, Expression second)
    {
        this.first = first;
        this.second = second;
    }
}

class Min:   Operation { public Min  (Expression first, Expression second): base(first, second) {} }
class Max:   Operation { public Max  (Expression first, Expression second): base(first, second) {} }
class Plus:  Operation { public Plus (Expression first, Expression second): base(first, second) {} }
class Minus: Operation { public Minus(Expression first, Expression second): base(first, second) {} }
class Mul:   Operation { public Mul  (Expression first, Expression second): base(first, second) {} }
class Div:   Operation { public Div  (Expression first, Expression second): base(first, second) {} }

public class Program
{
    public static void Main(string[] arguments)
    {        
        Expression expression = new Plus(new Literal(1.23), new Min(new Literal(3.45), new Literal(1.23)));
        Console.WriteLine("Expression '{0}' = {1}", expression.ToString(), expression.Eval());
    }
}
Re[2]: Функциональное программирование в Nemerle
От: VladD2 Российская Империя www.nemerle.org
Дата: 14.05.07 15:45
Оценка:
Здравствуйте, <Аноним>, Вы писали:

А>Здравствуйте, Чистяков Влад (VladD2), Вы писали:


А>По поводу интерпретатора арифметических выражений:


А>В C# версии реализован паттерн Visitor, а в Nemerle версии нет.


Естественно, так как он попросту не нужен при наличии паттерн-матчинга.

А>А было бы "замечательно" если бы у каждого варианта был бы метод Accept.


Не вижу ничего замечательного в этом. Использование данного паттерна — это проектное решение. В чистом ООП оно имеет смысл, так как упрощает равитие системы, при наличии паттерн-матчинга оно попросту бессмысленно.

А>Вот аналог того, что в Nemerle на C#


Это как раз поптыка эмулировать паттерн-матчинг на C#. Только у этого решенпия есть две прблемы которые заставят отказаться от него.
1. Нет никаких гарантий, что обработаны все варианты. О том, что какой-то варинат не обработан будет известно только в рантайме. Стало быть мы получаем самые плохие стороны динамики в казалось бы статически типизированном языке. Вариант с паттерн-мачингом дает нам такие гарантии (компилятор проверяет полноту паттернов).
2. Это очень примитивный случай. В нем паттерн-матчинг действительно не так сложно эмулировать на операторах is/as. Но с разрастанием кода станет очевидным, что эмуляция хуже оригинала. Как я говорил в статье, паттерн-матчинг поддерживеет сложные вложенные паттерны, что значительно увеличивает наши возможности. Например, если нам понадобиться распознать некий паттерн в коде (ну скажем упростить мат.выражения), то с паттерн-матчингом прийдется добавить всего пару строк кода, а в императивном коду это уже красиво не выразить. Прийдется лепить кучи if-ов.

Ну, и надо заметить, что кода все равно значительно больше чем на Nemerle, хотя и не так много как в чисто ОО-решении. К тому же в нем ради "укомпакчивания" кода бвли допущены разные вольности вроде наличия Value у всех выражений хотя только оно нужно только у литералов.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[3]: Функциональное программирование в Nemerle
От: Аноним  
Дата: 14.05.07 16:58
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>В чистом ООП оно имеет смысл, так как упрощает равитие системы, при наличии паттерн-матчинга оно попросту бессмысленно.

А главное отжирает по три строке в каждом классе. Я к тому, что в том примере C# и Nemerle сравнивались нечестно, за счет чего и получилась, столь впечатляющая разница в объеме кода в строках. В килобайтах, кстати не так много, не в 5 раз, а в 3.

VD>2. Это очень примитивный случай. В нем паттерн-матчинг действительно не так сложно эмулировать на операторах is/as. Но с разрастанием кода станет очевидным, что эмуляция хуже оригинала. Как я говорил в статье, паттерн-матчинг поддерживеет сложные вложенные паттерны, что значительно увеличивает наши возможности. Например, если нам понадобиться распознать некий паттерн в коде (ну скажем упростить мат.выражения), то с паттерн-матчингом прийдется добавить всего пару строк кода, а в императивном коду это уже красиво не выразить. Прийдется лепить кучи if-ов.

Ну и где такой пример, который бы с одной стороны имел достаточную сложность для показа превосходства Nemerle, а с другой не являлся бы, например, исходниками компилятора Nemerle.


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

В этом и мысль. Конечно превосходство Nemerle очевидно при сравнении 250 строк кода на С# и 50 строк кода на Nemerle, однако если аналогичный код на С# легко умещается в 80 строк, преимущество Nemerle испаряется.

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

Этого нет, Value только у Literal'ов.
Re[4]: Функциональное программирование в Nemerle
От: konsoletyper Россия https://github.com/konsoletyper
Дата: 14.05.07 18:45
Оценка:
Здравствуйте, <Аноним>, Вы писали:

VD>>2. Это очень примитивный случай. В нем паттерн-матчинг действительно не так сложно эмулировать на операторах is/as. Но с разрастанием кода станет очевидным, что эмуляция хуже оригинала. Как я говорил в статье, паттерн-матчинг поддерживеет сложные вложенные паттерны, что значительно увеличивает наши возможности. Например, если нам понадобиться распознать некий паттерн в коде (ну скажем упростить мат.выражения), то с паттерн-матчингом прийдется добавить всего пару строк кода, а в императивном коду это уже красиво не выразить. Прийдется лепить кучи if-ов.

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

См. исходники здесь. Особое внимание советую обратить на src/Common/Bnf/BnfUtils.n. И заодно рекомендую прикинуть, как будет выглядеть аналогичный код на C#, и сколько времени уйдёт на его написание.

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

А>В этом и мысль. Конечно превосходство Nemerle очевидно при сравнении 250 строк кода на С# и 50 строк кода на Nemerle, однако если аналогичный код на С# легко умещается в 80 строк, преимущество Nemerle испаряется.

Это эчень искусственно. В данном случае имеет место ужимание строк. Если честно эмулировать паттерн-матчинг, то строк должно быть около 120. Более чем в 2 раза — уже достойный результат. Причём, это C# так хорошо отделался на простом примере, дай ему что-то посложнее, и он быстро обломается.

Кстати, советую ещё обратить внимание на слова Влада про то, что компилятор Nemerle проверяет, все ли варианты отловлены и предупреждает в случае необходимости. А подчас помощь компилятора в нахождении ошибок за программиста — это гораздо больший плюс, нежели лаконичность.
... << RSDN@Home 1.2.0 alpha rev. 672>>
Re[5]: Функциональное программирование в Nemerle
От: Аноним  
Дата: 14.05.07 20:55
Оценка:
Здравствуйте, konsoletyper, Вы писали:

K>Здравствуйте, <Аноним>, Вы писали:


K>См. исходники здесь. Особое внимание советую обратить на src/Common/Bnf/BnfUtils.n. И заодно рекомендую прикинуть, как будет выглядеть аналогичный код на C#, и сколько времени уйдёт на его написание.

Гляну.

K>Если честно эмулировать паттерн-матчинг, то строк должно быть около 120. Более чем в 2 раза — уже достойный результат.

Не вижу, где нечестно и чего нехватает.

K>Причём, это C# так хорошо отделался на простом примере, дай ему что-то посложнее, и он быстро обломается.

Из данного примера облом не очевиден.

K>Кстати, советую ещё обратить внимание на слова Влада про то, что компилятор Nemerle проверяет, все ли варианты отловлены и предупреждает в случае необходимости. Я обратил. Пока думаю, как реализовать это на C#.
Re[6]: Функциональное программирование в Nemerle
От: Аноним  
Дата: 14.05.07 21:13
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Я обратил. Пока думаю, как реализовать это на C#.


Достаточно перенести код для ToString и Eval в методы класса, тем самым если появится новый класс — то эти методы придется реализовать
using System;

abstract class Expression
{
    public abstract double Eval();
    public override abstract string ToString();
}

class Literal: Expression
{
    private double value;
    public double Value { get { return value; } }
    public Literal(double value) { this.value = value; }
    public override double Eval() { return value; }
    public override string ToString() { return value.ToString(); }
}

abstract class Operation: Expression
{
    private Expression first, second;
    public Expression First { get {return first; } }
    public Expression Second { get {return second; } }
    public Operation(Expression first, Expression second)
    {
        this.first = first;
        this.second = second;
    }
}

class Min: Operation 
{ 
    public Min  (Expression first, Expression second): base(first, second) {} 
    public override double Eval() { return Math.Min(First.Eval(), Second.Eval()); }
    public override string ToString() { return "Min(" + First.ToString() + ", " + Second.ToString() + ")"; }
}

class Max: Operation 
{ 
    public Max(Expression first, Expression second): base(first, second) {} 
    public override double Eval() { return Math.Max(First.Eval(), Second.Eval()); }
    public override string ToString() { return "Max(" + First.ToString() + ", " + Second.ToString() + ")"; }
}

class Plus: Operation 
{ 
    public Plus(Expression first, Expression second): base(first, second) {} 
    public override double Eval() { return First.Eval() + Second.Eval(); }
    public override string ToString() { return First.ToString() + " + " + Second.ToString(); }
}

class Minus: Operation 
{ 
    public Minus(Expression first, Expression second): base(first, second) {} 
    public override double Eval() { return First.Eval() - Second.Eval(); }
    public override string ToString() { return First.ToString() + " - " + Second.ToString(); }
}

class Mul: Operation 
{ 
    public Mul(Expression first, Expression second): base(first, second) {}
    public override double Eval() { return First.Eval() * Second.Eval(); }
    public override string ToString() { return First.ToString() + " * " + Second.ToString(); }
}

class Div: Operation 
{ 
    public Div  (Expression first, Expression second): base(first, second) {} 
    public override double Eval() { return First.Eval() / Second.Eval(); }
    public override string ToString() { return First.ToString() + " / " + Second.ToString(); }
}

public class Program
{
    public static void Main(string[] arguments)
    {        
        Expression expression = new Plus(new Literal(1.23), new Min(new Literal(3.45), new Literal(1.23)));
        Console.WriteLine("Expression '{0}' = {1}", expression.ToString(), expression.Eval());
    }
}
Re[4]: Функциональное программирование в Nemerle
От: VladD2 Российская Империя www.nemerle.org
Дата: 14.05.07 21:22
Оценка:
Здравствуйте, <Аноним>, Вы писали:

VD>>В чистом ООП оно имеет смысл, так как упрощает равитие системы, при наличии паттерн-матчинга оно попросту бессмысленно.

А>А главное отжирает по три строке в каждом классе. Я к тому, что в том примере C# и Nemerle сравнивались нечестно, за счет чего и получилась, столь впечатляющая разница в объеме кода в строках. В килобайтах, кстати не так много, не в 5 раз, а в 3.

Ох уж мне эти приверженцы единственно правильных решений.

Отжирается конечно не по три строки. В приличном ОО-обществе принято каждый класс помещать в тдельный файл, а значит для каждого из них дублируется просторанство имен, using-и и прочая дрибедень. Здесь svn://rsdn.ru/RSharp находятся исходники R# который я создал до знакомства с Nemerle. Уверя, что если бы я писал подобный код сейчас и на Nemerle, то он был бы не в 3 или 5 раз меньше, а раз в 10.

VD>>2. Это очень примитивный случай. В нем паттерн-матчинг действительно не так сложно эмулировать на операторах is/as. Но с разрастанием кода станет очевидным, что эмуляция хуже оригинала. Как я говорил в статье, паттерн-матчинг поддерживеет сложные вложенные паттерны, что значительно увеличивает наши возможности. Например, если нам понадобиться распознать некий паттерн в коде (ну скажем упростить мат.выражения), то с паттерн-матчингом прийдется добавить всего пару строк кода, а в императивном коду это уже красиво не выразить. Прийдется лепить кучи if-ов.

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

Понимаю, что мышление человека инерно. По этому предлагаю начать с малого. Давай расширим оба примера поддержкой фунций с 3 и 5 параметрами. Причем на этот раз ты продемонстриуешь свое решение первым.

Вторая здачка будет интереснее. Произвольная трансформация выражений. Берем исходное выражение применяем к нему некоторую функцию в параметах которой задем условия трасформации и получаем на выходе трансформированное (оптимизированное выражение). Для простоты, в качестве теста, будем использовать следующую оптимизацию — если выражение преставляет из себя "<любое выражение> * 1", то заменяем его на "<любое выражение>". Причем подразумевается, что это всего лишь один из возможных вариантов замены. Другими словами вызвав код вида:
expr = expr.Convert(<условия преобразования>);

мы должны получить преобразованное выражение.
Например:
До трансформации
Expression '1.23 + max(1, 2) * 1' = 3.23

После трансформации
Expression '1.23 + max(1, 2)' = 3.23

Задача понятна?
Теперь ход что называется за тобой. Ты представляешь свое решение, а затем я демонструю свое. Кстити, свое я уже написал .

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

А>В этом и мысль.

В чем? В том, что ты потерял все приемущество ООП, но все равно не достиг такой же ясности и простоты кода?

А> Конечно превосходство Nemerle очевидно при сравнении 250 строк кода на С# и 50 строк кода на Nemerle, однако если аналогичный код на С# легко умещается в 80 строк, преимущество Nemerle испаряется.


Знаешь, многие были бы счасливы иметь 50 строк вместо 80, но на практике предпочитают 250, так как пользоваться инструментами вроде Nemerle они не умеют или боятся, а используя ООЯ прибегают к классическим паттернам проектирования приводящим именно к 250-строчному коду. И я их понимаю (правда, понимаю только в выборе паттернов, но не инструмента и парадигмы).

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

А>Этого нет, Value только у Literal'ов.

Ой. Сори. Это я невнимательно смотрел код. Ну, да когда ты попыташся добавить поддеркжу метода с 3 и т.п. параметрами ты увидишь, что косяки поползут сами собой. А уж пример с оптимизацией, надесь, приведет к полному прозрению.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[6]: Функциональное программирование в Nemerle
От: VladD2 Российская Империя www.nemerle.org
Дата: 14.05.07 21:42
Оценка:
Здравствуйте, <Аноним>, Вы писали:

K>>Если честно эмулировать паттерн-матчинг, то строк должно быть около 120. Более чем в 2 раза — уже достойный результат.

А>Не вижу, где нечестно и чего нехватает.

А ты реализуй предложенные мной расширения и увидишь. Понимаешь, ли в чем дело? Ты изменил дизайн кода в рассчете на конекретные ограничения. Например, функция у тебя имеет принципиально 2 параметра (она же выражение с двумя праметрами), в варинте с паттерн-матчингом это не имеет значения. Вместо паттерна:
Call("max", [arg1, arg2])

всегда можно написать:
Call("max", [arg1, arg2, arg3, arg4, arg5])

Это ничего не стоит в поддержке. У нас же список, а не наследование.

K>>Причём, это C# так хорошо отделался на простом примере, дай ему что-то посложнее, и он быстро обломается.

А>Из данного примера облом не очевиден.

На самом деле конечно же C# не сломается ни на каком примере. Просто чем дальше в лес, тем очевиднее будет, что код на C# далек от идиала.

Примером для посвященных тут является сам компилятор Nemerle. Это всего 1.5 мегабайта кода, но делает этот код коду больше чем делает код трех компиляторов ООЯ вместе взятых.

Но главное даже не то, что код получается значительно компактнее, а то, что его намного проще изменять. Вот два примера из, что называется, совсем ближайшего прошлого:
Добавил поддержку auto-property (как в C# 3.0)
Автор: VladD2
Дата: 09.05.07

Прикольный макрос похожий на предыдущее расширение
Автор: VladD2
Дата: 14.05.07


Исползуй я C# или темболее C++ и вряд ли бы я вообще отважился на добавление подобного расширения. А с паттерн-матчингом и квази-цитированием (супер-мега-фича для генерации кода) — это превратилось в веселое интеллектуальное развлечение на вечер. Точнее первая на вечер, а вторая вообще заняла 20 минут.

Так что исползование С++ в разрботке компилятора C# является настоящим преступленим — преступной халатностью. Ведь имея в своем распоряжении типобезопасный язык с паттерн-матчингом и квази-цитированием они могли бы сократить время воплощения фич с лет до месяцев и даже недель. И я уже не говорю о прототипировании и тестировании.

Но у МС моного делег и они могут позволить себе писать даже на ассемблере (что и происходило во времена ДОС-а). А у большинства из нас таких сверх-ресурсов нет .
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[7]: Функциональное программирование в Nemerle
От: VladD2 Российская Империя www.nemerle.org
Дата: 14.05.07 21:42
Оценка:
Здравствуйте, <Аноним>, Вы писали:

А>>Я обратил. Пока думаю, как реализовать это на C#.


А>Достаточно перенести код для ToString и Eval в методы класса, тем самым если появится новый класс — то эти методы придется реализовать


Позрдарвлю ты вернулся к ООП .

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

Следующим шагом будет избавление от большого количества методов в телах АСТ-классов и группировка их в одном месте, то есть реализация паттерна Посетитель. Так поступают 99% создателей компиляторов использующих ООЯ. И я их понимаю.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[5]: Функциональное программирование в Nemerle
От: VladD2 Российская Империя www.nemerle.org
Дата: 14.05.07 23:22
Оценка:
Здравствуйте, konsoletyper, Вы писали:

K>См. исходники здесь. Особое внимание советую обратить на src/Common/Bnf/BnfUtils.n. И заодно рекомендую прикинуть, как будет выглядеть аналогичный код на C#, и сколько времени уйдёт на его написание.


Кстати, в файле Common.Tests.nproj убери версию NUnit-а, а то, например, у меня это дело не компилируется. Достаточно:
    <Reference Include="nunit.framework"/>

nunit.framework регистриуется в ГАК-е. Так что полные пути к нему не нужны.

И еще хорошо бы избавиться от варнинков. А то их слишком много. Темболее что у Немерла варнинги — это почти ошибки.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[6]: Функциональное программирование в Nemerle
От: konsoletyper Россия https://github.com/konsoletyper
Дата: 15.05.07 20:17
Оценка:
Здравствуйте, <Аноним>, Вы писали:

А>Не мог вечером зайти в форум, какая-то ошибка, связанная с Dictionary Key, поэтому вечером писал по-памяти, что прочитал с утра, так что требования не соблюдены точно, но достаточно изоморфны.


В смысле

А>150 строк, пока в c# не разочаровался.


[skip]

А мне казалось, что грамотнее было бы при упрощении выражения не модифицировать новое дерево, а конструировать новое. Кроме того, стоит оставлять по одной строчке между методами — в приведённом виде код читается плохо. Так же я уверен, что код, упрощающий выражения вида 1 * x и x * 1 на C# получился бы длиннее (и запутаннее).
... << RSDN@Home 1.2.0 alpha rev. 672>>
Re[9]: Функциональное программирование в Nemerle
От: VladD2 Российская Империя www.nemerle.org
Дата: 15.05.07 21:24
Оценка:
Здравствуйте, <Аноним>, Вы писали:

А>Похоже, Посетитель — плохой паттерн.


На самом деле это очень хороший паттерн, так как позволяет решить две не маловажные задачи:
1. Вынести обработку из множества классов и поместить ее в один класс. Таким образом мы можем групировать обработку по соврешаемому действию, а не завить по туче классов выискивая их.
2. Он позволяет организовать двойную диспетчиризацию.

Вот только все это делается паттерн-матчингом намного лучше.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[6]: Функциональное программирование в Nemerle
От: VladD2 Российская Империя www.nemerle.org
Дата: 15.05.07 21:30
Оценка:
Здравствуйте, <Аноним>, Вы писали:

Да, забыл сказать...

Я не даром попросил тебя написать код первым. Проблема ООП не только в том, что не для всех задач в нем есть удобные и красивые решения, а в том, что он еще и наявзявает императивный образ мышления. Так что твой код несомненно можно причесать, сделав более универасальным и кратким. Но до кода на языке поддерживающем паттерн-мачинг он не дотянется. И совершенно бессысленно пытаться выиграть строчки за счет "укомпакчивания" кода. Ведь читаться он будет в лучшем случае так же как нормально отформатированный (а реально хуже). Тут же выигрышь не за счет компактной записи, а за счет применения более мощьных (и более подходящих для данной задачи) средств.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[2]: Функциональное программирование в Nemerle
От: VladD2 Российская Империя www.nemerle.org
Дата: 17.05.07 13:26
Оценка:
Здравствуйте, FDSC, Вы писали:

FDS>Честно скажу: старался читать внимательно и прочитал даже чуть больше половины После чего у меня перегорел последний защитный предохранитель и я понял: "Влад опять рассказывает фичи Немерле по отдельности...".


Здесь был бы очень полезен анализ того, что напрягло и в каком конкретно месте перегорел предохранитель. Глядишь можно было бы дополнить статью или при написании новой учесть ошибки старой.

FDS>P.S. Для тех, кто не понял. Опять не рассказали, как думать так, что бы использовать возможности Nemerle, зато привели кучу примеров, какие возможности у него есть. Короче говоря, как правильно было сказано, для того, что бы понять преимущества Немерле, нужно начать на нём правильно писать программы, но вот как правильно их писать я так и не понял в очередной раз.


Это действительно сложный вопрос. Я тоже не знаю на него ответа. Вот если передо мной стоит конкретна задача, то наверно я смогу объяснить как бы я ее решил и поучему. А вот как сформулировать общие принцыпы я незнаю.

Наверно общим принципом является дизайнерский выбор того как решать задачу. Если выбирается подход с эмуляцией проблемы с помощью объектов и изменения их состояний, то надо использовать ОО-фичи языка которые почти 1 в 1 как в C#. Другой подход который можно предпочесть — это описание модели как набора вариантов, а их обработку как набор преобразований (конвертаций) этих данных в другие представления.

По сути это и есть выбор междц ООП и ФП. Во втором случае и используются фунциональные фичи вроде вариантов, паттерн-матчинга и функций высшиго порядка.

Вот приведенный пример калькулятора как раз хорошо подпадает под фунициональное решение. На входе мы имеем модель одного вида (AST), а на выходе другого (вычесленное выражение и строковое предсавление). Приведенный здесь
Автор: VladD2
Дата: 16.05.07
пример оптимизации тоже подподает под понятие "конвертации".

FDS>Кода в статье слишком много... воды бы побольше.... хочется услышать чего-то общего, каких-то графических схем, сравнения, скажем, структуры (не кода) программы на C# 1.1 и Nemerle, потому что всякие там вещи по типу "смотрится лучше" и "написать что-то(_, x) вместо определения вспомогательной функции" всё-таки не производит впечатления, если учесть, что нужно для этого переходить на язык, интеграция которого к VisualStudio требует скачать огромную SDK...


Ну, SDK не требуется. В прочем SDK по сравнению с самой студией — это просто ничто (студия гигабайты, а SDK сто с копейками мег.).

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

По сути учиться писать фунционально можно и на C# 2.0. Только результат не всего удет выглядеть хорошо. Но это не главное. Главное научиться думать о прорамме как о серии преобразований исходных данных в конечные. Тогада все непонятные фичи вдруг сразу станут очень понятными и удобными.

FDS> неудобства пока перевешивают удобства. Хотя, конечно, те же замыкания — это жутко приятно


Да, замыкания в купе с локальными функциями и лямбдами — это супер. И приятно, что это очевидно. Но паттерн-матчинг и варинаты — это тоже очень удобно. Только нужно это прочувствовать.

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

FDS>P.P.S. Летом, на досуге, может ещё раз прочитаю... может пойму что-нибудь


Надо пробовать. Как показала практика все программисты которые хотели освоить новый язык и принимали участие в том или ином проекте через некоторое время отлично его осваивали.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[3]: Функциональное программирование в Nemerle
От: andrey.bond  
Дата: 17.05.07 13:36
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>По сути это и есть выбор междц ООП и ФП. Во втором случае и используются фунциональные фичи вроде вариантов, паттерн-матчинга и функций высшиго порядка.


Вот оно как
Тогда возникает следующий вопрос — зачем тогда язык поддерживает и то и другое?? я просто все пытаюсь понять как получить выгоду от слияния этих двух подходов, а как выясняется надо выбрать чтото 1.... бага
Re[3]: Функциональное программирование в Nemerle
От: andrey.bond  
Дата: 17.05.07 13:47
Оценка:
Здравствуйте, VladD2, Вы писали:


VD>Наверно общим принципом является дизайнерский выбор того как решать задачу. Если выбирается подход с эмуляцией проблемы с помощью объектов и изменения их состояний, то надо использовать ОО-фичи языка которые почти 1 в 1 как в C#. Другой подход который можно предпочесть — это описание модели как набора вариантов, а их обработку как набор преобразований (конвертаций) этих данных в другие представления.


И если можно вот с этого момента поподробней, а то в статьях действительно много воты — суть ускользает .
А хочется именно не примера в виде куска кода а какой-то теоретической базы чтоли (незнаю как назвать ).

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

WH>...Тогда это выражение будет преобразовано в Literal(5)


Да, так лучше.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[4]: Функциональное программирование в Nemerle
От: VladD2 Российская Империя www.nemerle.org
Дата: 17.05.07 15:52
Оценка:
Здравствуйте, andrey.bond, Вы писали:

AB>Тогда возникает следующий вопрос — зачем тогда язык поддерживает и то и другое??


Потому что есть задачи которые неудобно или не эффективно решать фунционально.
Например, работа с GUI-формами императивна по сути. Мы меняем состояние окна. По этому форму лучше сделать классом, а вот рассчеты которые производятся внутри вполне себе могут быть функциональными.

AB> я просто все пытаюсь понять как получить выгоду от слияния этих двух подходов, а как выясняется надо выбрать чтото 1.... бага


Как показывает практика большие глобальные сущности плохо описываются функционально. Уже упоминавшаяся форма или сессия в Веб-приложении — это по сути и есть состояние. Работать с ними лучше через объектный интерфейс.

Вообщем в программе можно выделить участки которые хорошо подходят под модель преобразования и реализоват их функционально. А уже эти участки удобно поместить в объектно-ориентированную оболочку.

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

В принципе лучше брать конкретную задачу и думать как ее лучше реализовать.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
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;
    }
}
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>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[5]: книга?
От: Аноним  
Дата: 18.05.07 12:13
Оценка:
Здравствуйте, VladD2, Вы писали:

[...]

VladD2, а вы не думали издать книгу про Nemerle и вообще по функциональным языкам?
Чисто Ваших статей только по Nemerle (из тех что в открытом доступе) набралось уже на 125 страниц формата А4, т.е. распечатать конечно можно но это будет ворох бумаги, что крайне неудобно. Хочется именно книгу.
Если присоединить туда обзорные статьи по ФП в целом, по Haskell, Erlang, Scala (это будет полезно, для обзора и для сравнения возможностей языков), то получится еще столько же. Ну и еще "связующий" текст, что-то из стандарта языка, побольше примеров и т.д.
Re[9]: Функциональное программирование в Nemerle
От: Аноним  
Дата: 18.05.07 21:20
Оценка:
Здравствуйте, VladD2, Вы писали:

      | Call(_, _)   => throw InvalidOperationException(this.ToString());

Кстати, а зачем этот код? Разве Nemerle не отслеживает все случаи когда соспоставление с образцом не сработает?
А тут, как я вижу проверка перенесена в Runtime.
Re[13]: Функциональное программирование в Nemerle
От: VladD2 Российская Империя www.nemerle.org
Дата: 18.05.07 22:49
Оценка:
Здравствуйте, IT, Вы писали:

IT>Пожалуйста, не надо считать других за идиотов и демонстрировать упёртость.


Собственно именно это и происхордит на протяжении всего разговора с Аноним 150. Демонстрация упертости. Бессмысленной и беспощадной. Посему нужно завязывать этот разговор. Все кто захочет сделает выводы сам. Заниматься воспитанием объективности не входит в наши задачи. Да и вряд ли это ее можно воспитать у взрослого человека.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[10]: Функциональное программирование в Nemerle
От: VladD2 Российская Империя www.nemerle.org
Дата: 18.05.07 22:49
Оценка:
Здравствуйте, <Аноним>, Вы писали:

А>
А>      | Call(_, _)   => throw InvalidOperationException(this.ToString());
А>

А>Кстати, а зачем этот код? Разве Nemerle не отслеживает все случаи когда соспоставление с образцом не сработает?
А>А тут, как я вижу проверка перенесена в Runtime.

Компилятор отслеживает, что match отлавливает все вариации. Если какой-то вариант не отлавливается выдается предупрждение. Если его прогнорировать и в рантайме появится тако паттерн, то вылетет исключение говорящее, что сопоставление с образцом не удалось. Делать так естественно не стоит. По этому если паттерны не покрывают все вариации, то нужно добвлять паттерн отлавливаеющий все что осталось. В данном случае он отлавливает все ошибки связнаные с неверным числом парметров у фукнции.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[13]: Функциональное программирование в Nemerle
От: Аноним  
Дата: 19.05.07 20:08
Оценка:
Здравствуйте, IT, Вы писали:

Да, я правильно понял, что мне тоже можно в C# размещать декларации для нескольких разнотипных переменных на одной строке или это прерогатива кода на Nemerle?
Re[15]: Функциональное программирование в Nemerle
От: konsoletyper Россия https://github.com/konsoletyper
Дата: 20.05.07 06:13
Оценка:
Здравствуйте, <Аноним>, Вы писали:

VD>>Собственно именно это и происхордит на протяжении всего разговора с Аноним 150. Демонстрация упертости. Бессмысленной и беспощадной.

А>Я правильно понимаю, что вы решили не замечать реализацию паттерн матчинга в C# и быстренько свернуть разговор.
А>Я, конечно, конкретный код реализации матчинга не привел, хотя он у меня и есть, а привел пример использования.

Обратили-обратили. Даже минус поставили. Всё потому, что ты даже не удосужился понять, что такое паттерн-матчинг. Только я тут этого объяснять не буду, а отошлю ещё раз внимательно перечитать статьи по Nemerle (или по другим ML-образным ФЯ) или к примерам кода. Кстати, на неконструктивные замечания я отвечать не намерен.
... << RSDN@Home 1.2.0 alpha rev. 672>>
Re[14]: Функциональное программирование в Nemerle
От: konsoletyper Россия https://github.com/konsoletyper
Дата: 20.05.07 06:13
Оценка:
Здравствуйте, <Аноним>, Вы писали:

А>Отлично, с учетом того, что это был выстрел вслепую, так как мне не было показано, во что должен превратиться мой код после увеличения количества строк до 300, для, возможного, увеличения читабельности. Причем я по-честному не стал приводить свою версию кода на Nemerle в своем первом ответе на обещание увеличить мой код до 300 строк. Однако это не привело к показу кода, поэтому я счел нужным первым перевести разговор в конкретную плоскость, с конкретным кодом и конкретными цифрами. В ответ я получил обиду, что не так переформатировал код, но так и не получил в ответ образец как надо было переформатировать мой код чтобы он занимал 300 строк, чтобы я на основании этого образца мог бы переформатировать код на Nemerle.


Отличный пример софистики и демагогии. Нуль конструкрива. Ты вообще понимаешь слово "читабельный", или просто издеваешься над собеседниками?
... << RSDN@Home 1.2.0 alpha rev. 672>>
Re[14]: Функциональное программирование в Nemerle
От: konsoletyper Россия https://github.com/konsoletyper
Дата: 20.05.07 06:13
Оценка:
Здравствуйте, <Аноним>, Вы писали:

А>Да, я правильно понял, что мне тоже можно в C# размещать декларации для нескольких разнотипных переменных на одной строке или это прерогатива кода на Nemerle?


В Nemerle, обрати внимание, такая практика существует только по отношению к вариантам. Потому что варианты унаследованы Nemerle от ML, где такое практикуется почти 30 лет. И это вполне обоснованная практика. Я не сильно разбираюсь в тонкостях computer science. Так что судить могу по абстрактному понятию "читабельность". Так вот, в вариантах размещение нескольких "деклараций" на одной строке читабельность повышает. В классах же — понижает. Думаю, всё это связано с тем, что классы поддерживают ООП-парадигму, так что должны походить на чёрный ящик, потому для них требуется пространное описание структуры. Варианты же — вещь ортогональная ООП, они, наоборот, максимально открыты, чтобы по ним было проще сопостовлять по образцу.
... << RSDN@Home 1.2.0 alpha rev. 672>>
Re[3]: Функциональное программирование в Nemerle
От: FDSC Россия consp11.github.io блог
Дата: 20.05.07 12:09
Оценка:
Здравствуйте, konsoletyper, Вы писали:

K>Какое SDK? Сейчас Блудов Павел раз в месяц выкладывает инсталлятор, и ничего (кроме инсталлятора, 2Мб) качать не нужно. Правда, есть неудобство — Интеграция пока жутко глючит. Но это всё же гораздо удобнее, чем в Блокноте.


Блин, ребят, что же вы не написали, а! Надо же было орать на весь форум!!! А я мучаюсь без интеграции....
Re[17]: Функциональное программирование в Nemerle
От: Аноним  
Дата: 20.05.07 14:34
Оценка:
Здравствуйте, Аноним, Вы писали:

А>привести неконструктив в ответ на конструктив

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

А>Да, я правильно понял, что мне тоже можно в C# размещать декларации для нескольких разнотипных переменных на одной строке или это прерогатива кода на Nemerle?


А где ты увидил несколько переменных на одной строке? Речь идет о связывамых перменных в паттернах? Или о полях?

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

Если о полях, то пожалуйсат, размещай. Условие только одно чтобы это хорошо читалось. Так что если определения уезжают за 80 символов, то это не дело.

Кстати, учти, что эти поля еще к тому же доступны только для чтения.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[15]: Функциональное программирование в Nemerle
От: VladD2 Российская Империя www.nemerle.org
Дата: 20.05.07 22:53
Оценка:
Здравствуйте, konsoletyper, Вы писали:

K>В Nemerle, обрати внимание, такая практика существует только по отношению к вариантам. Потому что варианты унаследованы Nemerle от ML, где такое практикуется почти 30 лет. И это вполне обоснованная практика. Я не сильно разбираюсь в тонкостях computer science. Так что судить могу по абстрактному понятию "читабельность". Так вот, в вариантах размещение нескольких "деклараций" на одной строке читабельность повышает. В классах же — понижает. Думаю, всё это связано с тем, что классы поддерживают ООП-парадигму, так что должны походить на чёрный ящик, потому для них требуется пространное описание структуры. Варианты же — вещь ортогональная ООП, они, наоборот, максимально открыты, чтобы по ним было проще сопостовлять по образцу.


Варианты соответствующим образом проектировались. Их поля по умолчанию публичны и доступны только для чтения. Это позволяет обойтись без свойств-эксесоров и сделать запись краткой. Более того, компилятор языка автоматом создает конструктор включающий все эти поля. Это все сделано специально, чтобы сделать запись краткой и одновременно ясной. Это как бы специализированные версии классов которые имеют специализированные умолчания и потому так хоршо записываются в одну строку.

Естественно, что если определения не лезут в одру строку, то нужно их переносить и как следует форматировать.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[16]: Функциональное программирование в Nemerle
От: VladD2 Российская Империя www.nemerle.org
Дата: 20.05.07 22:53
Оценка:
Здравствуйте, <Аноним>, Вы писали:

А>Обращаю внимание, что при паттерн матчинге декларация тоже на одной строке в Nemerle.

А>Ведь код типа
А>
А>match 
А>{
А>   | Call(expr1, expr2)
А>


А>это и есть декларация двух, возможно разнотипных, переменных expr1 и expr2 на одной строке


Ага. В этом и есть суть паттернов. Понимаш ли тут проблема с мозгами, а не с форматированием. Паттерн не надо рассматривать как что-то содержащее переменные. Паттерн — это образец со знаками/переменными заменителями. Их нельзя именить, им нельзя задать тип. Они определяются паттерном иявляются его чатьсю. Это как регулярные выражения с группами:
Начало образца ([A-za-z][A-za-z0-9]+) конец образца

Мы не объявляем переменную типа строка. Мы создаем образец часть которого является переменной величиной (в данном случае "([A-za-z][A-za-z0-9]+)"). Глупо заставлять людей записывать две группы в одном регэкспе на разных строках, да еще и аргументировать это тем, что в C# это плохо. В C# нет ни регекспов, ни паттерн-матчинга и добавить их студа средствами языка нельзя. Так что применять правила порматирования переменных C# к сущностям из другого языка ошибочно. Это называется применение выводов по анлогии. Грубейшая логическая ошибка.

А>Понимаю, Nemerle — хороший язый, ML — хороший язык (30 лет!) им можно декларации на одной строке размещать.

А>А вот C# плохой язык ему нельзя.

Плохой не плохой, а паттерн-матчинга в нем нерт и вывода типа пока тоже. Это однозначные минусы. Вывод типов (плохоньких, но хоть что-то) появится в 3.0, а вот паттерн-матчинг мы будем ждать очень длого. Рано или поздно он все равно появится во всех мэйнстрим-языках, но хотелось бы чтобы раньше. В прочем, Nemerle ка язык уже превосходит тот же C# практически по всем показателям. Так что можно ничего не ждать. Яык уже есть. Интеграция к Студии тоже.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[10]: Функциональное программирование в Nemerle
От: VladD2 Российская Империя www.nemerle.org
Дата: 20.05.07 22:53
Оценка:
Здравствуйте, <Аноним>, Вы писали:

А>Так же легко повернуть, что и код на Nemerle не делает, того что от него требовалось, и другого полезного ничего не делает.


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

А>Что несуразного в Min с одним параметром?


То что это функция вычисляющая минимальное значение. Глупо вычислять минимальное значение когда вариантов ровно один.

А> Не больше чем в умножении на 1.


Умножение на 1 может получиться в следствии применения другой оптимизации. Если ты заметил, то их там можно добавлять хоть тысячу.

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


Речь шало о исходном варинте.

А>А так у меня даже был Min с любым количеством параметров, не помню только выкладывал или нет.


Не выкладывал. Но этого никто не просил.

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

А>Серьезно не понимаю, зачем добиваться той же функциональности с точностью до миллиметра.

Сравнивать можно только программы решающие одни и те же задачи. А то я тебе напишу программу "x()" и отмажусь тем, что "не понимаю, зачем добиваться той же функциональности".

А> Разговор с моей стороны идет, что по объему кода никакого пятикратного преимущества у Nemerle нет,


Чтобы такое заявить нужно не иметь ни стыда, ни совести. В прочем как я вижу это не проблема.

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


Поправлю. Минимум двукратное. То есть 2+ получается после ужатия C#-ного кода до безоразия (объявления и выражения на одной строке, 150-символьные строки). Любому кто в теме очевидно, что увеличение объема кода связано с тем, что C#-ный вариант содержит море не важной для программы информации. В каждом классе приходится писать море баластного кода. К тому же какой-нибудь override можно пропустить и компилятор уже не подскажет, что ты забыл реализовать то или ное дейтсвие. А классов то уеже не мало и контролировать их в разрезе операций очень сложно.

При нормальном же форматировании разница составляет 3х. А при применении, напрашивющегося здесь, паттерна проектирования Посетитель код становится больше в 5 раз (при стандартном для C# форматировании). Собственно это и было продемонстрировано в статье. Граматные программисты занкомые с упомянутым паттерном и с разработкой парсеров, думаю, согласятся со мной, что его использование тут очень к месту. И что увелчение объема кода все же не так критично по сравнению с тем, что операции сложены вместе и их не надо искть по туче классов.

А> А уж если сравнивать по количеству нажатий на кнопки в среде оснащенной Intellisense'ом.


И что будет? Будет такое же 2-5 кратное упрощение работы. Более того, ad-hoc-полиморфизм в паттерн матчинге позволяет еще больше согратить запись.

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

А>Это на Nemerle не делал то что нужно

Ты вменяемый?

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

А>Пускай, я пока не смеюсь.

А тебе над чем смеяться то? Они смеются над тем как ты краткий и очевидны код (который даже ты вроде как понял) ты патшся сравнивать со своей кашей.

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

А>А откуда такая уверенность.

Из изучения твоих исходников. От бредового метода не осталось и следа. И задача во второй раз была почти решена.

А> Я переписал, код как только получил доступ к форуму и смог посмотреть на исходные условия.


В условиях задачи не сказно как надо делать. Там сказано, что нужно делать.

А>Да и что в твоем примере такого существенного?


Он верно работал с самого начала. И писал я его 10 минут, так как он фактически является изложением мыслей как они есть.

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

А>Инкапсуляция всегда небесполезна.

В конкретном случае бесполезно все, что не приносит пользы для этого случая. Все данные AST-классов должны быть доступны публично. Их тлько желательно сделать неизменяемыми. Это и делается автоматически в вариантах Немерле и вызывает нагромождения кода на C#. В общем, это банально более удобное решения конкретной задачи.

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

А>Пишу, в основном, после работы. Кстати, стараюсь никогда не оправдыватся, но, ха-ха, вчера у меня прорвало счетчик воды в квартире и половину ее залило, к счастью без особых последствий, но пять 15 литровых ведер воды, я с пола собрал.

Кстати, не всегда получается.
И совершеено не кстати, я на доработку кода потратил 5 минт от силы, на само письмо ушло времени гараздо больше.

А>Я подумал, подумал и написал сопоставление с образцом на C#.




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

А>С этим не согласен.

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

А> К тому же добавить свойство — всего одна дополнительная строка, а работа с литералами у меня и так типизированная.

Согласен, но это дело не меняет и ничего не оправдывает. Нарушение инкапсуляции (грубое) на лицо.

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

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

А кто с тобой спорил по поводу RemoveOneParameterMin? Консолетайпер выразил тебе свое мнение, что это кривое решение, но никто тебя не заставлял его убирать.

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

А>Отнюдь, я просто показал широту своих взглядов и легкость к изменениям.


Где ты изменил взгляд? Умора. Сам написать ничего приличного не смог, а потом оправдался тупое сдирание по контексту тем широтой вглядов и легкостью их изменения.

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

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

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

VD>>Серьезно? Ну, я почти на верняка пишу на C# дольше тебя (начал еще в 2000-ном когда первые превью появились), но вот почему-то никак не могу привыкнуть к тому, что вместо:

А>Я тоже начал в 2000 с бета версий, правда, тогда в основном упирал на VB.NET, ну да в контексте .NET это не так важно.
А>И оценка на brainbench у нас примерно одинаковая по C#.

Вообще-то исходное сообщение говорило о том, что опыт кодирования на C# у нас как минимум не меньше, и что мы не находим решение на Шарпе столь же ясным и удобным в поддржке.

Вот это о чем было:
VD>>Расскажи, как ты к такому привыкаешь?

А кто-то тупо обошел этот вопрос и начал развивать пенесометрийную тему. Демагогия однако.

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


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

А>Да ничего там не пришлось подглядывать.

Ну, это все видил.

А>У меня к тому же есть отличие, не надо проводить повторную конвертацию, если в результате первой конвертации в выражении получились, образцы подходящие для условий конвертации. Впрочем, можешь заявить, что это я у WolfHound подглядел.


В прочем, это заявление будет правдой.

А>И еще в большинстве случаев я стараюсь использовать полные имена для переменных, а не одно-двухбуквенные имена.


А, да, да. Это очень правильно, использовать не осмысленные имена, "полные". Кстати, не сильно смущают функции Min и Max? Может быть сделать обертки MinimalValue и MaximumValue?
А вот этот код
Автор:
Дата: 17.05.07
не твой ли? Смотри как от полных имен не осталось и следа! Даже Literal был в совершенно не очевидный Lit переименован. Это тоже, так сказать, проявление широты взглядов?

VD>>

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

VD>>Вряд ли ты станешь спорить, что теперь наш код иделогически близок. Но вот что лучше читается? На мой взгляд действия собранные вместе и без лишних заголовков функций читается намного лучше. Его и поддерживать проще.
А>C# неплохо читается,

А>можно по отдельности классы разбирать.


Ой, умаор! Да ничего другого и не приходится. Еще приходится скролировтаь код чтобы разглядеть, что там у тебя за горизонтом тварится. И при это всевремы ломать глаза, так как выцепить значемый код из 150-символьных строк ой как не просто. Уж лучше бы фукнция 3 строки занимала.

VD>>Развитие кода

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

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

Ведь в любом случае одна строка:
  | Minus   { expr1 : Expr;   expr2 : Expr; }

соотвествует как минимум:
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))); }
}

7 строкам на шарпе. А еще нужно учеть пустые строки которыми классы отбивают. да и код отбить по человечески:
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 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)));
  }
}


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

А>Так и мне подскажет. Набираешь override (даже несколько букв) вот и готово тело метода.
Согласен. Подскажет пока ты за override-ами внимательно следишь. Тут паритет. Жаль в остальных местах его нет.

А>А вот код сопоставления по образцу:

А>
А>  static Expr RemoveMulToOne(Expr expr)
А>  {
А>    Mul mul = null; Expr first = null; Lit lit = null;
А>    if (new Pattern<Mul, Expr, Lit>().Match<Expr>(expr, ref mul, ref first, ref lit))
А>    {
А>      if (lit.Eval() == 1) return first;
А>    }
А>    return expr;
А>  }

А>  static Expr RemoveMaxOfLiterals(Expr expr)
А>  {
А>    Max max = null; Lit lit1 = null; Lit lit2 = null;
А>    if (new Pattern<Max, Lit, Lit>().Match<Expr>(expr, ref max, ref lit1, ref lit2))
А>    {
А>      return new Lit(Math.Max(lit1.Eval(), lit2.Eval()));
А>    }
А>    return expr;
А>  }
А>


Это извини меня чушь какая-то, а не сопоставление с образцом. Ты бы хоть реализацию этого чуда привел бы, а то даже разговаривать не о чем. Ну, и надо заметить, что "это чудо" один фиг не сопоставимо с образцами паттерн-матчинга, ни по объему, ни по удобочитаемости. Это очередное награмождение кода попирающее принципы форматирования в C#.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[17]: Функциональное программирование в Nemerle
От: VladD2 Российская Империя www.nemerle.org
Дата: 21.05.07 01:31
Оценка:
Здравствуйте, <Аноним>, Вы писали:

А>А пример использования?


- Иссаак! Зачем ты покупашь яйца по рублю за десяток, варишь их и продаешь по 10 копеек за штуку?
— Как же? А наваррръ?!


Пример чего? У тебя что есть универсально решение которое обладает фунционльностью пттерн-тачинга? Ты меня извини, но этот алгоритм тебе просто не написать .

Пример использования один фиг награмождение кода по сравнению с исходным обрацом.

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

А> По нему вполне можно восстановить примерный код реализации.


А зачем мне знаиматься реверс-инжинирингом какого-то бредового куса кода? Темболее, что он у тебя есть.

А>Мне тоже небезынтересно проверить знание C# для спорящих со мной.


Это не интересно мне. Ведь не я пришел сюда спорить кажется? И не я рассказываю, что на коленке паттен-матчинг сварганил?

А>Также, хочу заметить, что вместе с сопоставлением по образцу код уложился в те самые 250 строк кода на C#, о котором количестве шла речь в исходной статье.


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

Понимаш ли даже 30% разницы в коде — это весомый результат. Это значит, что программа может быть написана на 30% быстрее, или что она может стать на 30% фуниональнее. А 2 раза — это уже огромный результат. Так что если бы даже тебе удалось хоть кого-то кроеме себя убедить в том, что твой код содержащий строки по 150 символов и нагромождение конструкций на одной строке — это нормально оформленный код, все равно он минимум в 2 раза хуже. И с каждым образцом он становится худе на 5-10 строк. А так как реальная цифра выигрыша составляет 3-5 раз, то он уже получается каким-то угражающим. Писать подобные задачи на C# в то время как есть возможность использовать более мощьный язык просто является приступлением.

Это все равно как подойти в качалку и заявить, что скажем жим 100 килограм с груди мало чем отличается от жима 50. Тебе сразу заметят, что 50 это результат для новичка. А вот до 100 уже не все добираются. Ну, а 150 это уже гигантская разница...
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[4]: Функциональное программирование в Nemerle
От: VladD2 Российская Империя www.nemerle.org
Дата: 21.05.07 01:31
Оценка:
Здравствуйте, FDSC, Вы писали:

FDS>Блин, ребят, что же вы не написали, а! Надо же было орать на весь форум!!! А я мучаюсь без интеграции....


Видишь, поарали и теперь многие дуются. Теперь вот тихо потребляем плоды прогресса.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[17]: Функциональное программирование в Nemerle
От: Аноним  
Дата: 21.05.07 16:24
Оценка:
Здравствуйте, VladD2, Вы писали:


VD>Ага. В этом и есть суть паттернов. Понимаш ли тут проблема с мозгами, а не с форматированием. Паттерн не надо рассматривать как что-то содержащее переменные. Паттерн — это образец со знаками/переменными заменителями. Их нельзя именить, им нельзя задать тип. Они определяются паттерном иявляются его чатьсю. Это как регулярные выражения с группами:

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

VD>
VD>Начало образца ([A-za-z][A-za-z0-9]+) конец образца
VD>

VD>Мы не объявляем переменную типа строка. Мы создаем образец часть которого является переменной величиной (в данном случае "([A-za-z][A-za-z0-9]+)"). Глупо заставлять людей записывать две группы в одном регэкспе на разных строках, да еще и аргументировать это тем, что в C# это плохо.
Образец — да, не совсем строка (хотя и задается в строке), а результат удачного сопоставления — строка например А0.

VD>В C# нет ни регекспов, ни паттерн-матчинга и добавить их студа средствами языка нельзя.

Кажется, regexp есть. Кажется они везде есть. Для всех случаев может и не сделать (хотя сильно над этим я еще не думал особенно в контексте C# 3.0), а для определенной иерархии классов вполне себе.
Re[16]: Функциональное программирование в Nemerle
От: FDSC Россия consp11.github.io блог
Дата: 21.05.07 16:42
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Конечно, любое выступление на форуме, можно посчитать демагогическим ибо в потенциале, его могут прочитать очень много людей.

А>Но нужно ли считать его демагогическим если идет обращение к одному человеку?

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

Смысл слово "демагогия" состоит не в том, что сообщения обращены к большому количеству людей, а в том, что нагло врут или коверкают логику. В этом смысле демагогия крайне сильно пересекается с термином "Софистика"


P.S. Кстати, вы случайно не преднамеренно путаете этимологию слова (его происхождение) с толкованием (значением) слова?
(это я по поводу этого
Автор:
Дата: 21.05.07
вашего сообщения, я так понимаю, это тоже вы)
Re[18]: Функциональное программирование в Nemerle
От: Аноним  
Дата: 21.05.07 17:31
Оценка:
Здравствуйте, VladD2, Вы писали:


VD>Пример чего? У тебя что есть универсально решение которое обладает фунционльностью пттерн-тачинга? Ты меня извини, но этот алгоритм тебе просто не написать

Я добрее к людям. Если, у программиста больше 4 по C# на brainbench, то он может написать этот алгоритм. В потенциале.

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

Зачем? Она помогает мне ощущать интеллектуальное превосходство. In my dreams, чтобы не злить волков.

VD>Понимаш ли даже 30% разницы в коде — это весомый результат.

По мне так даже отрицательный, если на одной чаше microsoft, а на другой пять человек.
Как видишь, заставить меня программировать на Nemerle не так сложно.
Достаточно чтобы ms купила его и вложила бы большие средства в его развитие.

VD>Это значит, что программа может быть написана на 30% быстрее, или что она может стать на 30% фуниональнее.

Это значит, что возможность получить справку по сложным моментам, в тысячи раз меньше.

VD>Это все равно как подойти в качалку и заявить, что скажем жим 100 килограм с груди мало чем отличается от жима 50. Тебе сразу заметят, что 50 это результат для новичка. А вот до 100 уже не все добираются. Ну, а 150 это уже гигантская разница...

В качалку чаще ходят, не для того чтобы один раз по 100, а для того чтобы два раза по 50. Повторяют, короче, упражения.
Где в качалке, intellisence, спрашивать опасаюсь.
Re[19]: Функциональное программирование в Nemerle
От: VladD2 Российская Империя www.nemerle.org
Дата: 21.05.07 20:50
Оценка:
Здравствуйте, <Аноним>, Вы писали:

А>Я добрее к людям. Если, у программиста больше 4 по C# на brainbench, то он может написать этот алгоритм. В потенциале.


Это алогоритм — это дисер на Ph.D. Его с нуля не написать ни мне, ни тебе не многим другим. Ты его можешь только содрать. Но как раз для этого тебе прийдется понять всю силу того самого паттерн-матчинга. А это уже парадокс.

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

А>Зачем? Она помогает мне ощущать интеллектуальное превосходство. In my dreams, чтобы не злить волков.

А, ну, успехов в этом нелегком труде.

VD>>Понимаш ли даже 30% разницы в коде — это весомый результат.

А>По мне так даже отрицательный, если на одной чаше microsoft, а на другой пять человек.
А>Как видишь, заставить меня программировать на Nemerle не так сложно.
А>Достаточно чтобы ms купила его и вложила бы большие средства в его развитие.

Вот! Что и требовалось доказать. А весь этот лживый демогогический бред можно было просто не раводить.

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

VD>>Это значит, что программа может быть написана на 30% быстрее, или что она может стать на 30% фуниональнее.

А>Это значит, что возможность получить справку по сложным моментам, в тысячи раз меньше.

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

Вообще, забавно, что тактика на смену темы пошла уже совсем открыто. Если ты обделался в одном вопросе, то надо срочно переключаться на другие. Вот только в них ты тоже можешь так же обделаться.

А>В качалку чаще ходят, не для того чтобы один раз по 100, а для того чтобы два раза по 50. Повторяют, короче, упражения.

А>Где в качалке, intellisence, спрашивать опасаюсь.

Ага. Вот одни всю жизнь 2 раза по 50, а другие 10 по 110. А некторые 10 по 200. Причем, как и в программировании все определяют гены.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[18]: Функциональное программирование в Nemerle
От: VladD2 Российская Империя www.nemerle.org
Дата: 21.05.07 20:50
Оценка:
Здравствуйте, <Аноним>, Вы писали:

VD>>Вот это она и есть софистика или иными словами демогогия.

А>А почему определения разные в википедии для софиситики и демагогии?

Потому что это два разных термина. По смыслу они почти-что идентичны.

А>Гм, а мне казалось, софизм, софисты и софистика — разные слова, пусть и однокоренные.


Ага. Разные. Одно означает один из методов выработанный течением, второе приверженцов оного течения, а третье само течение.

А>Что интересно, слово софистика есть в википедии, однако две приведенные ссылки, ссылаются на другие слова.

А>

Софи́стика (греч. σοφιστική — умение хитро вести прения)


Продолжашь пытаться применять демогогию? В этот раз пошел цитаты вырванные из контекста подсовывать.

ОК. Разобьем и эту демогогию. Для этого буквально нужно процетировать пару абзацев далее:

Софистика (греч. ????????? — умение хитро вести прения)

1. Философское течение в Древней Греции, созданное софистами.
2. Рассуждение, основанное на преднамеренном нарушении законов логики, на употреблении ложных доводов.

Остальные, кто еще не знаком ни с течением, ни с его последствиями могут прочитать всю статью целиком.
http://ru.wikipedia.org/wiki/%D0%A1%D0%BE%D1%84%D0%B8%D1%81%D1%82%D0%B8%D0%BA%D0%B0

Хреново ты владешь одным предметом.

А>Стоит-то стоит, только оно такое обширное, что под троллингом может пониматься практически все. Кстати сравнение оппонента с животным это тоже троллинг.


Вот ты попал. И если не закочишь свои упражнения на этом сайте, то прийдется твои айпишники в бан-лист складывать.

А>

Демаго́г (др.-греч. δημαγωγός, «предводитель народа»)

А>Как ни крути, предводитель народа, без самого народа — это вряд ли демагог. Даже если понятие народа трактовать широко.

Мы перешли на древне греческий? Если нет, то тебе прийдется пользоваться значениями слов из Русского языка.

А>Осторожно напоминаю, что речь шла о том, что я убил читабельность в коде на Nemerle.


Осторожно напомню, что после того как ты встал на путь лжи и демагогии, говорить о какой-то дискусси с тобой смешно.

А>А где ссылка на википедию?


Вот она.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[18]: Функциональное программирование в Nemerle
От: VladD2 Российская Империя www.nemerle.org
Дата: 21.05.07 20:50
Оценка:
Здравствуйте, <Аноним>, Вы писали:

А>Кажется, regexp есть. Кажется они везде есть. Для всех случаев может и не сделать (хотя сильно над этим я еще не думал особенно в контексте C# 3.0), а для определенной иерархии классов вполне себе.


Когда кажется, крестись. Регекспов в Шарп нет. Есть библиотека выполняющая их в рантайме. Сами регулярные выражения являются отдельным языоком.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[14]: Функциональное программирование в Nemerle
От: konsoletyper Россия https://github.com/konsoletyper
Дата: 22.05.07 08:31
Оценка:
Здравствуйте, <Аноним>, Вы писали:

А>Насчет догм считаю также. Насчет кода AST нет.


Много рабочих компиляторов написал? Ссылки в студию, плиз. И попрошу не оправдываться. Если нечем подтвердить свою компетентность в данном вопросе, попрошу демагогии не разводить.

WH>>Ну про то что тебе еще надо написать

WH>>
WH>>return converter(new Plus(first.Convert(converter), second.Convert(converter)));
WH>>
ты как обыно забыл...

А>Разговор шел про пользу intellisence для Nemerle, а не для C#.
[skip]
А>вот примерно, что придется набрать с клавиатуры:
А>ret con(new Pl(fir.(con), sec.(con));
А>Что придется набрать с клавиатуры в случае Nemerle пусть напишут знатоки Nemerle.
А>А код такой примерно:
А>| Plus(first, second) => converter(Plus(first.Convert(converter), second.Convert(converter))

Где-то так:

| Pl(fi, se) => con(Pl(fir.Conv(conv), sec.Conv(conv))


Только тут сразу происходит сопоставление по шаблону. А у тебя только возвращается результат.

И вообще, надо не забывать, что код труднее читать, чем писать. Я на сниппетах тебе такого нагородить на brainfuck могу, что ты потом всю оставшуюся жизнь в нём разбираться будешь.

А>>>А у меня есть мнение, что не одна строка на Nemerle, а четыре,

WH>>А у меня есть мнение что при правильном форматирование не 7 строк на C#, а 22
WH>>
WH>>class Minus : Oper
WH>>{
WH>>    public Minus(Expr first, Expr second)
WH>>        : base(first, second)
WH>>    {}
    
WH>>    public override string ToString()
WH>>    {
WH>>        return first.ToString() + "-" + second.ToString();
WH>>    }
    
WH>>    public override double Eval()
WH>>    {
WH>>        return first.Eval() - second.Eval();
WH>>    }
    
WH>>    public override Expr Convert(Converter converter)
WH>>    {
WH>>        return converter(new Minus(first.Convert(converter), second.Convert(converter)));
WH>>    }
WH>>}
WH>>

А>А я тогда, что на Nemerle 11
А>
А>| Minus 
А>  { 
А>      expr1 : Expr;   
А>      expr2 : Expr; 
А>  }
А>| Minus(expr1, expr2) 
А>    with oper = "-" 
А>| Minus(expr1, expr2) 
А>    => expr1.Eval() - expr2.Eval()
А>| Minus(expr1, expr2) 
А>    => transform(Minus(expr1.Convert(transform), expr2.Convert(transform)))
А>

А>2 * 11 = 22
А>Это я еще не добавил для отбивки пустые строки как в C#, пожалел.

Во-первых, хватит сравнивать тёплое с мягким. Во-вторых, варианты изначально так спроектирваны, чтобы поля опций записывались на одной строке с объявлением опции. Это потому, что много писать не приходится. И потому, что описание опции варианта гораздо более ёмкое, чем описание класса. Это не то же самое, что описание публичных полей в классе. В классе обычно приходится описывать очень много разных вещей, помимо нескольких полей, так что в одну строчку ты класс не запишешь.

В третьих, with — это неотъемлемая часть образца, так что её не стоит выносить на отдельную строку. Наконец, если образцы достаточно короткие, то допустимо записывать их на одной строке.

И отбивки между образцами никто не ставит. Это всё равно, что ставить отбивки между if-ом и его телом или меджу различными case'ами в switch'е.

Вообще, читабельность — понятие субъективное. Так что стиль кодирования вырабатывается не на основе теоретических положений, а ради обеспечения удобства большинства. Вот большинству кажется более удобным читать код на Nemerle в том виде, в котором его привёл VladD2, а код на C# — в том виде, как его привёл Wolfhound.

Кстати, допустимо всё это записать и так:

|
Minus
{
expr1
:
Expr
;
и т.д.


и

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)));}}


Так что твоя арифметика никому ничего не доказывает.

WH>>2)Попробуй написать аналог этого

WH>>
WH>>| Call("max", [Mul(Literal(x), Literal(m)), Div(Literal(y), Literal(d))]) => Literal(Math.Max(x * m, y / d))
WH>>

А>Всегда пожалуйста
А>
А>Max max; Mul mul; Div div; Lit x, m, y, d;
А>if (expr.Match<Max, Mul, Lit, Lit, Div, Lit, Lit>(out max, out mul, out x, out m, out div, out y, out d))
А>    return new Lit(Math.Max(x * m, y / d);
А>


Всё-таки ты невменяемый. Чтобы доказать обратное, прошу код метода Match в студию. Что-то его функциональность сильно напоминает телепатию. Кстати, очередные крики, что этот метод можно реконструировать, буду считать неконструктивом. Потому что нужно отвечать на вопрос, а не оправдываться.

PS: модераторы, куда вы смотрите. Это же явная провокация. Не сомневаюсь, что это очередное воплощение Kolhoz/GNU Zaurus. Баньте его к чёртовой матери!
... << RSDN@Home 1.2.0 alpha rev. 672>>
Re[16]: Функциональное программирование в Nemerle
От: rameel https://github.com/rsdn/CodeJam
Дата: 22.05.07 09:43
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>Это точно не Колхоз. Колхоз гораздо умнее.

WH>И уж точно Колхоз не станет защищать C#. Про C# Колхоз скорее скажет что-то типа: "Недоязычек для быдлокодеров."

А как же широта взглядов и лекгость к изменениям Re[9]: Функциональное программирование в Nemerle
Автор:
Дата: 19.05.07

Отнюдь, я просто показал широту своих взглядов и легкость к изменениям.

... << RSDN@Home 1.2.0 alpha rev. 677>>
Re[15]: Функциональное программирование в Nemerle
От: Lloyd Россия  
Дата: 22.05.07 14:05
Оценка:
Здравствуйте, konsoletyper, Вы писали:

А>>Насчет догм считаю также. Насчет кода AST нет.


K>Много рабочих компиляторов написал? Ссылки в студию, плиз.


А ваши компиляторы можно посмотреть?
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[16]: Функциональное программирование в Nemerle
От: konsoletyper Россия https://github.com/konsoletyper
Дата: 22.05.07 15:02
Оценка:
Здравствуйте, Lloyd, Вы писали:

А>>>Насчет догм считаю также. Насчет кода AST нет.


K>>Много рабочих компиляторов написал? Ссылки в студию, плиз.


L>А ваши компиляторы можно посмотреть?


Вообще-то Аноним спорил с Wolfhound'ом, у которого был опыт написания компиляторов (это мягко сказано), так что словам Wolfhound'а верится охотнее. А вот Аноним кидается словами по поводу AST, никак их не обосновывая. Кстати, небольшой опыт написания парсеров есть и у меня. Здесь
Автор: konsoletyper
Дата: 31.03.07
находится описание проекта, в котором так или иначе парсится текст. Причём синтаксис языка будет посложнее "A+B*C".
... << RSDN@Home 1.2.0 alpha rev. 672>>
Re[20]: Функциональное программирование в Nemerle
От: Аноним  
Дата: 22.05.07 17:07
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Это алогоритм — это дисер на Ph.D.

Кандидатская или докторская?

VD>Его с нуля не написать ни мне, ни тебе не многим другим.

А кто в наше время пишет с нуля?

VD>Ты его можешь только содрать.

А что если и правда содрал и реализовал на C# для C#? Шучу, шучу.

VD>Вообще, забавно, что тактика на смену темы пошла уже совсем открыто.

Ни стыда, ни совести, у этих скептиков Nemerle.

VD>Если ты обделался в одном вопросе,

А если нет?

VD>Вот только в них ты тоже можешь так же обделаться.

Ну волков бояться... Я уже даже написал, что у меня не короче.


VD>Ага. Вот одни всю жизнь 2 раза по 50, а другие 10 по 110. А некторые 10 по 200. Причем, как и в программировании все определяют гены.

Ставки повышены, не в пять раз N > C#, а в 10 или даже а 20. Рисковано.
Re[19]: Функциональное программирование в Nemerle
От: Аноним  
Дата: 22.05.07 17:19
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Когда кажется, крестись. Регекспов в Шарп нет. Есть библиотека выполняющая их в рантайме. Сами регулярные выражения являются отдельным языоком.

Регэкспов нет, а есть библиотека, которая выполняет их в рантайме. Их, которых нет. Загадочно.
Похоже имеется ввиду, что регэкспы есть, просто они не преобразовываются в готовый код при компиляции класса.
Re[16]: Функциональное программирование в Nemerle
От: konsoletyper Россия https://github.com/konsoletyper
Дата: 22.05.07 17:51
Оценка:
Здравствуйте, <Аноним>, Вы писали:

А>Спорить с вами konsoletyper, иногда все равно, что отнимать конфету у ребенка, слишком легко.


Ну спасибо, польстил. Просто я не софист и не люблю прибегать к нечестным методам ведения спора. Кстати на этом форуме принято обращаться на "ты", пусть даже общаются 15-летний молокосос и 50-летний матёрый дядька. Никто этого делать не заставляет, но традиция есть традиция. А вот твои "вы" воспринимаются как ироничное снисхождение, попытка выставить себя интеллигентом.

А>Вот назадавали мне кучу вопросов, а в конце, потребовали от модераторов, чтобы они меня забанили.

А>Зачем вопросы задавали, спрашивается, если ответов не хотели услышать? Ладно, предположу, что все-таки хотели.

Да потому что тебя давно забанить пора. Но так просто от тебя не отделаться. А то вона как какой-нибудь 15-летний молокосос начитается твоих бредней и будет потом всю жизнь Nemerle ненавидеть. А вдруг из него лет через 10-15 вышел бы крутой спец по ФЯ? Нет, либо тебя надо банить с полным отсечением ветки, либо дискредитировать. Правда, последнее вряд ли получится, т.к. ты ведёшь спор нечестными методами.

K>>И попрошу не оправдываться. Если нечем подтвердить свою компетентность в данном вопросе, попрошу демагогии не разводить.

А>Судья спрашивает у подсудимого — вы признаете себя виновным? И попрошу не оправдываться.
А>Да и что такого сложного в написании компилятора, в общем смысле, раз уж вы не уточнили какого именно?
А>И по-моему, в любом программистском ВУЗе, одна из курсовых, обязательно написание компилятора.

Да какой компилятор они там пишут? Так, поделки. И то, компилятор — это в лучшем случае. А так — интерпретатор какого-нибудь недопаскаля. Да и пишут они по старинке на каком нибудь C++.

Это я распознаю как уход от ответа. Вместо ответа на вопрос начинаются уточнения "что конкретно имели в виду?". Так играть можно до бесконечности. Хотя суть вопроса была всем ясна — тут высшей математики. Так что я делаю единственный возможный вывод — ты полный профан в плане написания компиляторов. Так что в таком споре:

А>Считаю, что код надо хранить поближе к данным, которые он обрабатывает.
WH>Это догма. Догмы до добра не доводят.
WH>Иногда это так. Иногда иначе.
WH>В случае с АСТ однозначно иначе.
A>Насчет догм считаю также. Насчет кода AST нет.


можно смело доверять опыту Wolfhound'у, а не тебе. Так же можно доверять опыту, например, разработчиков Nemerle, которые до него спроектировали не один язык и написали компиляторы для них.

K>>Где-то так:


K>>
K>>| Pl(fi, se) => con(Pl(fir.Conv(conv), sec.Conv(conv))
K>>

А>Оп-па, по количеству ввода Nemerle даже превзошел C#.

См. ниже.

K>>Только тут сразу происходит сопоставление по шаблону. А у тебя только возвращается результат.

А>Странно почему вам не пришло в голову, как же так возвращается результат, а сопоставление с образцом не происходит. Как же тогда работает программа, если результат возвращается не понятно, при каких условиях? Или все таки и у меня в данном случае есть сопоставление с образцом, только образец простой?

У тебя отсутствует код сопоставления с образцом. В версии для Nemerle он присуствует. Будь добр, добавь к своему коду сопоставление с образцом и покажи, что ты набираешь.

K>>И вообще, надо не забывать, что код труднее читать, чем писать. Я на сниппетах тебе такого нагородить на brainfuck могу, что ты потом всю оставшуюся жизнь в нём разбираться будешь.

А>Код труднее читать, чем писать, могу написать на редком языке, трудно понимаемую программу.
А>Гм. Не понял. Трудно понимаемую можно и на многих распространенных языках написать.

Вот ты как раз и даешь пример трудно понимаемого кода на C#.

K>>Во-вторых, варианты изначально так спроектирваны, чтобы поля опций записывались на одной строке с объявлением опции.

А>Понимаю, хорошие варианты хорошо спроектированы, им можно на одной строке. Плохие классы не так спроектированы — им нельзя.
А>class Mul { public Expr expr1, expr2; }

Классы не плохие, варианты — не хорошие. Они просто спроектированы для решения определённых задач.

K>>И отбивки между образцами никто не ставит. Это всё равно, что ставить отбивки между if-ом и его телом или меджу различными case'ами в switch'е.

А>Почему же ставят и часто, при определенном стиле форматирования.
А>
А>if (условие)
А>{
А>    тело
А>}
А>


Нет уж, согласно твоему подходу должно быть так:

if (cond1)
{

    body
    
}



K>>Кстати, допустимо всё это записать и так:

K>>Так что твоя арифметика никому ничего не доказывает.
А>Ситуация обратная. Сначала мне приводят форматирование на C# (например с множеством пустых строк), а я просто применяю примерно такой же стиль к Nemerle (что уже оказывается особо тяжким преступлением). Стили же приведенных вами фрагментов практически диаметрально противоположны.

Вот именно, что ты применяешь такой стиль формально. Фактически, ты нарушаешь своим подходом читадельность.

K>>Всё-таки ты невменяемый.

А>Сумашедший гений? Что вы на гениальности не настаиваю, хотя видеть подобный крен в эпитетах приятно.

Про гениальность никто не говорил. Это твои собственные домыслы. На лицо неограниченное самомнение и мания величия.

А>Впрочем, припоминаю, вы кажется уже хвалили мое умение искусно вести спор.


Не искусно, а нечестно.

K>>Что-то его функциональность сильно напоминает телепатию.

А>Не решились сказать, что напоминает сопоставление с образцом, решили сказать, что напоминает телепатию?

Блин, опять уход от ответа. Вот это и есть пример неконструктива. У тебя уже неоднократно просили привети код метода Match, а ты этого не сделал, как всегда, ловко уйдя от ответа. А это значит только одно — никакого паттерн-матчинга ты не изобрёл. В том числе, твоё утверждение про то, что ты понял паттерн-матчинг лучше нас — откровенная ложь.

Твоя функция напоминает телепатию, т.к. слижком уж она угадывает твои желания, которые ты непосредственно в коде никак не описываешь.

И про паттерн-матчинг я тебе объяснять не собираюсь. Что это такое, и так прекрасно описано в статье.

K>>Кстати, очередные крики, что этот метод можно реконструировать, буду считать неконструктивом. Потому что нужно отвечать на вопрос, а не оправдываться.

А>Не все могут реконструировать, это я признавал.

Да, все мы идиоты, а один ты Великий! Куда уж нам, ничтожным, до вас, до изобретателей паттерн-матчинга для C#. До вас даже Роберт Милнер не дотягивает — ему вон для паттерн матчинга специальный язык пришлось придымывать — ML называется.
... << RSDN@Home 1.2.0 alpha rev. 672>>
Re[19]: Функциональное программирование в Nemerle
От: Аноним  
Дата: 22.05.07 17:56
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Здравствуйте, <Аноним>, Вы писали:


VD>Потому что это два разных термина. По смыслу они почти-что идентичны.

По смыслу они почти противоположны.

Демагогия, это обращение к народу, причем с аргументами, которые понятны и нравятся народу (впрочем, попробовал бы кто обратится с аргументами, которые бы народу не понравились). В каком-то смысле упрощение спора. Для народа, напоминаю, в широком смысле.

Например: Голосуйте за меня, каждый получит по квартире.

А софистика, это в каком-то смысле усложнение спора, введение новых более сложных понятий, возможно плохо связанных с предметом спора. Тонкая (то есть не всякий сразу еще и поймет) подмена предмета спора.

VD>Ага. Разные. Одно означает один из методов выработанный течением, второе приверженцов оного течения, а третье само течение.

Да, причем мне сказали, что я занимаюсь софистикой и ссылка именно на это слово отсутствовала в приведенных вами ссылках.

VD>Продолжашь пытаться применять демогогию? В этот раз пошел цитаты вырванные из контекста подсовывать.

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

Софист, это мудрец. Софистика разговор мудреца. Неустранимых противоречий с последующими определениями не вижу.

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

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

Если бы мы перешли на древнегреческий, то все слова были бы древнегреческими.
Тем не менее происхождение слов помогает понять и их значение.
Re[16]: Функциональное программирование в Nemerle
От: VladD2 Российская Империя www.nemerle.org
Дата: 22.05.07 22:53
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>Это точно не Колхоз. Колхоз гораздо умнее.

WH>И уж точно Колхоз не станет защищать C#. Про C# Колхоз скорее скажет что-то типа: "Недоязычек для быдлокодеров."

Да, надо признать, при все троллевости и экстримизме Колхоза он хотя бы понимает, что защищает. Он точно не балб.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[17]: Функциональное программирование в Nemerle
От: VladD2 Российская Империя www.nemerle.org
Дата: 22.05.07 22:53
Оценка:
Здравствуйте, rameel, Вы писали:

R>А как же широта взглядов и лекгость к изменениям Re[9]: Функциональное программирование в Nemerle
Автор:
Дата: 19.05.07

R>

Отнюдь, я просто показал широту своих взглядов и легкость к изменениям.


Ну, если только Колхоз решил намерянно дуру включить и по быдлее по защищать C#. Типа игра от обратного. У нас тут на форуме были такие "руссукие" быдляцки мешающие с дерьмом украинцев, но с украинскими IP-ишниками.

В общем, то у меня тоже такое подозрение возникло. Товарищь как-будтно специльно подставляется.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[16]: Функциональное программирование в Nemerle
От: VladD2 Российская Империя www.nemerle.org
Дата: 22.05.07 22:53
Оценка:
Здравствуйте, Lloyd, Вы писали:

L>А ваши компиляторы можно посмотреть?


Compiler-compiler
Автор: konsoletyper
Дата: 31.03.07

Где искать мой ты и сам догадашся. Плюс можешь еще мне записать работу над тем же Немерловым компилятором.

Что дальше?
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[17]: Функциональное программирование в Nemerle
От: konsoletyper Россия https://github.com/konsoletyper
Дата: 23.05.07 07:58
Оценка:
Здравствуйте, rameel, Вы писали:

R>А как же широта взглядов и лекгость к изменениям Re[9]: Функциональное программирование в Nemerle
Автор:
Дата: 19.05.07

R>

Отнюдь, я просто показал широту своих взглядов и легкость к изменениям.


Ага, а ещй вот это:

Это был ответ в стиле, что если не указано, какого рода компилятор имеется ввиду, то я их написал сотни.


Помнится, Колхоз тоже бравировал тем, что понаписал кучу компиляторов и наизусть знает книгу дракона.
... << RSDN@Home 1.2.0 alpha rev. 672>>
Re[17]: Функциональное программирование в Nemerle
От: Lloyd Россия  
Дата: 23.05.07 16:38
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Compiler-compiler
Автор: konsoletyper
Дата: 31.03.07

VD>Где искать мой ты и сам догадашся. Плюс можешь еще мне записать работу над тем же Немерловым компилятором.

VD>Что дальше?


Спасибо
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[21]: Функциональное программирование в Nemerle
От: Аноним  
Дата: 24.05.07 16:50
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Предлагаю завязать с оффтопом и троллингом.

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

S>"здесь я не нарочно нарушил стандарт форматирования исходников на C#"

Будь, я на месте konsoletyper'а обязательно написал бы в ответ, что это "откровенная ложь"!
А так заявляю, что никогда не делал вид, что не нарочно нарушил некий стандарт форматирования исходников на C#.

S>Не забавляет затянутость этой шутки.

Что-то мешает игнорировать тему?
Re[2]: Функциональное программирование в Nemerle
От: IT Россия linq2db.com
Дата: 30.05.07 13:30
Оценка:
Здравствуйте, <Аноним>, Вы писали:

А>Обратил внимание, что в примере для Nemerle используются варианты и за счет этого можно успешно перебирать их в match.

А>Однако для C# также можно сделать подобное

Я когда-то очень давно эмулировал ООП на C, получалось примерно такое же г.
... << RSDN@Home 1.2.0 alpha rev. 0>>
Если нам не помогут, то мы тоже никого не пощадим.
Re[2]: Функциональное программирование в Nemerle
От: Иванков Дмитрий Россия  
Дата: 30.05.07 14:22
Оценка:
Здравствуйте, Кэр, Вы писали:

Кэр>
Кэр>    // без new данный вызов легко спутать с вызовом метода,
Кэр>    // а различать вызов метода и конструктора нужно по многим причинам
Кэр>  def stack = new Stack();

Различать их очень легко, конструктор всегда имеет имя this/base, если речь идет о текущем классе.
Если речь о внешнем по отношению к классу коду, то ничего страшного нет, при неоднозначности получим "overload ambiguity".
Идеология простая — вызов конструктора = вызов ф-ии, возвращающей экземпляр класса.

Ключевое слово new есть, но только для деклараций методов (virtual override или new).

За указание мест где требуются пояснения безусловно спасибо
Re[3]: Функциональное программирование в Nemerle
От: Кэр  
Дата: 30.05.07 14:31
Оценка:
Здравствуйте, Иванков Дмитрий, Вы писали:

ИД>Идеология простая — вызов конструктора = вызов ф-ии, возвращающей экземпляр класса.


В том-то и дело, что не равно. Метод может вернуть существующую копию объекта, конструктор всегда даст новый объект. Это уже дает совершенно разное отношение к этому коду.
Кроме того — лучше когда сразу понятно, куда надо если что обратить свой взор — где могут быть потенциальные проблемы. В одношаговых логических цепочках — это все равно, если что внимательно посмотрели на контекст, спохватились, начали думать в другом направлении. В более длинных цепочках подобные умолчания будут только тормозить решение проблемы.

И вообще если уж говорить про принципиальные отличия: внутри обычного метода можно использовать вызовы виртуальных методов, внутри конструктора нельзя — так что думать о них как о близнецах-братьях очень не рекомендуется.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[2]: Функциональное программирование в Nemerle
От: Кэр  
Дата: 30.05.07 14:33
Оценка:
konsoletyper, смелее, можно словами
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[5]: Функциональное программирование в Nemerle
От: Кэр  
Дата: 30.05.07 14:38
Оценка:
Здравствуйте, nikov, Вы писали:

N>Здравствуйте, Кэр, Вы писали:


Кэр>>В том-то и дело, что не равно. Метод может вернуть существующую копию объекта, конструктор всегда даст новый объект.


N>В Nemerle вызов конструктора не всегда возвращает новый объект.


Обалдеть А зачем это сделано?
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[3]: Функциональное программирование в Nemerle
От: Сергей Туленцев Россия http://software.tulentsev.com
Дата: 30.05.07 14:40
Оценка:
Здравствуйте, Иванков Дмитрий, Вы писали:

ИД>Ключевое слово new есть, но только для деклараций методов (virtual override или new).


Vermicious Knid припахал его еще для конструирования анонимных типов. Правда, в SVN это так и не попало, по моему.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
--
Re[6]: Функциональное программирование в Nemerle
От: nikov США http://www.linkedin.com/in/nikov
Дата: 30.05.07 14:40
Оценка:
Здравствуйте, Кэр, Вы писали:

N>>В Nemerle вызов конструктора не всегда возвращает новый объект.


Кэр>Обалдеть А зачем это сделано?


По-моему, очевидно... Для экономии объектов.
Re[4]: Функциональное программирование в Nemerle
От: Иванков Дмитрий Россия  
Дата: 30.05.07 14:51
Оценка:
Здравствуйте, Кэр, Вы писали:

Кэр>И вообще если уж говорить про принципиальные отличия: внутри обычного метода можно использовать вызовы виртуальных методов, внутри конструктора нельзя — так что думать о них как о близнецах-братьях очень не рекомендуется.


Верно, но конструктор "создающий" это как раз фактически обычная функция, и имя у нее такое же как и у класса.
А вот в том что внутри конструктора есть конечно упомянутая разница, и имя уже this/base для конструктора этого же экземпляра.
Re[5]: Функциональное программирование в Nemerle
От: Кэр  
Дата: 30.05.07 14:55
Оценка:
Здравствуйте, Иванков Дмитрий, Вы писали:

ИД>Здравствуйте, Кэр, Вы писали:


ИД>Верно, но конструктор "создающий" это как раз фактически обычная функция, и имя у нее такое же как и у класса.

ИД>А вот в том что внутри конструктора есть конечно упомянутая разница, и имя уже this/base для конструктора этого же экземпляра.

Ну, согласен
В общем, после того, как я осознал, что конструктор в Nemerle может не создать объект — надо сесть, помедитировать и провести оценку ценостей заново

Но замечания насчет return вполне в силе.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[3]: Функциональное программирование в Nemerle
От: anonym469  
Дата: 30.05.07 15:40
Оценка:
Здравствуйте, IT, Вы писали:

IT>Я когда-то очень давно эмулировал ООП на C

Я знал, что у нас есть что-то общее в далеком прошлом.
IT>получалось примерно такое же г.
Компактное г, смею заметить. А не пятикратное г.
Re[4]: Функциональное программирование в Nemerle
От: VladD2 Российская Империя www.nemerle.org
Дата: 31.05.07 11:06
Оценка:
Здравствуйте, Кэр, Вы писали:

Кэр>В том-то и дело, что не равно. Метод может вернуть существующую копию объекта, конструктор всегда даст новый объект. Это уже дает совершенно разное отношение к этому коду.


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

К тому же, если это так уж актуально, то всегда можно подвести мышку в IDE и посмореть, что это такое...

Кэр>Кроме того — лучше когда сразу понятно, куда надо если что обратить свой взор — где могут быть потенциальные проблемы.


Лучше сосредоточить свое внимание на логике программы. Тогда, если что просто не случится. Или если вдруг случится, то ты все равно будешь иметь больший контроль над программой, так как не возишся с мелочевкой, а владеешь сутью программы.

Кэр> В одношаговых логических цепочках — это все равно, если что внимательно посмотрели на контекст, спохватились, начали думать в другом направлении. В более длинных цепочках подобные умолчания будут только тормозить решение проблемы.


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

Кэр>И вообще если уж говорить про принципиальные отличия: внутри обычного метода можно использовать вызовы виртуальных методов, внутри конструктора нельзя — так что думать о них как о близнецах-братьях очень не рекомендуется.


1. Ты глубого заблуждаешся. В дотнете без проблем можно вызвать виртуальные методы из констроторов и финалайзеров.
2. А это уже никого не трогает. Точнее трогает того кто создает этот метод/конструктор. Ты работаешь с черным ящиком. Собственно это и есть инкапсуляция.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[5]: Функциональное программирование в Nemerle
От: VladD2 Российская Империя www.nemerle.org
Дата: 31.05.07 11:06
Оценка:
Здравствуйте, nikov, Вы писали:

N>В Nemerle вызов конструктора не всегда возвращает новый объект.


Можно с этого места по подробнее? О чем речь?
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[4]: Функциональное программирование в Nemerle
От: VladD2 Российская Империя www.nemerle.org
Дата: 31.05.07 11:06
Оценка:
Здравствуйте, konsoletyper, Вы писали:

K>Вообще, использовать new или нет — дело привычки, и, поверь, когда привыкнешь не писать new, обратно отвыкнуть будет труднее.


Хочу подчеркнуть эту мысль. Порой мы просто привыкаем к некоторому подходу и начинаем думать, что это "единственно верный путь". Привыкать к другому подходу всегда трудно. Это всегда вызвать некоторое неприятие.

Однако есть четкий способ понять какой из путей лучше. Если при обратном переходе неприятие (ломка) становится больше, то однозначо первый путь был хуже.

Так вот, подобные вещи в Немерле случаются очень часто. По началу кажется, что в нем использованы весьма спорыные решения, но поработав на Немеле и возвращаясь к C# начинашь испытвать такую ломку, что понимашь — решения выбранные в нем не случайны. Они имеют под собой основания. Просто эти основания не сразу становятся очевидными.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[5]: Функциональное программирование в Nemerle
От: VladD2 Российская Империя www.nemerle.org
Дата: 31.05.07 11:06
Оценка:
Здравствуйте, Кэр, Вы писали:

Кэр>Повторюсь — я не осозновал, что в Nemerle конструктор не обязательно возвращает новый объект.


Откровенно говоря я и по сей момент не осознаю. Семантика конструктора в Немерле вроде кака 1 в 1 C#-ная. Наверно, стоит дождаться пояснений от nikov-а.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[4]: Функциональное программирование в Nemerle
От: VladD2 Российская Империя www.nemerle.org
Дата: 31.05.07 11:06
Оценка:
Здравствуйте, anonym469, Вы писали:

A>Компактное г, смею заметить. А не пятикратное г.


Не очень. Просто автор "забыл" привести две тонны кода эмулируюих паттерн матчинг. Уверю тнебя, там будет не только не мало кода, но он будет еще и тормозным и не универсальным.

Дело в том, что паттерн-матчинг — это не очень тривиальная вещь. Разбирая match-и компилятор проводит весьма интеллектуальную работу. Он выстраивает дерево решения и уже на его основании генерирует ординарный код. Получаемый в результате код получается весьма эффективным. Достичь того же самого эмуляцией невозможно. Любое усложнение образцов будет усложнять задачу на порядки.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[5]: Функциональное программирование в Nemerle
От: VladD2 Российская Империя www.nemerle.org
Дата: 31.05.07 11:06
Оценка:
Здравствуйте, IT, Вы писали:

IT>ЗЫ. Я то этой фигнёй занимался от безнадёги, т.к. меня с C++ на C обратно на какое-то время пересадили. А зачем тебе это надо совсем непонятно.


Это как раз вроде ясно. Вудя по айпишникам — это тот самый троль, что развил всю тему.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[5]: Функциональное программирование в Nemerle
От: Кэр  
Дата: 31.05.07 11:54
Оценка:
Здравствуйте, VladD2, Вы писали:

Кэр>>В том-то и дело, что не равно. Метод может вернуть существующую копию объекта, конструктор всегда даст новый объект. Это уже дает совершенно разное отношение к этому коду.


VD>И в чем разница?

VD>И как ты справляешся с ситуацией когда у тебя есть фабричный метод? Ведь в этом случае по внешнему его виду нельзя скзать создаст ли он экземпляр или вызвратит уже имеющийся.

Дело в другом: когда мне объект падает от конструктора — я знаю, что это brand new объект. У меня не будет проблем с синхронизацией при его использовании. Мне не нужно будет думать — а вдруг его свойства уже как-то криво проинициализированны и мне нужно сначала исполнить шаманский танец перед его использованием.
Чаще всего Если это не так — значит это бага класса.
Поясню на примере — если мне приходит SqlCommand из какого-то метода, значит лезем в метод и смотрим, что за объект, что с ним уже сделали и пр. Если объект получен из конструктора — сразу работаем дальше.

VD>К тому же, если это так уж актуально, то всегда можно подвести мышку в IDE и посмореть, что это такое...


Да поддержка IDE — великая вещь. Но если из самого кода можно понять, что тут написано и быстро сделать вывода, причем стоимость создания такого кода невелика — то нужно писать как можно более понятный код. Ведь за мышкой покаааа потянееешься...

Кэр>>Кроме того — лучше когда сразу понятно, куда надо если что обратить свой взор — где могут быть потенциальные проблемы.


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


Когда сам пишешь код — ага. Когда читаешь чужой код — все намного хуже. Суть программы еще не схвачена. До нее как раз надо докопаться. В своем исходном посте я как раз привел ключевые слова, которые на мой взгляд к этому подталкивают.

Кэр>> В одношаговых логических цепочках — это все равно, если что внимательно посмотрели на контекст, спохватились, начали думать в другом направлении. В более длинных цепочках подобные умолчания будут только тормозить решение проблемы.

VD>Это в тебе говорят привычки и догмы. Точнее ты пыташся выдумать проблемы там где их нет, чтобы обосновать привычный тебе внешний вид кода.
Отнюдь. Вот это ни разу не привычный мне внешний вид кода.
def calc() : bool
{}

Просто этот код гораздо более информативный, чем этот:
def calc()
{}

Причем данная инфмормативность для автора кода чаще всего ничего не стоит.

Кэр>>И вообще если уж говорить про принципиальные отличия: внутри обычного метода можно использовать вызовы виртуальных методов, внутри конструктора нельзя — так что думать о них как о близнецах-братьях очень не рекомендуется.


VD>1. Ты глубого заблуждаешся. В дотнете без проблем можно вызвать виртуальные методы из констроторов и финалайзеров.


Как ты думаешь, что произойдет, если создать экземпляр Derived класса?
public abstract class Base
    {
        public Base()
        {
            Log("Instance created");
        }

        public abstract void Log(string message);
    }

    public class Derived : Base
    {
        public Derived()
        {
             _logMessages = new StringBuilder();
        }

        private StringBuilder _logMessages;

        public override void Log(string message)
        {
            _logMessages.Append(message);
            Console.WriteLine(message);
        }
    }



VD>2. А это уже никого не трогает. Точнее трогает того кто создает этот метод/конструктор. Ты работаешь с черным ящиком. Собственно это и есть инкапсуляция.


С этим не спорю. Я говорил о том, что в целом нельзя относится к конструктору и к методу, как к одному и тому же.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[6]: Функциональное программирование в Nemerle
От: konsoletyper Россия https://github.com/konsoletyper
Дата: 31.05.07 12:29
Оценка:
Здравствуйте, Кэр, Вы писали:

Кэр>Дело в другом: когда мне объект падает от конструктора — я знаю, что это brand new объект. У меня не будет проблем с синхронизацией при его использовании. Мне не нужно будет думать — а вдруг его свойства уже как-то криво проинициализированны и мне нужно сначала исполнить шаманский танец перед его использованием.


Неужели? А вдруг вновь созданный объект содержит внутри себя ссылку на уже давно созданный объект? От кривого изайна никакой компилятор не спасёт...

Кэр>Отнюдь. Вот это ни разу не привычный мне внешний вид кода.

Кэр>
Кэр>def calc() : bool
Кэр>{}
Кэр>

Кэр>Просто этот код гораздо более информативный, чем этот:
Кэр>
Кэр>def calc()
Кэр>{}
Кэр>

Кэр>Причем данная инфмормативность для автора кода чаще всего ничего не стоит.

Наивный...

А если из этой функции что-то невразумительное возвращается, вроде Map[string * bool, list[int * bool * string * string]]? Это, конечно, перегиб, и не стоит использовать такие вот конструкции в чём-то большом. Но бывает и так, что подобные выкрутасы являются более оправданными. Что же, мне всё это расписывать?

Кэр>С этим не спорю. Я говорил о том, что в целом нельзя относится к конструктору и к методу, как к одному и тому же.


Кто тебе это сказал?
... << RSDN@Home 1.2.0 alpha rev. 672>>
Re[6]: Функциональное программирование в Nemerle
От: Кэр  
Дата: 31.05.07 13:01
Оценка:
Здравствуйте, konsoletyper, Вы писали:

Кэр>>Повторюсь — я не осозновал, что в Nemerle конструктор не обязательно возвращает новый объект. С учетом специфики работы конструктора в .Net (в частности в силу отсутвия его собрата — деструктора) это может быть и вполне оправдано. Но опять же — это радикальное отличие от остальных .Net языков. Так что этому пожалуй стоит уделить особое внимание для "начинающих на Nemerle".


K>Ну, я сам не особо разбираюсь в нюансах работы компилятора Nemerle. Но дело не в том, что реально возвращается конструктором, а как это значение интерпретируется человеком. Если просто читать программу в "фнукциональном" режиме, то использование new начинает казаться неоправданным.


Здесь
Автор: Кэр
Дата: 31.05.07
я расписал, почему стоит различать вызов конструктора и метода.

Кэр>>Вот именно, что нужно вглядываться в контекст, чтобы получить принципиальное знание. Если бы функция была чуть сложнее — например, она бы делегировала все исходы другим функциям — пришлось бы смотреть, что возрвращают те функции. Совершенно лишний шаг при чтении кода. При том, что по сути — от умолчания : bool код ничего не выигрывает.


K>Да нет, никаких проблем с этим не возникает. Обычно, если грамотно называть функции и переменные, производить декомпозицию, то всё становится более менее очевидным. В худшем случае никто не мешает навиести курсор на функцию и получить хинт. Советую заодно присмотреться к динмически-типизированным языкам вроде PHP и Python, где при правильном проектировании и документировании таких проблем не возникает. Пролемы в них возникают при отладке, а вот в ML-образных языках мы получаем такую же лаконичность и не теряем в удобстве отладки (потенциально).


Спор ради спора? Ты даже готов следить за правильным именованием методов и переменных — лишь бы не указывать небольшую дополнительную информацию. Чем тебе так мешает этот : bool?

Кэр>>Ну и что? Это никак не противоречит тому, что выставления return в том месте, где возращается уже конечное значение (некоторое value-значение или объект) — повышает читабельность кода.


K>Опять же, значение не возвращается, а вычисляется. И это совершенно разные вещи. Вообще, если ты ещё не сомтрел на Scheme, то советую почитать SICP, там все эти вещи хорошо описаны (ой, сейчас Влад на меня зарычит, но я всё же твёрдо останусь при мнении, что SICP — отличное руководство по ФП для начинающих).


Под возращением я имел ввиду то место, где начинает разворачиваться стэк вызовов. Я понимаю отличие императивного и функционального кода
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[6]: Функциональное программирование в Nemerle
От: VladD2 Российская Империя www.nemerle.org
Дата: 31.05.07 13:04
Оценка:
Здравствуйте, Кэр, Вы писали:

Кэр>Дело в другом: когда мне объект падает от конструктора — я знаю, что это brand new объект. У меня не будет проблем с синхронизацией при его использовании.


Это в корне не верное предположение. Объект может быть устроен как угодно. В том числе он может запоминать создаваемые экземлпяры в неком глобальном массиве. Стало быть, любые предположения могут быть невреными.

Именно по этому объекты рассматривают как черные ящики имеющие только публичный интерфейс и некое оговариваемое поведение. Последнее и обуславливает то как можно использовать объект.

Кэр> Мне не нужно будет думать — а вдруг его свойства уже как-то криво проинициализированны и мне нужно сначала исполнить шаманский танец перед его использованием.


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

Кэр>Поясню на примере — если мне приходит SqlCommand из какого-то метода, значит лезем в метод и смотрим, что за объект, что с ним уже сделали и пр. Если объект получен из конструктора — сразу работаем дальше.


Зачем куда-то лезть? Если тебе возвращают SqlCommand, то это уже подразумевает, что команда должна быть должным образом инициализирована. Если тебе нужно каждый раз лезть в кишки методов, чтобы понять как их использовать, то или ты очень неуверен в себе и всего боишся, или ты имешь дело с кривой и неудобной библиотекой (кодом).

Кэр>Да поддержка IDE — великая вещь. Но если из самого кода можно понять, что тут написано и быстро сделать вывода, причем стоимость создания такого кода невелика — то нужно писать как можно более понятный код. Ведь за мышкой покаааа потянееешься...


Из кода должна быть понятна логика, а не информация о типах. Или тогда уж нужно быть последовательным. Почему тебе нужна информация только о том конструктор это или нет? А информация о типах параметров тебе не нужна? Давай тогда как это делали на С/С++ вписывать в имена всех переменных префиксы описывающие типы. Ведь С-подобные языки (да и почти любые языки) не предоставляют описание типов аргументов вызова.

Когда мне нужно знать тип фукнции я просто подвожу мышку к нужному вызову. Точно так же если я не уверен в том, что за вызов находится у меня в коде, я могу подвести мышку и увидеть надпись "constructor..." где будет кроме всего прочего еще описание типов его параметров и возомжно подсказка.

Когда же я читаю код мне важны более абстракные факты. Я и так додумаюсь, что это создание новго объекта.

К тому же функцианальный стиль подталкивает к тому, что бы воспринималь, по возможности, все как вызовы фукнций. И то что конструктор тоже выглядит как фукнция — это часть этого стиля.

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

Кэр>Когда сам пишешь код — ага. Когда читаешь чужой код — все намного хуже. Суть программы еще не схвачена.


Не соглашусь. Чем меньше лишних деталей, тем проще как раз ухватить суть программы. А уж если тебе для понимания потребуется информация о неком идентефикаторе, то ты всегда можешь подвести к нему мышку и поглядеть хинт.

Кэр> До нее как раз надо докопаться. В своем исходном посте я как раз привел ключевые слова, которые на мой взгляд к этому подталкивают.


Просто ты привык читать запутанный код и тебе кажется, что лишние (не влияющие на логику) являются очень важными. На самом деле это не так. Точнее если бы это было так, то прграммы написанные на скриптовых языках вроде Питона или Руби вообще невозможно было читать. Однако многие находят, что как раз все с точностью до наоборот и программы на хороших скриптовых языках читать проще чем, скажем, на C#.

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

Кэр>Отнюдь.

Я тоже писал в прошлом на С/С++/C#/Delphi и т.п. и знаю о чем говорю.

Кэр> Вот это ни разу не привычный мне внешний вид кода.

Кэр>
Кэр>def calc() : bool
Кэр>{}
Кэр>

Кэр>Просто этот код гораздо более информативный, чем этот:
Кэр>
Кэр>def calc()
Кэр>{}
Кэр>

Кэр>Причем данная инфмормативность для автора кода чаще всего ничего не стоит.

Да не проблема, если тебе кажется это лучшим ты имешь право вставить тип явно. Более того ты можешь указать тип даже там где в C# это сделать невозможно. Свобода выбора!

Но это очень примитивный случай. Здесь явное указание типа не заграмождает код. А бывает, так что парметров моного и типы начинают занимать слишком много места. Причем из параметров и названия метода ясно, что за типы у параметров и возвращаемого значения. При этом явное указанеие типов будет только мешать.

И опять же напоминаю, что есть IDE и IntelliSense. Если ты читаешь чужой код и тебе хочется понять, что значение какого типа возварщает фукнция, то ты можешь просто подвести курсор мыши и прочестьп олное описание типа фкнции. Так что с чтение чужого кода проблем особо нет если ты читаешь его в IDE. Другое дело если это отдельный файл или статья.

Кэр>Как ты думаешь, что произойдет, если создать экземпляр Derived класса?


Если все спроектировано грамотно, то все будет ОК. А нагородить ошибок можно и без того. К тому же я не понимаю какой смысл обсуждать факт? Это реальность и о ней нужно знать.

Кэр>
Кэр>public abstract class Base
Кэр>    {
Кэр>        public Base()
Кэр>        {
Кэр>            Log("Instance created");
Кэр>        }

Кэр>        public abstract void Log(string message);
Кэр>    }

Кэр>    public class Derived : Base
Кэр>    {
Кэр>        public Derived()
Кэр>        {
Кэр>             _logMessages = new StringBuilder();
Кэр>        }

Кэр>        private StringBuilder _logMessages;

Кэр>        public override void Log(string message)
Кэр>        {
Кэр>            _logMessages.Append(message);
Кэр>            Console.WriteLine(message);
Кэр>        }
Кэр>    }
Кэр>


Будет исключение которое с вероятностью 99% будет выявлено при первом же запуске.

Кэр>С этим не спорю. Я говорил о том, что в целом нельзя относится к конструктору и к методу, как к одному и тому же.


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

Интересно, кстати, что в Немреле с конструктором ожно обращаться точно так же как с функций. Например, следующий пример прекрасно работает:
def strCreator = string;
def someFanction(f)
{
    f(array['H', 'i', '!'])
}

WriteLine(someFanction(strCreator));


И того у нас получается:
1. Функция — это превокласное значение в Немерле. Ею можно гибко манипулировать.
2. Конструктор — это тоже частный вид функции.
Ну, и вывод:
Мы получаем мощнейшие выразительные средства функциональной декомпозиции. И все это благодаря тому, что наш язык более абстрактен нежели закомплексованные императивные предшественники.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[7]: Функциональное программирование в Nemerle
От: Кэр  
Дата: 31.05.07 13:11
Оценка:
Здравствуйте, konsoletyper, Вы писали:

Кэр>>Дело в другом: когда мне объект падает от конструктора — я знаю, что это brand new объект. У меня не будет проблем с синхронизацией при его использовании. Мне не нужно будет думать — а вдруг его свойства уже как-то криво проинициализированны и мне нужно сначала исполнить шаманский танец перед его использованием.


K>Неужели? А вдруг вновь созданный объект содержит внутри себя ссылку на уже давно созданный объект? От кривого изайна никакой компилятор не спасёт...


Ответ содержится в той части, которая выпала из цитаты

Кэр>>Отнюдь. Вот это ни разу не привычный мне внешний вид кода.

Кэр>>
Кэр>>def calc() : bool
Кэр>>{}
Кэр>>

Кэр>>Просто этот код гораздо более информативный, чем этот:
Кэр>>
Кэр>>def calc()
Кэр>>{}
Кэр>>

Кэр>>Причем данная инфмормативность для автора кода чаще всего ничего не стоит.

K>Наивный...


K>А если из этой функции что-то невразумительное возвращается, вроде Map[string * bool, list[int * bool * string * string]]? Это, конечно, перегиб, и не стоит использовать такие вот конструкции в чём-то большом. Но бывает и так, что подобные выкрутасы являются более оправданными. Что же, мне всё это расписывать?


В таком случае — тем более. Это часть сигнатуры функции. Если функция имеют такую страшную сигнатуру — в большинстве случаев это нужно знать заранее.
Опять же ключевое слово — в большинстве. Подчеркиваю: написать bool — очень просто, а самодокументирование кода сильно возрастает.

Кэр>>С этим не спорю. Я говорил о том, что в целом нельзя относится к конструктору и к методу, как к одному и тому же.

K>Кто тебе это сказал?

Опыт использования технологии .Net. Ты пробовал запустить тот код, что я привел выше по ветке?
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[4]: Функциональное программирование в Nemerle
От: VladD2 Российская Империя www.nemerle.org
Дата: 31.05.07 13:28
Оценка:
Здравствуйте, Кэр, Вы писали:

Кэр>Здравствуйте, VladD2, Вы писали:


VD>>От догм и предрассудков лучше избавляться.


Кэр>Угу, то что ты подписываешь меня на догматическое мышление я уже понял


Почему только тебя? Я сам по началу был немного обескуражен другим стилем записи.

Код типа:
def f(x)
{
  when (x)
    1;
    
    2;
}

я воспринимал как:
int f(bool x)
{
  if (x)
    return 1;
        
  return 2;
}

и первое время входил в ступо когда компилятор выдвавл предупреждение о том, что игнарируется каое-то там значение.

Кэр> В рассуждениях на самом деле не было ни одного отправного пункта — а вот в других языках так поэтому надо делать именно так. Рассуждения начинаются с нуля. Опровергай их тоже с нуля, не вешая на меня ярлыки Вполне допускаю, что могу быть неправ.


В том-то и дело, что не с нуля. Люди которые начинали писать скажем на Лиспе даже не зададут такой вопрос. Просто ты так привык к reurn-ам, что в твоем сознании это единственно правильный выбор и ты уже на подсознательном уровне отвергаешь "странные" варианты.

Со мной была та же фигня. Через неделю практики от этого не остается и следа. А через месяц ты начинаешь задваться вопросом "Зачем я всю жизнь тыкал return-ы там где они на фиг не упали?".

Кстати, в C# 3.0 появятся лямбды — анонимные методы с выводом типов (гы-гы) и тела которых могут быть чистыми выражениями. Так вот в них будут такие же "проблемы". Тоже не будет return-ов и можно будет не указывать типы. Возможно, даже, что тип возвращаемого значения вообще нельзя будет задать явно. Так что привыкать по любому придется. А как привыкнешь, то и вопрос сам собой отпадет.

VD>>Кстати, есть один вопрос:

VD>>
VD>>    | EndOfFile           => return stack.Count == 1
VD>>        ...
VD>>    | EndRound            => check(_ is Token.BeginRound)  // )
VD>>

VD>>А почему в первой строчке return понадобился, а во второй нет?

Кэр>Как раз по тем причинам, что я указывал выше — return обозначает то место, где начнет разворачиваться стэк вызовов функций.


Дык "стек начинает разворачиваться" в обоих случаях. В обоих случаях вычесленное значение будет возвращего из фукнции.

Кстати, скажу по сикрету, что физически никакого стека вызовов и темболее его раскрутки не будет. Дело в том, что эта рекурсия концевая. И компилятор перепишет ее в цикл. Так что не останется ни вызова метода, ни его рекрусивных вызово. В место этого физически будет сгенерирован цикл.

Кэр>Такой return

VD>>
VD>>    | EndRound            => return check(_ is Token.BeginRound)  // )
VD>>

Кэр>лишний. Здесь просто вычисления идут вглубь по стэку вызова.

... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[5]: Функциональное программирование в Nemerle
От: VladD2 Российская Империя www.nemerle.org
Дата: 31.05.07 13:28
Оценка:
Здравствуйте, konsoletyper, Вы писали:

Кэр>>Как раз по тем причинам, что я указывал выше — return обозначает то место, где начнет разворачиваться стэк вызовов функций.

Кэр>>Такой return
VD>>>
VD>>>    | EndRound            => return check(_ is Token.BeginRound)  // )
VD>>>

Кэр>>лишний. Здесь просто вычисления идут вглубь по стэку вызова.

K>Непоследовательно...


Скажу больеш — ошибочно. Или мы оба варианта рассматриваем как вычисление, или как возврат значений. Иначе получается мешанина.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[7]: Функциональное программирование в Nemerle
От: Кэр  
Дата: 31.05.07 13:48
Оценка:
Здравствуйте, VladD2, Вы писали:

Кэр>>Дело в другом: когда мне объект падает от конструктора — я знаю, что это brand new объект. У меня не будет проблем с синхронизацией при его использовании.


VD>Это в корне не верное предположение. Объект может быть устроен как угодно. В том числе он может запоминать создаваемые экземлпяры в неком глобальном массиве. Стало быть, любые предположения могут быть невреными.


VD>Именно по этому объекты рассматривают как черные ящики имеющие только публичный интерфейс и некое оговариваемое поведение. Последнее и обуславливает то как можно использовать объект.


Ключевое слово в этом утверждении было: "Чаще всего". Я знаю очень мало объектов, которые занимаются описанным извратом. Более того, я знаю очень много библиотечных классов, которые таким извратом не занимаются.


VD>Если тебе нужно думать о таких вещах, то это уже признак того, что класс спроектирован из рук плохо.


VD>Зачем куда-то лезть? Если тебе возвращают SqlCommand, то это уже подразумевает, что команда должна быть должным образом инициализирована. Если тебе нужно каждый раз лезть в кишки методов, чтобы понять как их использовать, то или ты очень неуверен в себе и всего боишся, или ты имешь дело с кривой и неудобной библиотекой (кодом).


Ну вот уже перешли на личности Я прагматичный человек, не верю в абстрактные лозунги (ООП, правильное проектирование и т.п.) и очень неуверен в других А также понимаю, что проблему можно видеть очень по-разному и соответственно с объектами работать очень по-разному. Так что когда мне возвращают SqlCommand — я задаюсь вопросом — а какой connection он использует? Нет передано ли туда уже каких-либо параметров и прочее, и прочее.

VD>Из кода должна быть понятна логика, а не информация о типах. Или тогда уж нужно быть последовательным. Почему тебе нужна информация только о том конструктор это или нет? А информация о типах параметров тебе не нужна? Давай тогда как это делали на С/С++ вписывать в имена всех переменных префиксы описывающие типы. Ведь С-подобные языки (да и почти любые языки) не предоставляют описание типов аргументов вызова.


Зачем сходить с ума? Конкретно в этом случае совершенно сразу неочевидно, что scan, принимающая параметр типа Token — это и есть практически та функция, которая ответит на ключевой вопрос парности скобок. А если указать тип возвращаемого значения сразу при декларации сигнатуры функции scan — уже понятно, что скорее всего это именно эта функция и ее содержимое будет читаться уже вкупе с этим знанием.

VD>Когда мне нужно знать тип фукнции я просто подвожу мышку к нужному вызову. Точно так же если я не уверен в том, что за вызов находится у меня в коде, я могу подвести мышку и увидеть надпись "constructor..." где будет кроме всего прочего еще описание типов его параметров и возомжно подсказка.


Повторяю — написать bool очень быстро, ничему не противоречит. Каждому тянутся мышкой, кто будет читать этот код — долго. А в данной статье и вообще невозможно.


Кэр>>Когда сам пишешь код — ага. Когда читаешь чужой код — все намного хуже. Суть программы еще не схвачена.


VD>Не соглашусь. Чем меньше лишних деталей, тем проще как раз ухватить суть программы. А уж если тебе для понимания потребуется информация о неком идентефикаторе, то ты всегда можешь подвести к нему мышку и поглядеть хинт.


Ну да Есть пример такого языка — Perl. Очень кратко. Но зачастую понять это чириканье просто нереально.

VD>Однако многие находят, что как раз все с точностью до наоборот и программы на хороших скриптовых языках читать проще чем, скажем, на C#.


Весьма спорное утверждение.

Кэр>> Вот это ни разу не привычный мне внешний вид кода.

Кэр>>
Кэр>>def calc() : bool
Кэр>>{}
Кэр>>

Кэр>>Просто этот код гораздо более информативный, чем этот:
Кэр>>
Кэр>>def calc()
Кэр>>{}
Кэр>>

Кэр>>Причем данная инфмормативность для автора кода чаще всего ничего не стоит.

VD>Да не проблема, если тебе кажется это лучшим ты имешь право вставить тип явно. Более того ты можешь указать тип даже там где в C# это сделать невозможно. Свобода выбора!


Не спорю. Просто, имхо, это должно быть что-то вроде guideline разработки — использовать вывод типов именно там, где это принципиально сокращает и упрощает код. А не просто везде, где только можно.

VD>Но это очень примитивный случай. Здесь явное указание типа не заграмождает код. А бывает, так что парметров моного и типы начинают занимать слишком много места. Причем из параметров и названия метода ясно, что за типы у параметров и возвращаемого значения. При этом явное указанеие типов будет только мешать.


Тогда их указывать не надо.

VD>Если все спроектировано грамотно, то все будет ОК. А нагородить ошибок можно и без того. К тому же я не понимаю какой смысл обсуждать факт? Это реальность и о ней нужно знать.


Я к тому, что не надо никогда не забывать о реальности и в первую очередь при проектировании языка и правил хорошего оформления кода на этом языке.

VD>Будет исключение которое с вероятностью 99% будет выявлено при первом же запуске.

И это все проблемы, что ты тут видишь? А если кто-нибудь, кто не знаком с подробностями реализации Base возьмет и отнаследуется от него, а в конструкторе напишет такой код, что не получит null reference ошибку, а просто в методе Log будет работать с недоинициализированным объектом. При этом могут происходить самые разнообразные веселые и совсем не очень вещи.

VD>В целом это не только можно делать, но и нужно. Это всего лишь предрассудок который просто нужно преодолеть. Думать о конструктре как о фунции очень полезно. Это дает более горманичную картину преложения. Просто можно думать о конструктре как о частном случае метода.

То же самое, что и я говорил, просто другими словами. Конструктор и метод различаются — причины изложены выше.

VD>Интересно, кстати, что в Немреле с конструктором ожно обращаться точно так же как с функций. Например, следующий пример прекрасно работает:

VD>
VD>def strCreator = string;
VD>def someFanction(f)
VD>{
VD>    f(array['H', 'i', '!'])
VD>}

VD>WriteLine(someFanction(strCreator));
VD>


Да, это интересный пример.

VD>И того у нас получается:

VD>1. Функция — это превокласное значение в Немерле. Ею можно гибко манипулировать.
VD>2. Конструктор — это тоже частный вид функции.
VD>Ну, и вывод:
VD>Мы получаем мощнейшие выразительные средства функциональной декомпозиции. И все это благодаря тому, что наш язык более абстрактен нежели закомплексованные императивные предшественники.
С этим не спорю. Но по изложенным выше причинам — различать их вызовы очень часто все равно нужно
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[6]: Функциональное программирование в Nemerle
От: anonym469  
Дата: 31.05.07 16:39
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>что развил всю тему.

Звучит как похвала.
Re[6]: Функциональное программирование в Nemerle
От: Иванков Дмитрий Россия  
Дата: 31.05.07 18:56
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Здравствуйте, nikov, Вы писали:


N>>В Nemerle вызов конструктора не всегда возвращает новый объект.


VD>Можно с этого места по подробнее? О чем речь?


Видимо о variant без полей
class A {}
variant B {|Q}
A () : object != A () : object;
B.Q () : object == B.Q () : object;

В частном случае с [] это практически очевидно и не бросается в глаза, а вот про произвольный variant как-то раньше не задумывался.
Re[8]: Функциональное программирование в Nemerle
От: VladD2 Российская Империя www.nemerle.org
Дата: 01.06.07 00:39
Оценка:
Здравствуйте, Кэр, Вы писали:

Кэр>Ключевое слово в этом утверждении было: "Чаще всего". Я знаю очень мало объектов, которые занимаются описанным извратом. Более того, я знаю очень много библиотечных классов, которые таким извратом не занимаются.


Дык трудно уловимые ошибки и появляются когда совпадают несколько не очень часто появляющихся особенностей.

Кэр>Ну вот уже перешли на личности Я прагматичный человек, не верю в абстрактные лозунги (ООП, правильное проектирование и т.п.) и очень неуверен в других А также понимаю, что проблему можно видеть очень по-разному и соответственно с объектами работать очень по-разному. Так что когда мне возвращают SqlCommand — я задаюсь вопросом — а какой connection он использует? Нет передано ли туда уже каких-либо параметров и прочее, и прочее.


Это плохой подход. Все узнать нельзя. Нужные вещи должны оговариваться отдельно. А остальное должно жить на тестировании и разумных умолчаниях.

Так от команды тебе важно, чтобы она могла выполнить нужный тебе SQL. Пока это так (тесты работают) разбираться бессмысленно.

VD>>Из кода должна быть понятна логика, а не информация о типах. Или тогда уж нужно быть последовательным. Почему тебе нужна информация только о том конструктор это или нет? А информация о типах параметров тебе не нужна? Давай тогда как это делали на С/С++ вписывать в имена всех переменных префиксы описывающие типы. Ведь С-подобные языки (да и почти любые языки) не предоставляют описание типов аргументов вызова.


Кэр>Зачем сходить с ума?


Хороший вопрос. Задай его себе .

Кэр> Конкретно в этом случае совершенно сразу неочевидно, что scan, принимающая параметр типа Token — это и есть практически та функция, которая ответит на ключевой вопрос парности скобок. А если указать тип возвращаемого значения сразу при декларации сигнатуры функции scan — уже понятно, что скорее всего это именно эта функция и ее содержимое будет читаться уже вкупе с этим знанием.


И в чем проблема? Если тебя занимает вопрос о типе возвращаемого значения при чтени, то подведи мышку. Если все и так очевидто, то двигай дальше!

Кэр>Повторяю — написать bool очень быстро, ничему не противоречит. Каждому тянутся мышкой, кто будет читать этот код — долго. А в данной статье и вообще невозможно.


Тянуться как раз не долго. Да и нужно это редко. А с bool тебе уже сказли. Да в данном случае он вряд ли повредит читабельности. А в более сложном — может. Так что в правило это воодить нельзя. Разве что для примера в статьях. Там это актуально.

Кэр>Ну да Есть пример такого языка — Perl. Очень кратко. Но зачастую понять это чириканье просто нереально.


Перл — это, кстати, по сегодняшним временам не очень кратко. И плохая читабельность там из-за невнятных соглашений (разных переменных и т.п.). Да и с хинтами там вроде бы не здорово. В прочем какие на фиг хинты если их смотреть негде? Ведь неявные переменные на то и не явные, чтобы их тяжело было отследить .

VD>>Однако многие находят, что как раз все с точностью до наоборот и программы на хороших скриптовых языках читать проще чем, скажем, на C#.


Кэр>Весьма спорное утверждение.


Это не утверждение, а констатация факта. Это кстати, не мое утверждение. Но поклонники динамики в один голос это заявляют.

В прочем, я тоже согласен, что зачастую в том же Шарпе аннотация типов избыточна. Те же анонимные методы это отлично показывают. И их модификация в C# 3.0 говорит о том, что авторы это тоже признают.

Кэр>Не спорю. Просто, имхо, это должно быть что-то вроде guideline разработки — использовать вывод типов именно там, где это принципиально сокращает и упрощает код. А не просто везде, где только можно.


Тут guideline один. Считашь, что что-то невнятно? Считашь, что аннотация типов увеличит читабельность? Вставь ее. Вставил? Код не загромоздился? Зашибись. Загромоздился? Фигово. Стоит подумать над тем, чтобы убрать аннотацию.

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

Кэр>Я к тому, что не надо никогда не забывать о реальности и в первую очередь при проектировании языка и правил хорошего оформления кода на этом языке.


Вот в C# из конструкторов можно взывать виртуальные метода. На форумах не раз поднимался вопрос об опасности этого. Но еще ни разу я не видел реального случая когда это привело бы к проблемам. Значит проблема надумана. И обсуждать ее смысла нет.

VD>>Будет исключение которое с вероятностью 99% будет выявлено при первом же запуске.

Кэр>И это все проблемы, что ты тут видишь? А если кто-нибудь, кто не знаком с подробностями реализации Base возьмет и отнаследуется от него, а в конструкторе напишет такой код, что не получит null reference ошибку, а просто в методе Log будет работать с недоинициализированным объектом. При этом могут происходить самые разнообразные веселые и совсем не очень вещи.

Твоих "если" просто не происходит на практике. Что обсуждать гипотетические проблемы?

VD>>В целом это не только можно делать, но и нужно. Это всего лишь предрассудок который просто нужно преодолеть. Думать о конструктре как о фунции очень полезно. Это дает более горманичную картину преложения. Просто можно думать о конструктре как о частном случае метода.

Кэр>То же самое, что и я говорил, просто другими словами. Конструктор и метод различаются — причины изложены выше.

Что тоже самое? Ты говорил, что плохо думать о конструктре как о фунции, а значит плохо когда они синтаксически неотличимы.

Кэр>Да, это интересный пример.


Вот если было бы обязательное new, то было бы тяжело объяснить почему присвоив конструктор переменной его вдруг можно стало вызвать как фукнцию. Кстати, обрати внимание на то, что в этом примере можно было подсунуть вместо конструктора ссылку на статическую фукнцию.

Кэр>С этим не спорю. Но по изложенным выше причинам — различать их вызовы очень часто все равно нужно


Вот я уже считай год языком пользуюсь и не разу этого не наблюдал. Значит все же это предпрассудок.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[5]: Функциональное программирование в Nemerle
От: Кэр  
Дата: 13.06.07 05:52
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Здравствуйте, Кэр, Вы писали:


VD>Почему только тебя? Я сам по началу был немного обескуражен другим стилем записи.


VD>Код типа:

VD>
VD>def f(x)
VD>{
VD>  when (x)
VD>    1;
    
VD>    2;
VD>}
VD>

VD>я воспринимал как:
VD>
VD>int f(bool x)
VD>{
VD>  if (x)
VD>    return 1;
        
VD>  return 2;
VD>}
VD>

VD>и первое время входил в ступо когда компилятор выдвавл предупреждение о том, что игнарируется каое-то там значение.

Кстати, да, по поводу такого вот примера — они наталкивают на похожий код, когда вначале идет "санитизация" входных параметров и уже дальше идет вычисление функции. Мне действительно интересно, как предлагается оформлять следующую логику в Nemerle:
Как данная логика должна быть оформлена в функциональном стиле? Вопрос скорее всего от малой практики использования того же pattern-matching'а. Но мне как новичку интересно

VD>В том-то и дело, что не с нуля. Люди которые начинали писать скажем на Лиспе даже не зададут такой вопрос. Просто ты так привык к reurn-ам, что в твоем сознании это единственно правильный выбор и ты уже на подсознательном уровне отвергаешь "странные" варианты.


VD>Со мной была та же фигня. Через неделю практики от этого не остается и следа. А через месяц ты начинаешь задваться вопросом "Зачем я всю жизнь тыкал return-ы там где они на фиг не упали?".


Вполне возможно

VD>Кстати, в C# 3.0 появятся лямбды — анонимные методы с выводом типов (гы-гы) и тела которых могут быть чистыми выражениями. Так вот в них будут такие же "проблемы". Тоже не будет return-ов и можно будет не указывать типы. Возможно, даже, что тип возвращаемого значения вообще нельзя будет задать явно. Так что привыкать по любому придется.


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

VD>>>Кстати, есть один вопрос:

VD>>>
VD>>>    | EndOfFile           => return stack.Count == 1
VD>>>        ...
VD>>>    | EndRound            => check(_ is Token.BeginRound)  // )
VD>>>

VD>>>А почему в первой строчке return понадобился, а во второй нет?

Кэр>>Как раз по тем причинам, что я указывал выше — return обозначает то место, где начнет разворачиваться стэк вызовов функций.


VD>Дык "стек начинает разворачиваться" в обоих случаях. В обоих случаях вычесленное значение будет возвращего из фукнции.


Я имел ввиду следующее — на уровню абстракций при вызове другой функции мы увеличиваем стэк вызова. Грубо говоря — делаем типичный шаг в некотором цикле. Так вот — при программировании цикла большинтсво проблем обычно пожинаются при задании условий входа в цикл и выхода из цикла. Поэтому к ним нужно обращать максимальное внимание. Собственно за этим и я предлагал оставить return — как отметку, что здесь мы начинаем раскручивать стэк вызова обратно — в этом месте мы по сути начинаем выходить из "цикла", это нужно заметить, нужно посмотреть какие условия выхода и пр.
Не претендую, что это самое общее правило — просто излагаю свой взгляд на осмысление подобного кода.

VD>Кстати, скажу по сикрету, что физически никакого стека вызовов и темболее его раскрутки не будет. Дело в том, что эта рекурсия концевая. И компилятор перепишет ее в цикл. Так что не останется ни вызова метода, ни его рекрусивных вызово. В место этого физически будет сгенерирован цикл.


Это здорово, что концевые рекурсии распознаются и разворачиваются в цикл. Но ведь это подробности реализации по сути. Мы же говорим о "концептуальном понимании кода"
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[9]: Функциональное программирование в Nemerle
От: Кэр  
Дата: 13.06.07 05:52
Оценка:
Здравствуйте, VladD2, Вы писали:

Кэр>>Ключевое слово в этом утверждении было: "Чаще всего". Я знаю очень мало объектов, которые занимаются описанным извратом. Более того, я знаю очень много библиотечных классов, которые таким извратом не занимаются.


VD>Дык трудно уловимые ошибки и появляются когда совпадают несколько не очень часто появляющихся особенностей.


С этим не спорю. Но как тут отсутствие слова return может помочь — я не понимаю. Но привожу аргументы, чему отсутствие этого слова может помешать.

VD>Это плохой подход. Все узнать нельзя. Нужные вещи должны оговариваться отдельно. А остальное должно жить на тестировании и разумных умолчаниях.


VD>Так от команды тебе важно, чтобы она могла выполнить нужный тебе SQL. Пока это так (тесты работают) разбираться бессмысленно.


От команды мне нужно многое — чтобы она выполнила нужный мне sql, на нужном sql сервере, с нужными параметрами. Я согласен, что всего узнать нельзя. Просто когда я вижу просто вызов конструктора для обще-известного класса я не полезу в потроха конструктора, чтобы проверить как он инициализируется — если там что-то не так — очень быстро это станет известно.
Если же поставкой этого объекта занимается некий неизвестный мне интернальный framework и я первый раз его использую — я не только прочитаю документацию по вызову этого метода, но и скорее всего быстро пробегу по пути инициализации этого объекта.

Кэр>>Повторяю — написать bool очень быстро, ничему не противоречит. Каждому тянутся мышкой, кто будет читать этот код — долго. А в данной статье и вообще невозможно.


VD>Тянуться как раз не долго. Да и нужно это редко. А с bool тебе уже сказли. Да в данном случае он вряд ли повредит читабельности. А в более сложном — может. Так что в правило это воодить нельзя. Разве что для примера в статьях. Там это актуально.


Согласен.

VD>Это не утверждение, а констатация факта. Это кстати, не мое утверждение. Но поклонники динамики в один голос это заявляют.


VD>В прочем, я тоже согласен, что зачастую в том же Шарпе аннотация типов избыточна. Те же анонимные методы это отлично показывают. И их модификация в C# 3.0 говорит о том, что авторы это тоже признают.


Да, при объявлении анонимных функций часто можно опускать типы входящих параметров и результата. Пока это умолчание не становится повсеместным... Но не будем по второму кругу

VD>Вот в C# из конструкторов можно взывать виртуальные метода. На форумах не раз поднимался вопрос об опасности этого. Но еще ни разу я не видел реального случая когда это привело бы к проблемам. Значит проблема надумана. И обсуждать ее смысла нет.


Не надо из частного случая и частного опыта выводить общее правило. Я вот тоже думал, что рассуждения о beforefieldinit аттрибуте при определении ленивого синглтона через static конструктор — рассуждения сугубо теоритические. И вот недавно в проекте наступили на эту проблему весело и с размаху
Проблема с вызовом виртуальных методов в конструкторах — тоже себе вполне живая и забывать о ней не стоит.


VD>>>Будет исключение которое с вероятностью 99% будет выявлено при первом же запуске.

Кэр>>И это все проблемы, что ты тут видишь? А если кто-нибудь, кто не знаком с подробностями реализации Base возьмет и отнаследуется от него, а в конструкторе напишет такой код, что не получит null reference ошибку, а просто в методе Log будет работать с недоинициализированным объектом. При этом могут происходить самые разнообразные веселые и совсем не очень вещи.

VD>Твоих "если" просто не происходит на практике. Что обсуждать гипотетические проблемы?


VD>>>В целом это не только можно делать, но и нужно. Это всего лишь предрассудок который просто нужно преодолеть. Думать о конструктре как о фунции очень полезно. Это дает более горманичную картину преложения. Просто можно думать о конструктре как о частном случае метода.

Кэр>>То же самое, что и я говорил, просто другими словами. Конструктор и метод различаются — причины изложены выше.

VD>Что тоже самое? Ты говорил, что плохо думать о конструктре как о фунции, а значит плохо когда они синтаксически неотличимы.


Кэр>>Да, это интересный пример.


VD>Вот если было бы обязательное new, то было бы тяжело объяснить почему присвоив конструктор переменной его вдруг можно стало вызвать как фукнцию. Кстати, обрати внимание на то, что в этом примере можно было подсунуть вместо конструктора ссылку на статическую фукнцию.


Кэр>>С этим не спорю. Но по изложенным выше причинам — различать их вызовы очень часто все равно нужно


VD>Вот я уже считай год языком пользуюсь и не разу этого не наблюдал. Значит все же это предпрассудок.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[6]: Функциональное программирование в Nemerle
От: VladD2 Российская Империя www.nemerle.org
Дата: 13.06.07 14:27
Оценка:
Здравствуйте, Кэр, Вы писали:

Кэр>Кстати, да, по поводу такого вот примера — они наталкивают на похожий код, когда вначале идет "санитизация" входных параметров


Откровенно говоря не знаю что означает слово "санитизация". Если под этим термином понимается проверка параметров на граничные условия с генерацией исключений, то или как показал ie или с помощью макроса assert(), который генерирует специфичное условие.

В прочем и when тут подойдет, так как исключение по любому прерывает метод и думать о ветвлении не нужно. Но вариат ie конечно же оптимальный. Только чтбы он работал нужно октрыть (using) пространство имен Nemerle.Assertions.

VD>>Со мной была та же фигня. Через неделю практики от этого не остается и следа. А через месяц ты начинаешь задваться вопросом "Зачем я всю жизнь тыкал return-ы там где они на фиг не упали?".


Кэр>Вполне возможно


100%! И это не только мои наблюдения. Например, IT, тоже в начале тыкался в return-ы, а потом признался, что когда пишет на Шарпе начал ловить себя на мысли, что недоволен тем, что приходится без особой нужды тыкать ретурны.

Просто в мозгу в какой-то момент происходит счелчек и ты переключаешся на мышление в терминах выражений. После этого нетурны тебе становятся нужны исключительно тогда, когда алгоритм проще записать императивно. Например, когда нужно выйти из foreach. Да и происходит не часто.

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


return нельзя. Точнее для этого нужно использовать специальный синтаксис с блоком кода. А типы задавать можно. При этом получается полное уродство, так как даже простешие лямбды начинают вылетать за пределы строки. В общем, разработчики Шарпа тоже не идиоты и вводят вывод типов не по велению моды. Это насущьная необходимость для того чтобы писать в фунциональном стиле.

Кэр>Я имел ввиду следующее — на уровню абстракций при вызове другой функции мы увеличиваем стэк вызова.


Что это за абстракция такая если инам нужно думать о каких-то там деталях релизации компилятора?

Кэр> Грубо говоря — делаем типичный шаг в некотором цикле. Так вот — при программировании цикла большинтсво проблем обычно пожинаются при задании условий входа в цикл и выхода из цикла. Поэтому к ним нужно обращать максимальное внимание. Собственно за этим и я предлагал оставить return — как отметку, что здесь мы начинаем раскручивать стэк вызова обратно — в этом месте мы по сути начинаем выходить из "цикла", это нужно заметить, нужно посмотреть какие условия выхода и пр.


На самом деле лучше всего в таких случаях пользоваться рекурсией. Она же в Немерле бесплатная. Тогда у тебя как бы происходит переворот в сознании. Условия перестают "размещаться" в конце и начале цила. Вместо этого они становятся основной идеей алгоритма. А ветвление управления производится с помощью рекурсивного вызова. Вот, напирмер, код парсинга $-строки где выделяются "..$xxx", "..$(...)", "$xxx", "$(...)", ведущие пробельные символы, концы строк и просто текст. Вместо того, чтобы создавать сложный и непонятный ДКА на циклах и свитчах, я просто воспользовался рекурсивными вызовами

def loop (res : list[StrPart]) : list[StrPart]
{
  nestLevel++; Diagnostics.Trace.Assert(nestLevel < 200); // Prevent stack owerflow
  
  // Завершает акомуляцию сиволов литерала и создает соотвествующую 
  // лексему добавляя ее к началу списка лексем
  def endLiteral()
  {
    if (strBuilder.Length == 0)
      res
    else
    {
      def str = strBuilder.ToString();
      strBuilder.Length = 0;
      StrPart.Lit(str) :: res
    }
  }
  def isNextDollar(n)
  {
    def ch1 = peekN(n);
    if (char.IsWhiteSpace(ch1)) isNextDollar(n + 1)
    else                        ch1 == '$'
  }
  def isElipse() { peek() == '.' && isNextDollar(2) }
  def processNewLine() { loop (StrPart.NewLine() :: endLiteral()) }
  
  match (next())
  {
    | '\0'                     => endLiteral()
    | '$'                      => parceSpliceEx(endLiteral(), index, true)
    | '.'  when isElipse()     => index = str.IndexOf('$', index);
                                  parceSpliceEx(endLiteral(), index, false); // '..$'
    | '\r' when peek() == '\n' => _ = next(); processNewLine()
    | '\n' | '\r'              =>             processNewLine()
    | x                        => _ = strBuilder.Append(x); loop(res)
  }
}

Алгоримт при этом становится совершенно очевидным и практически не требует документирования.

Кэр>Это здорово, что концевые рекурсии распознаются и разворачиваются в цикл. Но ведь это подробности реализации по сути. Мы же говорим о "концептуальном понимании кода"


Ошибаешся. Это как раз подробности спецификции языка. Для ФЯ гарантия оптимизации концевой рекурсии является очень важной. Без этого писать в фунциональном стиле становится опасным для производительности.

Кстати, забавный факт. В самом языке (Немерле) вообще нет циклов! Они все эмулируются макросами. А макросы как раз переписывают циклы в рекурсивные фуцнии. Так что фактически использование рекурсивных фуцний быстрее нежели for, foreach, while и т.п., так как они в лучшем случае будут переписаны в такую же фунцию. Ну, а при генерации MSIL-а компилятор обратно превратит функции с концеовой рекурсией в циклы. И все это прозрачно для программиста. Он может думать, что язык одинаково хорошо поддерживает как фунции с концевой рекурсией, так и все виды циклов. Даже цикл вида:
foreach (i in [1..10])
 ...

будет генерировать быстрый код.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[7]: Функциональное программирование в Nemerle
От: Warturtle  
Дата: 26.06.07 17:38
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Здравствуйте, Кэр, Вы писали:


Кэр>>Кстати, да, по поводу такого вот примера — они наталкивают на похожий код, когда вначале идет "санитизация" входных параметров


VD>Откровенно говоря не знаю что означает слово "санитизация". Если под этим термином понимается проверка параметров на граничные условия с генерацией исключений, то или как показал ie или с помощью макроса assert(), который генерирует специфичное условие.


VD>В прочем и when тут подойдет, так как исключение по любому прерывает метод и думать о ветвлении не нужно. Но вариат ie конечно же оптимальный. Только чтбы он работал нужно октрыть (using) пространство имен Nemerle.Assertions.


VD>>>Со мной была та же фигня. Через неделю практики от этого не остается и следа. А через месяц ты начинаешь задваться вопросом "Зачем я всю жизнь тыкал return-ы там где они на фиг не упали?".


Кэр>>Вполне возможно


VD>100%! И это не только мои наблюдения. Например, IT, тоже в начале тыкался в return-ы, а потом признался, что когда пишет на Шарпе начал ловить себя на мысли, что недоволен тем, что приходится без особой нужды тыкать ретурны.


VD>Просто в мозгу в какой-то момент происходит счелчек и ты переключаешся на мышление в терминах выражений. После этого нетурны тебе становятся нужны исключительно тогда, когда алгоритм проще записать императивно. Например, когда нужно выйти из foreach. Да и происходит не часто.


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


VD>return нельзя. Точнее для этого нужно использовать специальный синтаксис с блоком кода. А типы задавать можно. При этом получается полное уродство, так как даже простешие лямбды начинают вылетать за пределы строки. В общем, разработчики Шарпа тоже не идиоты и вводят вывод типов не по велению моды. Это насущьная необходимость для того чтобы писать в фунциональном стиле.


VD>...


Да — нету в C# "искры Божьего гнева", а в Немерле, бзпсд, есть...
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.