Паттерн-матчинг - отличие от обычных конструкций
От: SmbdRsdn  
Дата: 22.04.08 16:11
Оценка: :)))
Здравствуйте, z00n, Вы писали:

Z>Здравствуйте, Lazy Cjow Rhrr, Вы писали:


LCR>>Ещё в качестве альтернативы предлагаю вот этот микробенчмарк, названный Jon Harrop Challenge Problem .

Z>Отличная мысль. Аналогично, Одерски как-то хвастался перед явистами паттерн-матчингом на таком примере:
Z>
Z>// SCALA!
Z>class Term
Z>case class Num(n: int)           extends Term
Z>case class Var(name: String)     extends Term
Z>case class Mul(l: Term, r: Term) extends Term
Z>case class Add(l: Term, r: Term) extends Term

Z>// Now let's say we want to implement some simplification rules on such terms.
Z>// Two useful simplifications apply the equalities:
Z>// 0 * x  =  0
Z>// 1 * x  =  x

Z>def simplify(term: Term) = term match {
Z>  case Mul(Num(0), x) => Num(0)
Z>  case Mul(Num(1), x) => x
Z>  case _ => term
Z>}
Z>


Z>Ему ответили, что мултиплай — диспатч на яве — это просто

В чем принципиальное отличие от такого кода на Яве?
    public Term simplify(Term term) {
        _Term x = new _Term();
        if (term.equals(new Mul(new Num(0), x))) return new Num(0);
        if (term.equals(new Mul(new Num(1), x))) return x.value;
        return term;
    }


01.05.08 08:35: Ветка выделена из темы Действительно ли ML языки хороши в компиляторописании
Автор: FR
Дата: 13.12.07
— AndrewVK
Re: Паттерн-матчинг - отличие от обычных конструкций
От: Lazy Cjow Rhrr Россия lj://_lcr_
Дата: 23.04.08 09:51
Оценка: 34 (4)
SmbdRsdn,

Z>class Term
Z>case class Num(n: int)           extends Term
Z>case class Var(name: String)     extends Term
Z>case class Mul(l: Term, r: Term) extends Term
Z>case class Add(l: Term, r: Term) extends Term

Z>def simplify(term: Term) = term match {
Z>  case Mul(Num(0), x) => Num(0)
Z>  case Mul(Num(1), x) => x
Z>  case _ => term
Z>}


Z>>Ему ответили, что мултиплай — диспатч на яве — это просто

SR>В чем принципиальное отличие от такого кода на Яве?
SR>    public Term simplify(Term term) {
SR>        _Term x = new _Term();
SR>        if (term.equals(new Mul(new Num(0), x))) return new Num(0);
SR>        if (term.equals(new Mul(new Num(1), x))) return x.value;
SR>        return term;
SR>    }


Отличия колоссальные:
1. Паттерн-матчинг осуществляет разбор одновременно с биндингом, так что в первом случае x получит в качестве значения всё поддерево, чего бы там ни было
2. Паттерн-матчинг не пересоздаёт выражения чтобы выяснить соответствие выражений паттерну
3. Алгоритмы паттерн-матчинга не выясняют структуры подвыражений, если структура стала известна на предыдущих шагах
4. Паттерн-матчинг может содержать вайлдкарды и гварды
5. Паттерн-матчинг может быть исследован на полноту в процессе компиляции

Подробнее можно прочитать хере

Для окончательного прояснения различия я декомпилировал код на Скале, функция simplify в данном случае будет выглядеть так:
public Term simplify(Term term)
{
    Term term1 = term;
    Term term4;
    if(term1 instanceof Mul)
    {
        Mul mul = (Mul)term1;
        Term term2 = mul.l();
        Term term3 = mul.r();
        if(term2 instanceof Num)
        {
            switch(((Num)term2).n())
            {
            default:
                break;

            case 0: // '\0'
                term4 = new Num(0);
                break;

            case 1: // '\001'
                term4 = term3;
                break;
            }
        }
    }
    term4 = term;
    return term4;
}


Стоит чуть-чуть навернуть simplify,
def simplify(term: Term) = term match {
  case Mul(Num(0), x) => Num(0)
  case Mul(Num(1), x) => x
  case Add(Num(0), f) => f
  case Add(f, Num(0)) => f
  case _ => term
}

и чтобы сэмулировать это на Йаве, потребуется небольшой такой напряг (кстати, у jad-а при декомпиляции пупок надорвался):
    public Term simplify(Term term)
    {
        Term term1 = term;
        if(!(term1 instanceof Mul)) goto _L2; else goto _L1
_L1:
        Term term2;
        Term term3;
        Mul mul = (Mul)term1;
        term2 = mul.l();
        term3 = mul.r();
        if(!(term2 instanceof Num)) goto _L4; else goto _L3
_L3:
        ((Num)term2).n();
        Term term6;
        JVM INSTR tableswitch 0 1: default 192
    //                   0 64
    //                   1 75;
           goto _L4 _L5 _L6
_L5:
        term6 = new Num(0);
          goto _L7
_L6:
        term6 = term3;
          goto _L7
_L2:
        if(!(term1 instanceof Add)) goto _L4; else goto _L8
_L8:
        Term term4;
        Term term5;
        Add add = (Add)term1;
        term4 = add.l();
        term5 = add.r();
        if(!(term4 instanceof Num)) goto _L10; else goto _L9
_L9:
        Num num = (Num)term4;
        if(num.n() != 0) goto _L12; else goto _L11
_L11:
        term5;
          goto _L13
_L12:
        if(!(term5 instanceof Num) || ((Num)term5).n() != 0) goto _L4; else goto _L14
_L14:
        Term f = num;
          goto _L15
_L10:
        if(!(term5 instanceof Num) || ((Num)term5).n() != 0) goto _L4; else goto _L16
_L16:
        f = term4;
_L15:
        f;
          goto _L13
_L4:
        term6 = term;
_L7:
        term6;
_L13:
        return;
    }

Можно попробовать перевести на человеческий, это будет каскад вложенных условий, но сейчас времени нет.
quicksort =: (($:@(<#[),(=#[),$:@(>#[)) ({~ ?@#)) ^: (1<#)
Re[2]: Паттерн-матчинг - отличие от обычных конструкций
От: z00n  
Дата: 23.04.08 11:25
Оценка: 87 (8)
Здравствуйте, Lazy Cjow Rhrr, Вы писали:
LCR>Можно попробовать перевести на человеческий, это будет каскад вложенных условий, но сейчас времени нет.

У меня есть самопальный компилятор, который умеет переписывать патернматчинг как каскад вложенных if-else, правда таргетит язык с динамической типизацией(Lua) — что очевидным образом увеличивает количество тестов. Вообще, конечно, свитчи или goto лучше, но в луа goto есть только в байткоде, а мне хотелось сохранить минимальную читаемость. Использован модифицированный алгоритм Sestoft'а, как в MosML, MLKit, Nemerle.

Итак исходный пример переписанный на неком надмножестве луа(похоже на Ocaml), добавил рекурсию:
require'zstd'
local ppp = zstd.ppp

-- Scala:
-- def simplify(term: Term) = term match {
--   case Mul(Num(0), x) => Num(0)
--   case Mul(Num(1), x) => x
--   case Add(Num(0), f) => f
--   case Add(f, Num(0)) => f
--   case _ => term
-- }

local fun simplify
  | {"Mul",{"Num",0},x} -> return {"Num",0}
  | {"Mul",{"Num",1},x} -> return simplify(x)
  | {"Add",{"Num",0},f} -> return simplify(f)
  | {"Add",f,{"Num",0}} -> return simplify(f)
  | term -> return term
end

-- TEST:
ppp(1, simplify({"Mul",{"Num",1},"X"}))                    --> "X"
ppp(2, simplify({"Mul",{"Num",0},"X"}))                    --> {"Num",0}
ppp(3, simplify({"Add",{"Num",0},"F"}))                    --> "F"
ppp(4, simplify({"Add","F",{"Num",0}}))                    --> "F"
ppp(5, simplify({"Mul",{"Num",1}, {"Add",{"Num",0},"F"}})) --> "F"


Вот как выглядит результат компиляции функции simplify на Lua 5.1
local function simplify(_u0)
    if type(_u0) == 'table' then
        if #_u0 == 3 then
            if _u0[1] == "Mul" then
                if type(_u0[2]) == 'table' then
                    if #_u0[2] == 2 then
                        if _u0[2][1] == "Num" then
                            if _u0[2][2] == 0 then return {"Num";0}
                            else
                                if _u0[2][2] == 1 then return simplify(_u0[3])
                                else return _u0
                                end;
                            end;
                        else return _u0
                        end;
                    else return _u0
                    end;
                else return _u0
                end;
            else
                if _u0[1] == "Add" then
                    if type(_u0[2]) == 'table' then
                        if #_u0[2] == 2 then
                            if _u0[2][1] == "Num" then
                                if _u0[2][2] == 0 then return simplify(_u0[3])
                                else
                                    if type(_u0[3]) == 'table' then
                                        if #_u0[3] == 2 then
                                            if _u0[3][1] == "Num" then
                                                if _u0[3][2] == 0 then
                                                    return simplify(_u0[2])
                                                else return _u0
                                                end;
                                            else return _u0
                                            end;
                                        else return _u0
                                        end;
                                    else return _u0
                                    end;
                                end;
                            else
                                if type(_u0[3]) == 'table' then
                                    if #_u0[3] == 2 then
                                        if _u0[3][1] == "Num" then
                                            if _u0[3][2] == 0 then
                                                return simplify(_u0[2])
                                            else return _u0
                                            end;
                                        else return _u0
                                        end;
                                    else return _u0
                                    end;
                                else return _u0
                                end;
                            end;
                        else
                            if type(_u0[3]) == 'table' then
                                if #_u0[3] == 2 then
                                    if _u0[3][1] == "Num" then
                                        if _u0[3][2] == 0 then
                                            return simplify(_u0[2])
                                        else return _u0
                                        end;
                                    else return _u0
                                    end;
                                else return _u0
                                end;
                            else return _u0
                            end;
                        end;
                    else
                        if type(_u0[3]) == 'table' then
                            if #_u0[3] == 2 then
                                if _u0[3][1] == "Num" then
                                    if _u0[3][2] == 0 then
                                        return simplify(_u0[2])
                                    else return _u0
                                    end;
                                else return _u0
                                end;
                            else return _u0
                            end;
                        else return _u0
                        end;
                    end;
                else return _u0
                end;
            end;
        else return _u0
        end;
    else return _u0
    end;
end;


Справка по синтаксису Луа:
-- комментарий
x = {1,2,{11,12}} -- x массив из 3-х элементов, индексы начинаются с 1.
#x == 3 -- # оператор взятия длинны
x[3][2] == 12 -- сабскрипт
Re[2]: Паттерн-матчинг - отличие от обычных конструкций
От: SmbdRsdn  
Дата: 23.04.08 16:56
Оценка:
Здравствуйте, Lazy Cjow Rhrr, Вы писали:


LCR>Отличия колоссальные:

Речь шла про синтаксис, а в этом случае различия малосущественные.
LCR>1. Паттерн-матчинг осуществляет разбор одновременно с биндингом, так что в первом случае x получит в качестве значения всё поддерево, чего бы там ни было
Также и в моем примере.

LCR>2. Паттерн-матчинг не пересоздаёт выражения чтобы выяснить соответствие выражений паттерну

LCR>3. Алгоритмы паттерн-матчинга не выясняют структуры подвыражений, если структура стала известна на предыдущих шагах
Это лишь вопросы (2. и 3.) производительности, соответственно достаточно интеллектуальный компилятор, особенно если ему помочь аннотацией, вполне способен развернуть equals в набор if'ов. В расширении же синтаксиса и тем более в переходе на новый язык нет необходимости.

LCR>4. Паттерн-матчинг может содержать вайлдкарды и гварды

Wildcard есть и в моем примере, это переменная x.
Guard же это вообще насколько я понимаю практически чистый if или оператор ?:.

LCR>5. Паттерн-матчинг может быть исследован на полноту в процессе компиляции

Да, это определенное преимущество.
Но опять же, достаточно интеллектуальный компилятор java может провести подобное исследование.
Что-то в духе:
boolean is(int number) {
  if (number > 0)
    return true;
  if (number <= 0)
    return false;
  // отсутствует ошибка, что "This method must return a result of type boolean."
}

С другой стороны в примере на Scala такой проверки нет использутся case _.

LCR>Для окончательного прояснения различия я декомпилировал код на Скале, функция simplify в данном случае будет выглядеть так:

Я тоже это проделывал, очевидно, что Jad'у не удалось получить правильно работающий код.

LCR>
LCR>public Term simplify(Term term)
LCR>{
LCR>    Term term1 = term;
LCR>    Term term4;
LCR>    if(term1 instanceof Mul)
LCR>    {
LCR>       ...
LCR>    }
LCR>    term4 = term;
LCR>    return term4;
LCR>}
LCR>


LCR>Стоит чуть-чуть навернуть simplify,

LCR>
LCR>def simplify(term: Term) = term match {
LCR>  case Mul(Num(0), x) => Num(0)
LCR>  case Mul(Num(1), x) => x
LCR>  case Add(Num(0), f) => f
LCR>  case Add(f, Num(0)) => f
LCR>  case _ => term
LCR>}
LCR>

LCR>и чтобы сэмулировать это на Йаве, потребуется небольшой такой напряг (кстати, у jad-а при декомпиляции пупок надорвался):
Никакого напряга не потребуется.
public Term simplify(Term term) {
_Term x = new _Term();
if (term.equals(new Mul(new Num(0), x)))
  return new Num(0);
if (term.equals(new Mul(new Num(1), x))
  return x.value;
_Term f = new _Term();
if (term.equals(new Add(new Num(0), f))
  return f.value;
if (term.equals(new Add(f, new Num(0)))
  return f.value;
return term;
}

Правда и пример ничем существенно не отличается от предыдущего.
В исходном сообщении Одерски есть ссылка на гораздо более сложный simplify, тем не менее он тоже вполне успешно воспроизводится.
Re[3]: Паттерн-матчинг - отличие от обычных конструкций
От: Lazy Cjow Rhrr Россия lj://_lcr_
Дата: 24.04.08 08:39
Оценка: 15 (1) +1
SmbdRsdn,

SR>Речь шла про синтаксис, а в этом случае различия малосущественные.

Даже если ограничиться синтаксисом, то ПМ выглядит чище. Плюс отсутствует дополнительный уровень косвенности, который привносит equals.

LCR>>1. Паттерн-матчинг осуществляет разбор одновременно с биндингом, так что в первом случае x получит в качестве значения всё поддерево, чего бы там ни было

SR>Также и в моем примере.
Тогда ты забыл привести определение метода equals. (Сдаётся мне, что он будет иметь побочные эффекты, и потребуется сбрасывать x перед каждым новым if).

LCR>>2. Паттерн-матчинг не пересоздаёт выражения чтобы выяснить соответствие выражений паттерну

LCR>>3. Алгоритмы паттерн-матчинга не выясняют структуры подвыражений, если структура стала известна на предыдущих шагах
SR>Это лишь вопросы (2. и 3.) производительности, соответственно достаточно интеллектуальный компилятор, особенно если ему помочь аннотацией, вполне способен развернуть equals в набор if'ов. В расширении же синтаксиса и тем более в переходе на новый язык нет необходимости.
Игнорирование вопросов производительности приводит к тому, что приходится делать квадратичное количество сравнений вместо линейного. Никакой интеллектуальный компилятор не сможет избежать создания трёх объектов ("new Mul(new Num(0), x)"), ибо они передаются в функцию. Короче, зачем нужны кривые подпорки, если есть прямое средство?

LCR>>4. Паттерн-матчинг может содержать вайлдкарды и гварды

SR>Wildcard есть и в моем примере, это переменная x.
SR>Guard же это вообще насколько я понимаю практически чистый if или оператор ?:.
Добро пожаловать в Turing tarpit.

LCR>>5. Паттерн-матчинг может быть исследован на полноту в процессе компиляции

SR>Да, это определенное преимущество.
SR>Но опять же, достаточно интеллектуальный компилятор java может провести подобное исследование.
SR>Что-то в духе:
SR>
SR>boolean is(int number) {
SR>  if (number > 0)
SR>    return true;
SR>  if (number <= 0)
SR>    return false;
SR>  // отсутствует ошибка, что "This method must return a result of type boolean."
SR>}
SR>

SR>С другой стороны в примере на Scala такой проверки нет, и использутся case _.
Плохие новости номер раз. Сейчас достаточно интеллектуального компилятора Йавы нет и учитывая скорость развития её в ближайшую декаду не предвидится.

Плохие новости номер два. Даже если он вдруг неожиданно появится, есть принципиальные моменты, в которые этот компилятор упрётся. Например, попробуй хотя бы сам доказать, что здесь не нужно сообщение "this method must return bla-bla-bla..."
    if (((int) Math.pow(number, 19)) - number) % 19 == 0)
        return true;

Теорему Райса ещё никто не отменял, и "интеллектуальному компилятору" это тоже не удастся.

Плохие новости номер три. Очевидным решением будет "попробовать проверить эти if-ы, если удастся что-нибудь доказать, то выдать результат". Это решение будет в 99% выдавать "не смог", потому что синтаксис if-ов общий, и компилятор не может делать консервативные предположения, в отличие от паттерн-матчинга, где синтаксис может выбран так, чтобы с одной стороны он был как можно более общий, а с другой, чтобы он оставался разрешимым относительно exhaustiveness checking.

Плохие новости номер четыре. В Scala такая проверка таки есть:
sealed abstract class Term
case class Num(n: int)           extends Term
case class Var(name: String)     extends Term
case class Mul(l: Term, r: Term) extends Term
case class Add(l: Term, r: Term) extends Term

class App extends Application
{
    def simplify(term: Term) = term match {
      case Mul(Num(0), x) => Num(0)
      case Mul(Num(1), x) => x
      case Add(Num(0), f) => f
      case Add(f, Num(0)) => f
//      case _ => term
    }
}

имеем
test2.scala:16: warning: match is not exhaustive!
missing combination            Num
missing combination            Var
        def simplify(term: Term) = term match {
                                   ^
one warning found



LCR>>и чтобы сэмулировать это на Йаве, потребуется небольшой такой напряг (кстати, у jad-а при декомпиляции пупок надорвался):

SR>Никакого напряга не потребуется.
SR>
SR>public Term simplify(Term term) {
SR>_Term x = new _Term();
SR>if (term.equals(new Mul(new Num(0), x)))
SR>  return new Num(0);
SR>if (term.equals(new Mul(new Num(1), x))
SR>  return x.value;
SR>_Term f = new _Term();
SR>if (term.equals(new Add(new Num(0), f))
SR>  return f.value;
SR>if (term.equals(new Add(f, new Num(0)))
SR>  return f.value;
SR>return term;
SR>}
SR>

SR>Правда и пример ничем существенно не отличается от предыдущего.
Сделай мне, чтобы твой код имел тот-же порядок сложности, что и ПМ, а то я тут вижу слишком много лишних действий. Ну примерно так:
    public Term simplify(Term term)
    {
        if(term instanceof Mul)
        {
            Mul term2 = (Mul) term;
            Term term3 = term2.l();
            Term term4 = term2.r();
            if (term3 instanceof Num)
            {
                switch(((Num)term3).n())
                {
                case 0:
                    return new Num(0);
                case 1:
                    return term4;
                default:
                    return term;
                }
            }
        }
        else if (term instanceof Add)
        {
            Add term2 = (Add) term;
            Term term3 = term2.l();
            Term term4 = term2.r();
            if (term3 instanceof Num && ((Num)term3).n() == 0)
                return term4;
            else if (term4 instanceof Num && ((Num)term4).n() == 0)
                return term3;
        }
        return term;
    }

Никаких лишних сравнений подвыражений на instanceof, и, где это выгодно, используется switch.

BTW, если бы я вынужден был бы оставаться в Йаве, то вместо изобретения велосипеда я бы просто взял готовую библиотеку с реализацией какого-нибудь алгоритма ПМ, например Tom.
quicksort =: (($:@(<#[),(=#[),$:@(>#[)) ({~ ?@#)) ^: (1<#)
Re[3]: Паттерн-матчинг - отличие от обычных конструкций
От: Lazy Cjow Rhrr Россия lj://_lcr_
Дата: 24.04.08 08:50
Оценка:
z00n,

Z>У меня есть самопальный компилятор, который умеет переписывать патернматчинг как каскад вложенных if-else, правда таргетит язык с динамической типизацией(Lua) — что очевидным образом увеличивает количество тестов. Вообще, конечно, свитчи или goto лучше, но в луа goto есть только в байткоде, а мне хотелось сохранить минимальную читаемость. Использован модифицированный алгоритм Sestoft'а, как в MosML, MLKit, Nemerle.


Круто!

То есть, как я понял, ты какое-то время писал на голом Луа, потом тебя это достало, и ты решил создать метаязык для Луа, так? Паттерн-матчинг значит там уже есть, а ещё что? ФВП, list comprehensions, continuations?
quicksort =: (($:@(<#[),(=#[),$:@(>#[)) ({~ ?@#)) ^: (1<#)
Re[4]: Паттерн-матчинг - отличие от обычных конструкций
От: SmbdRsdn  
Дата: 24.04.08 10:35
Оценка: -2 :)))
Здравствуйте, Lazy Cjow Rhrr, Вы писали:

LCR>Даже если ограничиться синтаксисом, то ПМ выглядит чище.

Или излишне сокращенно, короче дело вкуса.
LCR>Плюс отсутствует дополнительный уровень косвенности, который привносит equals.
Или присутствует дополнительный уровень явности — программа читается как текст, что является преимуществом.
Название метода даже можно заменить на matches или что-то вроде этого.

LCR>Тогда ты забыл привести определение метода equals. (Сдаётся мне, что он будет иметь побочные эффекты, и потребуется сбрасывать x перед каждым новым if).

Я не забыл, просто для обсуждения возможного синтаксиса PM в Java он не существенен.
А сбрасывать нет необходимости, значение там появится только когда будет совпадение с образцом.

LCR>Игнорирование вопросов производительности приводит к тому, что приходится делать квадратичное количество сравнений вместо линейного. Никакой интеллектуальный компилятор не сможет избежать создания трёх объектов ("new Mul(new Num(0), x)"), ибо они передаются в функцию. Короче, зачем нужны кривые подпорки, если есть прямое средство?

Вопросы производительности не нужно игнорировать, а нужно как и в большинстве случаев при разработке ПО откладывать.
Особого интеллекта компилятору не нужно, в теме уже приводились примеры развертывания PM на блок if'ов.

SR>>Guard же это вообще насколько я понимаю практически чистый if или оператор ?:.

LCR> Добро пожаловать в Turing tarpit.
Гм? Как раз Guard переносится на Java один в один, что тут загадочного или не с ходу понятного?

LCR>Плохие новости номер раз. Сейчас достаточно интеллектуального компилятора Йавы нет и учитывая скорость развития её в ближайшую декаду не предвидится.

Так как синтаксис не меняется, то тут достаточно компиляторы из Java в Java. А отличных парсеров Java предостаточно, пока думаю остановится на ASTParser из eclipse.

LCR>Плохие новости номер два. Даже если он вдруг неожиданно появится, есть принципиальные моменты, в которые этот компилятор упрётся. Например, попробуй хотя бы сам доказать, что здесь не нужно сообщение "this method must return bla-bla-bla..."

LCR>
LCR>    if (((int) Math.pow(number, 19)) - number) % 19 == 0)
LCR>        return true;
LCR>

LCR>Теорему Райса ещё никто не отменял, и "интеллектуальному компилятору" это тоже не удастся.
А зачем Java бежать впереди паровоза? Пусть сначала подобная возможность появится в Scala.

LCR>Плохие новости номер три. Очевидным решением будет "попробовать проверить эти if-ы, если удастся что-нибудь доказать, то выдать результат". Это решение будет в 99% выдавать "не смог", потому что синтаксис if-ов общий, и компилятор не может делать консервативные предположения, в отличие от паттерн-матчинга, где синтаксис может выбран так, чтобы с одной стороны он был как можно более общий, а с другой, чтобы он оставался разрешимым относительно exhaustiveness checking.

В обобщенном применении и нет необходимости. Достаточно если будут обрабатываться методы помеченные определенным атрибутом и if'ы имеющие определенную форму.

LCR>Плохие новости номер четыре. В Scala такая проверка таки есть:

LCR>
LCR>class App extends Application
LCR>{
LCR>    def simplify(term: Term) = term match {
LCR>      case Mul(Num(0), x) => Num(0)
LCR>      case Mul(Num(1), x) => x
LCR>      case Add(Num(0), f) => f
LCR>      case Add(f, Num(0)) => f
LCR>//      case _ => term
LCR>    }
LCR>}
LCR>

LCR>имеем
LCR>
LCR>test2.scala:16: warning: match is not exhaustive!
LCR>missing combination            Num
LCR>missing combination            Var
LCR>        def simplify(term: Term) = term match {
LCR>                                   ^
LCR>one warning found
LCR>

По приведенному-то коду не особенно впечатляюще. Вот если бы не было case_ и образцы были бы посложнее.

SR>>Правда и пример ничем существенно не отличается от предыдущего.

LCR>Сделай мне, чтобы твой код имел тот-же порядок сложности, что и ПМ, а то я тут вижу слишком много лишних действий. Ну примерно так:
Я уже писал, это дело компилятора. Впрочем возможно я займусь подобной оптимизацией в ближайшее время.

LCR>BTW, если бы я вынужден был бы оставаться в Йаве, то вместо изобретения велосипеда я бы просто взял готовую библиотеку с реализацией какого-нибудь алгоритма ПМ, например Tom.

Неужели, думаете, что начиная рассуждать о PM в Java я не был в курсе про Tom?
К тому же PM в Tom мощнее того, что в Scala.
Re[5]: Действительно ли ML языки хороши в компиляторописани
От: SmbdRsdn  
Дата: 24.04.08 10:40
Оценка:
Здравствуйте, SmbdRsdn, Вы писали:

SR>По приведенному-то коду не особенно впечатляюще. Вот если бы не было case_ и образцы были бы посложнее.

case _ и не было, но простоту образцов это не отменяет.
Re[4]: Паттерн-матчинг - отличие от обычных конструкций
От: z00n  
Дата: 24.04.08 12:18
Оценка: 121 (6)
Здравствуйте, Lazy Cjow Rhrr, Вы писали:
LCR>Круто!
Спасибо

LCR>То есть, как я понял, ты какое-то время писал на голом Луа, потом тебя это достало, и ты решил создать метаязык для Луа, так? Паттерн-матчинг значит там уже есть, а ещё что? ФВП, list comprehensions, continuations?


Паттерн матчинг для луа я увидел в metalua, но он был реализован наивно(проверяем все подряд пока не false, goto следующая строка) — захотелось сделать лучше
ФВП — там уже есть, вместо continuations есть coroutines, вместо list comprehensions есть итераторы. Я добавил поддержку списков в стиле ML, что вкупе с паттерн-матчингом позволило мне воровать достаточно нетривиальные программы написанные на Haskell или Ocaml.
-- Сердце Вадлеровского претти-принтера украденное одновременно у Линдига(Quest)
-- и у Daan Leijen (Haskell PPrint)

  -- best : (sb,int,int,Cells) -> sb
  -- @sb - string buffer
  -- @n  - indentation of current line
  -- @k  - current column
  -- Cells : listof {indent, Mode, Doc}  
  local function best(sb, n, k, cells) case cells of
      | []                -> return sb
      | {i,_,Empty}  :: z -> return best(sb,n,k,z)
      | {i,m,{'Cons',x,y}}  :: z -> return best(sb,n,k,{i,m,x}::{i,m,y}::z)
      | {i,m,{'Nest',j,x}}  :: z -> return best(sb,n,k,{i+j,m,x}::z)
      | {i,_,{'Text',s}}    :: z -> return best(emit(sb,s),n,k+#s,z)
      | {i,FLT,{'Break',s}} :: z -> return best(emit(sb,s),n,k+#s,z)
      | {i,BRK,{'Break',_}} :: z -> return best(nl(sb,i),i,i,z)
      | {i,FLT,{'Group',x}} :: z -> return best(sb,w,k,{i,FLT,x}::z)
      | {i,BRK,{'Group',x}} :: z -> 
          local ribbonleft = (w - k) `min` (ribbon - k + n)
          if fits(ribbonleft,k,{i,FLT,x}::z) then
            return best(sb,n,k,{i,FLT,x}::z)
          else
            return best(sb,n,k,{i,BRK,x}::z)
          end
      | {i,m,{'Column',f}}  :: z -> return best(sb,n,k,{i,m,f(k)}::z)
      | {i,m,{'Nesting',f}} :: z -> return best(sb,n,k,{i,m,f(i)}::z)
      | x -> error(tostring(x))
    end
  end
  -- return of layout
  return best(sb,0,0,{0,BRK,doc}::[])


Ну и по мелочи: добавил инфиксные-префиксные операторы в стиле Scala, компактную форму для thunks, etc
-- prefix                        
(?)  = assert                   ---> _prefix_question = assert;
?getImage("some.img")           ---> _prefix_question(getImage"some.img");

-- right assoc
(:-:) = docCons                 ---> _op_colon_dash_colon = docCons;
mydoc = adoc :-: bdoc :-: empty ---> mydoc = _op_colon_dash_colon(adoc
                                --->                             ,_op_colon_dash_colon(bdoc,empty));
-- infixl 5 pseudo-operator
x = (fn(x)=> x+42) `map` xs     ---> x = map((function(x) return x+42 end),xs);

-- Scala's thunk
print(=> 1/0)                   ---> print(function() return 1/0 end);
Re[5]: Действительно ли ML языки хороши в компиляторописани
От: Mamut Швеция http://dmitriid.com
Дата: 24.04.08 12:28
Оценка:
LCR>>Даже если ограничиться синтаксисом, то ПМ выглядит чище.
SR>Или излишне сокращенно, короче дело вкуса.
LCR>>Плюс отсутствует дополнительный уровень косвенности, который привносит equals.
SR>Или присутствует дополнительный уровень явности — программа читается как текст, что является преимуществом.
SR>Название метода даже можно заменить на matches или что-то вроде этого.


Дело далеко не в названии метода, а в его реализации
... << RSDN@Home 1.2.0 alpha 4 rev. 1084>>


dmitriid.comGitHubLinkedIn
Re[6]: Действительно ли ML языки хороши в компиляторописани
От: SmbdRsdn  
Дата: 24.04.08 13:25
Оценка:
Здравствуйте, Mamut, Вы писали:

M>Дело далеко не в названии метода, а в его реализации

А в чем дело с реализацией?
Re[5]: Действительно ли ML языки хороши в компиляторописани
От: Lazy Cjow Rhrr Россия lj://_lcr_
Дата: 24.04.08 13:34
Оценка:
SmbdRsdn,

LCR>>Тогда ты забыл привести определение метода equals. (Сдаётся мне, что он будет иметь побочные эффекты, и потребуется сбрасывать x перед каждым новым if).

SR>Я не забыл, просто для обсуждения возможного синтаксиса PM в Java он не существенен.
SR>А сбрасывать нет необходимости, значение там появится только когда будет совпадение с образцом.
А решать вопрос "сбрасывать или нет" каждый раз должен программист? Нет, спасибо, и так хватает головной боли.

SR>А зачем Java бежать впереди паровоза? Пусть сначала подобная возможность появится в Scala.

При чём здесь Scala, мы же говорили о "достаточно интеллектуальном компиляторе для явы"? Скала и не претендовала на звание "обобщённого упрощателя условных выражений".

SR>В обобщенном применении и нет необходимости. Достаточно если будут обрабатываться методы помеченные определенным атрибутом и if'ы имеющие определенную форму.

А! Вот оно. Всё понятно, это препроцессор для явы. Специально помеченные if-ы (которые, заметим, работают совсем не так как выглядят!) будут прогоняться через препроцессор, а последний будет выплёвывать уже явовский код, который потом будет компилироваться с помощью javac. Плохо.

SR>По приведенному-то коду не особенно впечатляюще. Вот если бы не было case_ и образцы были бы посложнее.

Если проверка на полноту реализована (а это так), то она будет работать и с простым кодом, и со сложным, и с одноэтажным, и с многоэтажным, и с невпечатляющим, и с впечатляющим. С любым, если код синтаксически корректен. Просто по определению... Создай сам код для ПМ, впечатляющий тебя, и впечатлись

LCR>>BTW, если бы я вынужден был бы оставаться в Йаве, то вместо изобретения велосипеда я бы просто взял готовую библиотеку с реализацией какого-нибудь алгоритма ПМ, например Tom.

SR>Неужели, думаете, что начиная рассуждать о PM в Java я не был в курсе про Tom?
SR>К тому же PM в Tom мощнее того, что в Scala.
(Кста, на этом форуме всё же приятнее обращаться на "ты"). Если ты в курсе про Tom, тогда в курсе, что он тоже неидеален, и по сравнению со Скалой проигрывает по многим параметрам. Возможно в отношении ПМ он и мощнее (хотя мне это неочевидно, так как в Скале есть unapply, который открывает очень богатые возможности которых, кажется, хватит за глаза любому приложению), но в отношении остальных вещей остановился на уровне обычной явы.
И я так и не понял, в чём преимущества твоего решения (которого кстати я по-прежнему не увидел, даже наброска, а имею возможность лишь косвенно догадываться по кусочкам кода и брошенным фразам)? Ы?
quicksort =: (($:@(<#[),(=#[),$:@(>#[)) ({~ ?@#)) ^: (1<#)
Re[7]: Действительно ли ML языки хороши в компиляторописани
От: Mamut Швеция http://dmitriid.com
Дата: 24.04.08 13:45
Оценка:
M>>Дело далеко не в названии метода, а в его реализации
SR>А в чем дело с реализацией?

Возьму из своего же примера

У нас есть правила для валидации полей:

Проверить, существует ли такое поле

{field_name}


Сравнить поле field_name с полем field2_name (также можно использовать '=', '/=', '<', '=<', '>', '>=' )
{field_name, {'=', field2_name}}


Сравнить значение поля с любым другим значением:
{field_name, {'=', Value}}


Использовать callback-функцию. Функция может быть лямбдой или любой функцией из любого модуля в виде module:function/2 или {module, function}
{field_name, F}


Использовать callback-функцию с дополнительным значением. Функция может быть лямбдой или любой функцией из любого модуля в виде module:function/3 или {module, function}
{field_name, {F, Value}}



Ну и как написать term.equals на каждое из правил? Я предположил, что для этого каждое правило придется представлять в виде класса, отнаследованного от некоторого абстрактного Rules. С паттерн-матчингом это тривиально:
%%{field}
validate_rule({FieldName}) ->
    ok.

%%{field, Func}
validate_rule({FieldName, Func}) when is_function(Func) ->
    ok.

%%{field, {'=', field2}}
validate_rule({FieldName, {Operator, FieldName2}}) ->
    ok.


и так далее.

При этом при отсутствии ПМ на каждый сулчай, когда придется что-то матчить, придется писать новые классы с новым equals. В случае с ПМ можно сразу обработать структуру практически любой сложности.
... << RSDN@Home 1.2.0 alpha 4 rev. 1084>>


dmitriid.comGitHubLinkedIn
Re[8]: Действительно ли ML языки хороши в компиляторописани
От: SmbdRsdn  
Дата: 24.04.08 14:49
Оценка:
Здравствуйте, Mamut, Вы писали:

M>>>Дело далеко не в названии метода, а в его реализации

SR>>А в чем дело с реализацией?

M>Возьму из своего же примера

Пример слабопонятен. Вернее решение для него.
Что не так, например, в таком решении, если надо всего лишь проверить ввод?
    boolean validate(String login, String password, String password_repeat, String email) {
        return 
          ((login.length() >= 4 && login.length() <= 16)) &&
          ((password.length() >= 4 && password.length() <= 16)) &&
          ((password.equals(password_repeat))) &&
          ((email.matches("\\w+@\\w+\\.\\w+")));        
    }

Вероятно, что-то пропущено в формулировке.
Re[9]: Действительно ли ML языки хороши в компиляторописани
От: Mamut Швеция http://dmitriid.com
Дата: 24.04.08 15:27
Оценка:
примера
SR>Пример слабопонятен. Вернее решение для него.
SR>Что не так, например, в таком решении, если надо всего лишь проверить ввод?
SR>
SR>    boolean validate(String login, String password, String password_repeat, String email) {
SR>        return 
SR>          ((login.length() >= 4 && login.length() <= 16)) &&
SR>          ((password.length() >= 4 && password.length() <= 16)) &&
SR>          ((password.equals(password_repeat))) &&
SR>          ((email.matches("\\w+@\\w+\\.\\w+")));        
SR>    }
SR>

SR>Вероятно, что-то пропущено в формулировке.

Приведенный вариант просто вернет true или false. Мой вариант вернет список не прошедших валидацию полей и всех ошибок, которые с ними связаны (правила валидации могут передаваться списком).

Более того, проверка полей может отдаваться на растерзание внешним функциям.

А что, если полей станет больше? Как написать общую функцию, которая:
— примет неограниченый список полей;
— для кажого поля можно передать от 0 до бесконечного количества правил;
— каждое правило позволяет отдать проверку внешней функции или устроить сравнение с переданым значением или другим полем;
— возвращает осмысленный список полей, не пршедших валидацию, со списком ошибок для каждого поля?

process_signup(A) ->
    ValidateLength = fun(A, Field) ->
        %% проверяем на длину
    end,
    EmailCheck = fun(Args, Field2) ->
        %% проверяем правильность мыла
    end,

    buktu_form:validate(A, [
        {login, F},              %% проверяем с использованием внешней функции
        {email, EmailCheck},     %% проверяем с использованием внешней функции
        {password, [{'=', password_repeat}, F]} %% проверяем на равенство с другим полем
                                                %% а потом - с использованием внешней функции
    ]).


Если поля не будут введены:
[{login,invalid_field},
 {email,invalid_field},
 {password,[{invalid_fields,[password,password_repeat]},
            invalid_field]}]


Если неправильные значения:
[{login,length},
 {email,invalid_value},
 {password,[{not_equal,password_repeat},
            length]}]



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

Расширим пример. У нас появится пункт о лицензионном соглашении, еще несколько checkbox'ов, которые необходимо отметить, а также год рождени, который должен быть раньше 1980-го года:

validate([
    {registration},
    {checkbox1},
    {checkbox2},
    {year, {'<', 1980}}
    {login, F},              %% внешние функции остаются те же
    {email, EmailCheck},     
    {password, [{'=', password_repeat}, F]} 
])


Причем полученый список ошибок разбрать не просто легко, а очнь легко ПМ по [H|T] по списку и вперед


А функцию можно спокойно дописать для подержки более сложных правил. Например:
%% {field, {Rule, and, Rule2}}
%% оба правила должны сработать

validate(FieldName, {Rule1, and, Rule2}) ->
        %% разбиваем на валидацию двух правил
    validate({FieldName, Rule}) == {} andalso validate({FieldName, Rule2}) == {}

%% {field, {Rule, or, Rule2}}
%% одно из правил должно сработать

validate(FieldName, {Rule1, or, Rule2}) ->
        %% разбиваем на валидацию двух правил
    validate({FieldName, Rule}) == {} orelse validate({FieldName, Rule2}) == {}


При этом функция остается общей и может использоваться для любых полей любой веб-формы. Без ПМа здесь только один выход — создание некоего движка правил. Но это — совсем неудобно
... << RSDN@Home 1.2.0 alpha 4 rev. 1084>>


dmitriid.comGitHubLinkedIn
Re[10]: Действительно ли ML языки хороши в компиляторописани
От: Курилка Россия http://kirya.narod.ru/
Дата: 24.04.08 15:31
Оценка: :)
Здравствуйте, Mamut, Вы писали:

[cut]

M>При этом функция остается общей и может использоваться для любых полей любой веб-формы. Без ПМа здесь только один выход — создание некоего движка правил. Но это — совсем неудобно


Да нет, Дим, про "совсем" ты тут зря, некоторые ёжики продолжают колоться и лезть на кактус. Ну нравится им это и ничего ты с этим не сделаешь...
Re[6]: Действительно ли ML языки хороши в компиляторописани
От: SmbdRsdn  
Дата: 24.04.08 15:32
Оценка: :))
Здравствуйте, Lazy Cjow Rhrr, Вы писали:

LCR>SmbdRsdn,


LCR>А решать вопрос "сбрасывать или нет" каждый раз должен программист?

Нет. Сбрасывать не зачем.

LCR>При чём здесь Scala,

Я написал свой ответ на сравнение сопоставления с образцом в Scala и в Java.

LCR>мы же говорили о "достаточно интеллектуальном компиляторе для явы"?

Но и не об обобщенно-интеллектуальном на все случаи жизни.

Я, конечно, понимаю, отчего возникло непонимание.
Мне было лень писать что-то вроде:

abstract class Term {};
class Num extends Term {};
class Var extends Term {}

@Exhaustive
Term simplify(Term term) {
  if (term instanceof Num)
     return ...;
  if (term instanceof Var)
     return ...;
  // отсутствует "This method must return a result of type Term."
}


для показа как может выглядеть проверка на полноту при сопоставлении с образцом в Java.

LCR>А! Вот оно. Всё понятно, это препроцессор для явы.

Термин препроцессор перегружен не в том направлении.

LCR>Специально помеченные if-ы

Не отдельные if, а отдельный метод. Помеченный аннотацией. Что является законным способом добавления мета-данных в Java.

LCR>(которые, заметим, работают совсем не так как выглядят!)

Работают так же как и выглядят. То есть делают тоже, что и написано. Просто быстрее.
К тому же в Java сообществе имеется много материалов, о том как написать свой equals и для каких целей это может потребоваться.
То есть код вида
if (object.equals(new Object(...))

достаточно широко распространен.

LCR>будут прогоняться через препроцессор, а последний будет выплёвывать уже явовский код, который потом будет компилироваться с помощью javac. Плохо.

зачем прогоняться? В ASTParser можно на лету заменять отдельные ветки на другие. Короче, в чем-то аналог R#.

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

Вот именно. Я это знаю, поэтому меня и удивило, что демонстрация проверки полноты производилась на сравнительно простом примере.

LCR>(Кста, на этом форуме всё же приятнее обращаться на "ты").

Я знаю, но предпочитаю обращаться на Вы. Впрочем не требую того же в ответ.

LCR>И я так и не понял, в чём преимущества твоего решения (которого кстати я по-прежнему не увидел, даже наброска, а имею возможность лишь косвенно догадываться по кусочкам кода и брошенным фразам)? Ы?

Готового производительного решения и нет. А преимущества в отсутствии необходимости перехода на другой язык с сильно измененным синтаксисом только для возможности сопоставления с образцом.
Re[10]: Действительно ли ML языки хороши в компиляторописани
От: SmbdRsdn  
Дата: 24.04.08 17:13
Оценка: :))
Здравствуйте, Mamut, Вы писали:

M>Приведенный вариант просто вернет true или false. Мой вариант вернет список не прошедших валидацию полей и всех ошибок, которые с ними связаны (правила валидации могут передаваться списком).

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

M>Более того, проверка полей может отдаваться на растерзание внешним функциям.

Неужели думаете что в Java нельзя сообщить функции, что определенное действие она может проделать при помощи некоторой внешней функции, неизвестной на момент разработки?

M>А что, если полей станет больше? Как написать общую функцию, которая:

M>- примет неограниченый список полей;
Думаете в Java функция не может принять неограниченный список параметров?
M>- для кажого поля можно передать от 0 до бесконечного количества правил;
Думаете в Java не поддерживаются массивы с переменной длиной, от 0 до ...?
M>- каждое правило позволяет отдать проверку внешней функции или устроить сравнение с переданым значением или другим полем;
Неужели думаете что в Java нельзя сообщить функции, что определенное действие она может проделать при помощи некоторой внешней функции, неизвестной на момент разработки?
M>- возвращает осмысленный список полей, не пршедших валидацию, со списком ошибок для каждого поля?

M>При этом функция — достаточно общая, позволяет передавать 5 видов различных правил, причем по нескольку штук на поле.


M>Расширим пример. У нас появится пункт о лицензионном соглашении, еще несколько checkbox'ов, которые необходимо отметить, а также год рождени, который должен быть раньше 1980-го года:


M>Причем полученый список ошибок разбрать не просто легко, а очнь легко ПМ по [H|T] по списку и вперед

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

M>А функцию можно спокойно дописать для подержки более сложных правил. Например:

Неужели сомневаетесь, что на Java можно дописывать функции?

M>При этом функция остается общей и может использоваться для любых полей любой веб-формы. Без ПМа здесь только один выход — создание некоего движка правил. Но это — совсем неудобно

А у вас стало быть не движок правил?

    public void main() {
        Form form = new Form();
        form.put("login", "name");
        form.put("password", "123");
        form.put("password_repeated", "123");
        form.put("email", "name@domain.com");
        form.put("born_year", "1980");
        
        Object[] rules = new Object[] {
            "login", "length", parameters(4, 16),
            "password", "length", parameters(4, 16),
            "password", "=", parameters("password_repeated"),
            "email", "email", parameters(),
            "born_year", "<", parameters("1990")
        };
        
        check(form, rules);
    }

    // О боже мой, кажется, я реализовал сопоставление с образцом для списка в Java!
    // Этого не может быть, наверное я сплю.
    private void check(Form form, Object[] rules) {
        for (int index = 0; index < rules.length; index += 3) {
            String field = rules[index].toString();
            String rule = rules[index+1].toString();
            Object[] parameters = (Object[])rules[index+2];
        
            check(form, field, rule, parameters);
        }
    }

    private void check(Form form, String field, String rule, Object[] parameters) {
        if (rule.equals("length")) { 
            int min = (Integer)parameters[0]; 
            int max = (Integer)parameters[1];
            checkLength(form.get(field), min, max);
        }
        ...
        // остальной код в той же мере тривиален
    }
Re[5]: Действительно ли ML языки хороши в компиляторописани
От: Lazy Cjow Rhrr Россия lj://_lcr_
Дата: 25.04.08 05:16
Оценка:
z00n,

Z>Паттерн матчинг для луа я увидел в metalua, но он был реализован наивно(проверяем все подряд пока не false, goto следующая строка) — захотелось сделать лучше

Z>ФВП — там уже есть, вместо continuations есть coroutines, вместо list comprehensions есть итераторы. Я добавил поддержку списков в стиле ML, что вкупе с паттерн-матчингом позволило мне воровать достаточно нетривиальные программы написанные на Haskell или Ocaml.

Спасибо за информацию, интересно. Как говорят в определённых кругах, "автор, пиши ещё"
quicksort =: (($:@(<#[),(=#[),$:@(>#[)) ({~ ?@#)) ^: (1<#)
Re[3]: Паттерн-матчинг - отличие от обычных конструкций
От: GlebZ Россия  
Дата: 25.04.08 06:50
Оценка:
Здравствуйте, z00n, Вы писали:

Z>У меня есть самопальный компилятор, который умеет переписывать патернматчинг как каскад вложенных if-else, правда таргетит язык с динамической типизацией(Lua) — что очевидным образом увеличивает количество тестов. Вообще, конечно, свитчи или goto лучше, но в луа goto есть только в байткоде, а мне хотелось сохранить минимальную читаемость. Использован модифицированный алгоритм Sestoft'а, как в MosML, MLKit, Nemerle.

Sestoft — это вот этот?
... << RSDN@Home 1.2.0 alpha rev. 789>>
Re[11]: Действительно ли ML языки хороши в компиляторописани
От: Mamut Швеция http://dmitriid.com
Дата: 25.04.08 07:05
Оценка:
M>>Приведенный вариант просто вернет true или false. Мой вариант вернет список не прошедших валидацию полей и всех ошибок, которые с ними связаны (правила валидации могут передаваться списком).
SR>А, ну надо было тогда в условие задачи, добавить, что правила проверки должны задаваться более-менее декларативно.


Ну, во многом в этом и состоит смысл ПМа — описывать ребуемое декларативно



M>>При этом функция остается общей и может использоваться для любых полей любой веб-формы. Без ПМа здесь только один выход — создание некоего движка правил. Но это — совсем неудобно

SR>А у вас стало быть не движок правил?

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


SR>
SR>    public void main() {
SR>        Form form = new Form();
SR>        form.put("login", "name");
SR>        form.put("password", "123");
SR>        form.put("password_repeated", "123");
SR>        form.put("email", "name@domain.com");
SR>        form.put("born_year", "1980");
        
SR>        Object[] rules = new Object[] {
SR>            "login", "length", parameters(4, 16),
SR>            "password", "length", parameters(4, 16),
SR>            "password", "=", parameters("password_repeated"),
SR>            "email", "email", parameters(),
SR>            "born_year", "<", parameters("1990")
SR>        };
        
SR>        check(form, rules);
SR>    }

SR>    // О боже мой, кажется, я реализовал сопоставление с образцом для списка в Java!
SR>    // Этого не может быть, наверное я сплю.
SR>    private void check(Form form, Object[] rules) {
SR>        for (int index = 0; index < rules.length; index += 3) {
SR>            String field = rules[index].toString();
SR>            String rule = rules[index+1].toString();
SR>            Object[] parameters = (Object[])rules[index+2];
        
SR>            check(form, field, rule, parameters);
SR>        }
SR>    }

SR>    private void check(Form form, String field, String rule, Object[] parameters) {
SR>        if (rule.equals("length")) { 
SR>            int min = (Integer)parameters[0]; 
SR>            int max = (Integer)parameters[1];
SR>            checkLength(form.get(field), min, max);
SR>        }
SR>        ...
SR>        // остальной код в той же мере тривиален
SR>    }
SR>



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

То есть. Для исхдного примера
Автор: z00n
Дата: 14.12.07
придется реализовывать метод equals для term, для моего примера — целую отдельную функцию, эмулирующую сопоставление с образом, для менее тривиального примера
Автор: z00n
Дата: 24.04.08
придется еще как-нибудь изворачиваться. А ПМ позвлит все задачи решить декларативно. Это не магическая пуля, конечно, писать все равно придется Но каждый раз это будет легко и — главное! — одинаково.

Просто if поможет только сравнить значения. ПМ позволит наглядно сравнить и структуру и значения.
... << RSDN@Home 1.2.0 alpha 4 rev. 1084>>


dmitriid.comGitHubLinkedIn
Re[12]: Действительно ли ML языки хороши в компиляторописани
От: SmbdRsdn  
Дата: 25.04.08 10:21
Оценка:
Здравствуйте, Mamut, Вы писали:

M>Правильно. И такой код придется писать каждый раз заново для любой более-менее тривиальной смены структуры передаваемых данных.

Какой такой? Цикл по списку? Так это аналог рекурсии по списку, которую тоже придется писать каждый раз.

M>То есть. Для исхдного примера
Автор: z00n
Дата: 14.12.07
придется реализовывать метод equals для term,

Метод equals легко автоматизируется, также как создание getter, setter и конструктора по полям в eclipse.
Я уж молчу про поддержку со стороны компилятора.

M>для моего примера — целую отдельную функцию, эмулирующую сопоставление с образом,

Странно, стороннику ФП не нравятся отдельные функции. Ну раз не нравятся объедините в одну большую.

M>для менее тривиального примера
Автор: z00n
Дата: 24.04.08
придется еще как-нибудь изворачиваться.

Пример не более тривиален чем исходный.

M>А ПМ позвлит все задачи решить декларативно. Это не магическая пуля, конечно, писать все равно придется Но каждый раз это будет легко и — главное! — одинаково.

Так все задачи или не магическая пуля?

M>Просто if поможет только сравнить значения. ПМ позволит наглядно сравнить и структуру и значения.

Какая структура в вашем-то примере?
Re[13]: Действительно ли ML языки хороши в компиляторописани
От: Mamut Швеция http://dmitriid.com
Дата: 25.04.08 10:47
Оценка:
M>>Правильно. И такой код придется писать каждый раз заново для любой более-менее тривиальной смены структуры передаваемых данных.
SR>Какой такой? Цикл по списку? Так это аналог рекурсии по списку, которую тоже придется писать каждый раз.

При этом с ПМ рекрсия по списку тривиальна


M>>То есть. Для исхдного примера
Автор: z00n
Дата: 14.12.07
придется реализовывать метод equals для term,

SR>Метод equals легко автоматизируется, также как создание getter, setter и конструктора по полям в eclipse.

{ok, {{Version, 200, ReasonPhrase}, Headers, Body}} =
      http:request(...
      
{ok, {_, _, Body}} = http:request(...


{ok, {_, 200, _}, _, _} = http:request(


Какой-какой автоматизированый equals мне поможет это написать?


SR>Я уж молчу про поддержку со стороны компилятора.


Я тоже умолчу

M>>для моего примера — целую отдельную функцию, эмулирующую сопоставление с образом,

SR>Странно, стороннику ФП не нравятся отдельные функции. Ну раз не нравятся объедините в одну большую.

В какую ону большую? В Tom что ли?

M>>для менее тривиального примера
Автор: z00n
Дата: 24.04.08
придется еще как-нибудь изворачиваться.

SR>Пример не более тривиален чем исходный.

     | {i,FLT,{'Break',s}} :: z -> return best(emit(sb,s),n,k+#s,z)
     | {i,BRK,{'Break',_}} :: z -> return best(nl(sb,i),i,i,z)
     | {i,FLT,{'Group',x}} :: z -> return best(sb,w,k,{i,FLT,x}::z)


это, я так понимаю, предлагается переписать в виде
if(term.m == FLT && term.cell.type == 'Break' && term.cell.data == s)
{
}
else if(term.m == BRK && term.cell.type == 'Break')
{
}
else if(term.m == FLT && term.cell.type == 'Group' && term.cell.data == x)
{
}


?

M>>А ПМ позвлит все задачи решить декларативно. Это не магическая пуля, конечно, писать все равно придется Но каждый раз это будет легко и — главное! — одинаково.

SR>Так все задачи или не магическая пуля?

Любая, где требуется разбор структур (данных). Сопоставление с образцом — это унифицированый подход к разбору произвольных структур(данных)


M>>Просто if поможет только сравнить значения. ПМ позволит наглядно сравнить и структуру и значения.

SR>Какая структура в вашем-то примере?

rules_list         = [fields_and_rules]
fields_and_rules   = [field_rules]
field_rules        = {field} | {field, Rules}
Rules              = Rule | [Rule]
Rule               = function | OperatorRule | FunctionRule
OperatorRule       = {Operator, value} | (Operator, field)
Operator           = '=' | '/=' | '<' | '=<' | '>' | '>='
FunctionRule       = {function, value} | {function, field}


Как придумал, так и записал. Более того, реализация сильно похожа на то же самое

Но у меня, безусловно, простой пример. А есть посложнее. Типа того, что я привел в самом начале.
... << RSDN@Home 1.2.0 alpha 4 rev. 1084>>


dmitriid.comGitHubLinkedIn
Re[4]: Паттерн-матчинг - отличие от обычных конструкций
От: z00n  
Дата: 25.04.08 10:50
Оценка:
Здравствуйте, GlebZ, Вы писали:
GZ>Sestoft — это вот этот?
Да, это он.
Re[14]: Действительно ли ML языки хороши в компиляторописани
От: SmbdRsdn  
Дата: 25.04.08 11:32
Оценка:
Здравствуйте, Mamut, Вы писали:

M>При этом с ПМ рекрсия по списку тривиальна

Неужели считаете, что цикл нетривиален?

M>
M>{ok, {{Version, 200, ReasonPhrase}, Headers, Body}} =
M>      http:request(...
      
M>{ok, {_, _, Body}} = http:request(...


M>{ok, {_, 200, _}, _, _} = http:request(
M>


M>Какой-какой автоматизированый equals мне поможет это написать?

Как-то определили, что мне знаком erlang?

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

SR>>Странно, стороннику ФП не нравятся отдельные функции. Ну раз не нравятся объедините в одну большую.


M>В какую ону большую? В Tom что ли?

Гм, по вашему одна большая функция не разбитая на малые превращается сразу в язык программирования Tom. Интересная способ рассуждений.

SR>>Пример не более тривиален чем исходный.


M>
M>     | {i,FLT,{'Break',s}} :: z -> return best(emit(sb,s),n,k+#s,z)
M>     | {i,BRK,{'Break',_}} :: z -> return best(nl(sb,i),i,i,z)
M>     | {i,FLT,{'Group',x}} :: z -> return best(sb,w,k,{i,FLT,x}::z)
M>


M>это, я так понимаю, предлагается переписать в виде

M>
M>if(term.m == FLT && term.cell.type == 'Break' && term.cell.data == s)
M>{
M>}
M>else if(term.m == BRK && term.cell.type == 'Break')
M>{
M>}
M>else if(term.m == FLT && term.cell.type == 'Group' && term.cell.data == x)
M>{
M>}
M>


M>?

Нет. Вспомните, я и код такого вида не приводил.

M>Любая, где требуется разбор структур (данных). Сопоставление с образцом — это унифицированый подход к разбору произвольных структур(данных)

Это вы хватили, насчет произвольных структур. Вот например разработчики Tom'а заявляли, что в Tom возможно сопоставлять с образцом более сложные структуры чем в Scala, но все равно не произвольные.

M>>>Просто if поможет только сравнить значения. ПМ позволит наглядно сравнить и структуру и значения.

SR>>Какая структура в вашем-то примере?

M>
M>rules_list         = [fields_and_rules]
M>fields_and_rules   = [field_rules]
M>field_rules        = {field} | {field, Rules}
M>Rules              = Rule | [Rule]
M>Rule               = function | OperatorRule | FunctionRule
M>OperatorRule       = {Operator, value} | (Operator, field)
M>Operator           = '=' | '/=' | '<' | '=<' | '>' | '>='
M>FunctionRule       = {function, value} | {function, field}
M>


M>Как придумал, так и записал.


M>Более того, реализация сильно похожа на то же самое

В реализации многовато дублирования образцов. Практически каждый по два раза.

M>Но у меня, безусловно, простой пример. А есть посложнее. Типа того, что я привел в самом начале.

Про посложнее это понятно. Однако считается, что преимущество сопоставления с образцом видно уже на простых иерархиях.
А у вас странно звучит — да на простой иерархии особой разницы не видно, но если ее навернуть на порядок, тогда преимущество будет очевидно.
Re[15]: Действительно ли ML языки хороши в компиляторописани
От: Mamut Швеция http://dmitriid.com
Дата: 25.04.08 12:05
Оценка:
M>>При этом с ПМ рекрсия по списку тривиальна
SR>Неужели считаете, что цикл нетривиален?

Он менее "читаем", чем ПМ

M>>
M>>{ok, {{Version, 200, ReasonPhrase}, Headers, Body}} =
M>>      http:request(...
      
M>>{ok, {_, _, Body}} = http:request(...


M>>{ok, {_, 200, _}, _, _} = http:request(
M>>


M>>Какой-какой автоматизированый equals мне поможет это написать?

SR>Как-то определили, что мне знаком erlang?

Ну, мы ж про паттерн-матчинг говорим? А тут вполне себе паттерн-матчинг. Вполне понятный даже незнакомому с Эрлангом

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

SR>Как повелось сторонниками ФП демонстрировать преимущества сопоставления с образцом на основе структур для условного калькулятора так предлагаю и продолжать.
SR>Нет, если конечно считаете, что у вас какая-то принципиально иная структура, которая в калькулятор не укладывается.

Ну, в исходном
Автор: z00n
Дата: 14.12.07
сообщении был приведен и пример кода их компилятора

Вообще-то на одном только изолированом примере показать/доказать что-то сложно.
Надо привести два-три примера, где ПМ позволяет использовать одинаковый подход к решению проблемы, а язык без ПМа требует каждый раз нового подхода (здесь
Автор: SmbdRsdn
Дата: 22.04.08
— реализация метода equals, здесь
Автор: SmbdRsdn
Дата: 24.04.08
— функции с применением if-ов). А ПМ в итоге позволяет читать код, как книгу, без необходимости пробираться сквозь дебри if-ов и попыток понять, что же автор хотел сказать тем или иным циклом

SR>>>Странно, стороннику ФП не нравятся отдельные функции. Ну раз не нравятся объедините в одну большую.


M>>В какую ону большую? В Tom что ли?

SR>Гм, по вашему одна большая функция не разбитая на малые превращается сразу в язык программирования Tom. Интересная способ рассуждений.

Или в нечто ему подобное. Потому что мы же хотим некую общую функцию, которая поможет разбирать образцы не только на одном примере разбора веб-форм


SR>>>Пример не более тривиален чем исходный.


M>>
M>>     | {i,FLT,{'Break',s}} :: z -> return best(emit(sb,s),n,k+#s,z)
M>>     | {i,BRK,{'Break',_}} :: z -> return best(nl(sb,i),i,i,z)
M>>     | {i,FLT,{'Group',x}} :: z -> return best(sb,w,k,{i,FLT,x}::z)
M>>


M>>это, я так понимаю, предлагается переписать в виде

M>>
M>>if(term.m == FLT && term.cell.type == 'Break' && term.cell.data == s)
M>>{
M>>}
M>>else if(term.m == BRK && term.cell.type == 'Break')
M>>{
M>>}
M>>else if(term.m == FLT && term.cell.type == 'Group' && term.cell.data == x)
M>>{
M>>}
M>>


M>>?

SR>Нет. Вспомните, я и код такого вида не приводил.

Ну, для калькулятора был код с term.equals, для проверки веб-=форм был код с if'ами. Для этого конкретного примера term.equals не подойдет, потому что нам не всегда все значения нужны. Так что if-ы

M>>Любая, где требуется разбор структур (данных). Сопоставление с образцом — это унифицированый подход к разбору произвольных структур(данных)

SR>Это вы хватили, насчет произвольных структур. Вот например разработчики Tom'а заявляли, что в Tom возможно сопоставлять с образцом более сложные структуры чем в Scala, но все равно не произвольные.

Это, возможно, ограничения языков и/или JVM.

M>>Более того, реализация сильно похожа на то же самое

SR>В реализации многовато дублирования образцов. Практически каждый по два раза.

Это мои кривые руки.


M>>Но у меня, безусловно, простой пример. А есть посложнее. Типа того, что я привел в самом начале.

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

На простых просто как раз и начинается- а вот тут я могу if'ом, а вот тут — функцией...


Хотя... Опять же. ПМ предлагает одинаковый подход к решению всех приведенных здесь примеров. Который еще и очень легко читается.
... << RSDN@Home 1.2.0 alpha 4 rev. 1084>>


dmitriid.comGitHubLinkedIn
Re[7]: Действительно ли ML языки хороши в компиляторописани
От: Lazy Cjow Rhrr Россия lj://_lcr_
Дата: 25.04.08 13:29
Оценка: 30 (1) +1
SmbdRsdn,

LCR>>А решать вопрос "сбрасывать или нет" каждый раз должен программист?

SR>Нет. Сбрасывать не зачем.
Тогда приведи наконец этот мега-equals (или matches, неважно). Хотя бы его poc.

SR>Я, конечно, понимаю, отчего возникло непонимание.

SR>Мне было лень писать что-то вроде:
SR>
SR>abstract class Term {};
SR>class Num extends Term {};
SR>class Var extends Term {}

SR>@Exhaustive
SR>Term simplify(Term term) {
SR>  if (term instanceof Num)
SR>     return ...;
SR>  if (term instanceof Var)
SR>     return ...;
SR>  // отсутствует "This method must return a result of type Term."
SR>}
SR>


SR>для показа как может выглядеть проверка на полноту при сопоставлении с образцом в Java.

Это очень хорошо, что ты снизошёл до более предметного разговора, только вот здесь ничего проверить невозможно, потому что у компилятора нет доказательства того, что у Term только 2 потомка. Ведь действительно, мы при запуске можем добавить ещё пару джарок, в которых может определено ещё сколько угодно подклассов Term. В Скале такой проблемы нет, потому что класс помечен sealed.

Попытка номер два?

LCR>>Специально помеченные if-ы

SR>Не отдельные if, а отдельный метод. Помеченный аннотацией. Что является законным способом добавления мета-данных в Java.
Как ты собираешься отделять "паттерн-матчинговские" if-ы от обычных, в которых объекты просто сравниваются между собой?

LCR>>(которые, заметим, работают совсем не так как выглядят!)

SR>Работают так же как и выглядят. То есть делают тоже, что и написано. Просто быстрее.
Да вот оказывается нет, не так.
      _Term x = new _Term();
      if (term.equals(new Mul(new Num(1), x))) return x.value;

Я ожидаю здесь создания композиции из трёх объектов и сравнения (по-видимому глубокого) с объектом term. А оказывается:
1. никакого создания объектов не происходит
2. equals вовсе никакое не сравнение, он не симметричен (уж не знаю, что там с транзитивностью), возвращает значения через параметры (то есть метод имеет побочные эффекты!), и вообще это не метод, а просто символическое имя, которое этот препроцессор понимает по-своему.
3. класс _Term вообще какой-то волшебный. Он одновременно является подклассом всех классов входящих в юнион-тип, потому что класс может принимать в качестве параметра не абстрактный Term, а какие-то конкретные термы, и вайлдкард может матчить как раз конкретный терм:
...
case class Yo(n: Add) extends Term

def simplify(term: Term) = term match {
  ...
  case Yo(x) => x
  case _ => term
}

4. код неявно предполагает, что объекты типов Term, Num, Mul, Add и т.п. иммутабельны, а конструкторы не имеют побочных эффектов. Но это полная туфта, в яве ты нигде не можешь потребовать того, чтобы объект был иммутабельным, и задача определения наличия значимых побочных эффектов в общем случае неразрешима.

Короче, ты просто пытаешься старым именем назвать новую сущность. Код стал более понятным? Щаз. Лично меня ты ввёл в конкретное заблуждение. Я сначала так и подумал: товарищ создаёт дерево на трёх элементах, заводит локальную переменную, передаёт в функцию equals — фигня какая-то. Зачем это делать, если можно этого не делать?

SR>К тому же в Java сообществе имеется много материалов, о том как написать свой equals и для каких целей это может потребоваться.

Да, я всё жду от тебя твоего мега-equals. Не забудь про рефлексивность, симметричность, транзитивность и неналичие побочных эффектов (это чтобы порядок вызова нескольких equals не имел значения).

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

Ничего хорошего в этом я не вижу в упор. Синтаксис должен подчёркивать главное и всячески помогать в программировании, а не смешивать разные сущности в одной ступе а потом тщательно толочь чтобы у программиста сформировалась равномерно распределённая каша в голове... Syntax does matter.
quicksort =: (($:@(<#[),(=#[),$:@(>#[)) ({~ ?@#)) ^: (1<#)
Re[16]: Действительно ли ML языки хороши в компиляторописани
От: SmbdRsdn  
Дата: 25.04.08 19:15
Оценка: -2 :)
Здравствуйте, Mamut, Вы писали:

M>>>При этом с ПМ рекрсия по списку тривиальна

SR>>Неужели считаете, что цикл нетривиален?

M>Он менее "читаем", чем ПМ

Цикл это цикл, причем тут сопоставление с образцом? Сопоставление происходит уже внутри цикла.

M>>>
M>>>{ok, {{Version, 200, ReasonPhrase}, Headers, Body}} =
M>>>      http:request(...
      
M>>>{ok, {_, _, Body}} = http:request(...


M>>>{ok, {_, 200, _}, _, _} = http:request(
M>>>


M>>>Какой-какой автоматизированый equals мне поможет это написать?

SR>>Как-то определили, что мне знаком erlang?

M>Ну, мы ж про паттерн-матчинг говорим? А тут вполне себе паттерн-матчинг. Вполне понятный даже незнакомому с Эрлангом

Ладно попробую, хотя смысл ok слабо понятен. Какое-то ключевое слово в erlang, видимо. Так что пока без ok.
    private Response getResponse() {
        return new Response(list (
            list ( "HTTP/1.1", 200, "OK" ),
            list (
                "Content-Type: text/html; charset=UTF-8", 
                "Content-Length: 0" ),
            list ( "" )
        ));        
    }
    
    public void parse() {
        Response response = getResponse();
        
        Any _ = new Any();
        Match version = new Match(), responsePhrase = new Match(), headers = new Match(), body = new Match();        
        if (response.matches( list ( list (version, 200, responsePhrase), headers, body ))) {
            System.out.println(responsePhrase.value);
        }
        if (response.matches( list (_, _, body))) {
            System.out.println(body.value);
        }        
        if (response.matches( list ( list (_, 200, _), headers, body))) {
            System.out.println(headers.value);
        }
    }


M>Ну, в исходном
Автор: z00n
Дата: 14.12.07
сообщении был приведен и пример кода их компилятора

Какого компилятора? Была приведена только функция упрощения выражения. Потому что Одерски показывал только сопоставление с образцом.
Я уже приводил ссылку на полную версию программы на Scala.
Кстати код на Java, который был приведен в исходном сообщении, вроде бы тоже не руками написан, а с применением спец-компилятора Java

M>Вообще-то на одном только изолированом примере показать/доказать что-то сложно.

M>Надо привести два-три примера, где ПМ позволяет использовать одинаковый подход к решению проблемы, а язык без ПМа требует каждый раз нового подхода (здесь
Автор: SmbdRsdn
Дата: 22.04.08
— реализация метода equals, здесь
Автор: SmbdRsdn
Дата: 24.04.08
— функции с применением if-ов).


M>А ПМ в итоге позволяет читать код, как книгу, без необходимости пробираться сквозь дебри if-ов и попыток понять, что же автор хотел сказать тем или иным циклом

Какие дебри? Даже if'а в if'e нет. Замените if на case и вот практически код на erlang. Или там дебри case'ов?

SR>>Гм, по вашему одна большая функция не разбитая на малые превращается сразу в язык программирования Tom. Интересная способ рассуждений.

M>Или в нечто ему подобное. Потому что мы же хотим некую общую функцию, которая поможет разбирать образцы не только на одном примере разбора веб-форм
Списки — простой случай, повторяю в который раз. Неужели сомневаетесь, что можно написать обобщенную функцию разбора?


SR>>Нет. Вспомните, я и код такого вида не приводил.


M>Ну, для калькулятора был код с term.equals, для проверки веб-=форм был код с if'ами. Для этого конкретного примера term.equals не подойдет, потому что нам не всегда все значения нужны. Так что if-ы

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

M>Это, возможно, ограничения языков и/или JVM.

В Nemerle тоже сопоставляются только варианты.

M>На простых просто как раз и начинается- а вот тут я могу if'ом, а вот тут — функцией...

M>Хотя... Опять же. ПМ предлагает одинаковый подход к решению всех приведенных здесь примеров. Который еще и очень легко читается.
не вижу различий, еще раз считайте что if это case.
Re[8]: Действительно ли ML языки хороши в компиляторописани
От: SmbdRsdn  
Дата: 25.04.08 20:09
Оценка:
Здравствуйте, Lazy Cjow Rhrr, Вы писали:

LCR>SmbdRsdn,


LCR>Тогда приведи наконец этот мега-equals (или matches, неважно). Хотя бы его poc.

Это в почти стандартный equals для сравнения не по ссылке а по содержанию.
class A {
  public Class1 field1;
  public Class2 field2;

  public boolean equals(Object object) {
    return object instanceof A && equals((A)object);
  }
  
  private boolean equals(A a) {
     return field1.equals(a.field1) && field2.equals(a.field2);
  }
}

Конечно реальный equals отличается еще поддержкой связывания.

LCR>Это очень хорошо, что ты снизошёл до более предметного разговора, только вот здесь ничего проверить невозможно, потому что у компилятора нет доказательства того, что у Term только 2 потомка. Ведь действительно, мы при запуске можем добавить ещё пару джарок, в которых может определено ещё сколько угодно подклассов Term. В Скале такой проблемы нет, потому что класс помечен sealed.

Не забывайте, что Скала не может выйти за пределы JVM.
LCR>Попытка номер два?
Надуманная проблема, тем не менее хорошо, что она была озвучена. Решение — конструктор базового класса видимый только из пакета, потомки sealed.

LCR>>>Специально помеченные if-ы

SR>>Не отдельные if, а отдельный метод. Помеченный аннотацией. Что является законным способом добавления мета-данных в Java.
LCR>Как ты собираешься отделять "паттерн-матчинговские" if-ы от обычных, в которых объекты просто сравниваются между собой?
Зачем? Вполне разумно вынести сопоставление с образцом в отдельный метод, в котором не будет if'ов вида (if (object.equals(new Object()))) не представляющих сопоставление с образцом.


SR>>Работают так же как и выглядят. То есть делают тоже, что и написано. Просто быстрее.

LCR>Да вот оказывается нет, не так.
LCR>
LCR>      _Term x = new _Term();
LCR>      if (term.equals(new Mul(new Num(1), x))) return x.value;
LCR>

LCR>Я ожидаю здесь создания композиции из трёх объектов и сравнения (по-видимому глубокого) с объектом term. А оказывается:
LCR>1. никакого создания объектов не происходит
А что тут удивительного? В Java для повышения производительности во время выполнения объект может и не создаваться каждый раз, а браться из пула уже созданных объектов. Даже проще во время компиляции преобразовать образец не в набор if'ов, а в обращение к некоторому пулу образцов, который будет создавать объекты по требованию.
LCR>2. equals вовсе никакое не сравнение, он не симметричен (уж не знаю, что там с транзитивностью),
Симметричность, специально не проверял, но кажется будет симметричен и транзитивен.
LCR>возвращает значения через параметры (то есть метод имеет побочные эффекты!),
Не забывайте, это же Java!
Что еще за требование, что метод не может иметь побочных эффектов?
Может и от оператора присваивания отказаться?
LCR>и вообще это не метод, а просто символическое имя, которое этот препроцессор понимает по-своему.
В каком-то смысле любой метод это символическое имя которое компилятор понимает по своему.
LCR>3. класс _Term вообще какой-то волшебный. Он одновременно является подклассом всех классов входящих в юнион-тип, потому что класс может принимать в качестве параметра не абстрактный Term, а какие-то конкретные термы, и вайлдкард может матчить как раз конкретный терм:
Класс _Term очень простой, его даже можно вывести из его применения.
public class _Term extends Term {
  public Term value;
}

LCR>4. код неявно предполагает, что объекты типов Term, Num, Mul, Add и т.п. иммутабельны, а конструкторы не имеют побочных эффектов.
Из кода не видно, зачем ему это предположение, видимо очень не явно. На Java с Yo можно сопоставлять аналогично предыдущим классам.

LCR>Короче, ты просто пытаешься старым именем назвать новую сущность.

Скорее новым (для Java) именем старую. Equals можно было переопределять давным давно.

LCR>Код стал более понятным? Щаз. Лично меня ты ввёл в конкретное заблуждение.

Ну если так легко ввести в заблуждением кодом вида if (object.equals(new Object())), тогда не знаю.
Видимо надо начинать спрашивать про опыт программирования на Java.

SR>>К тому же в Java сообществе имеется много материалов, о том как написать свой equals и для каких целей это может потребоваться.

LCR>Да, я всё жду от тебя твоего мега-equals. Не забудь про рефлексивность, симметричность, транзитивность и неналичие побочных эффектов (это чтобы порядок вызова нескольких equals не имел значения).

LCR>Ничего хорошего в этом я не вижу в упор. Синтаксис должен подчёркивать главное и всячески помогать в программировании, а не смешивать разные сущности в одной ступе а потом тщательно толочь чтобы у программиста сформировалась равномерно распределённая каша в голове... Syntax does matter.

Ну это поэзия, которая может быть и красивой, но часто неправой. А в реальности имеем синтаксис отличающийся словом new.
Re[17]: Действительно ли ML языки хороши в компиляторописани
От: Mamut Швеция http://dmitriid.com
Дата: 26.04.08 08:13
Оценка:
M>>>>При этом с ПМ рекрсия по списку тривиальна
SR>>>Неужели считаете, что цикл нетривиален?

M>>Он менее "читаем", чем ПМ

SR>Цикл это цикл, причем тут сопоставление с образцом? Сопоставление происходит уже внутри цикла.

match([]) ->
    not_ok.
match([H|T]) ->
    ok.


намного понятнее. Тем более, что мы сразу на месте можем указать, что нам нужно:

match([{ok, Value}|T]) ->
    ok.
match([что_то_там|T]) ->
    ok.
match([{ok, {{Version, 200, ReasonPhrase}, Headers, Body}}|T]) ->
    %% здесь мы сразу получаем доступ ко всем переменным
    ok.


M>>>>
M>>>>{ok, {{Version, 200, ReasonPhrase}, Headers, Body}} =
M>>>>      http:request(...
      
M>>>>{ok, {_, _, Body}} = http:request(...


M>>>>{ok, {_, 200, _}, _, _} = http:request(
M>>>>


M>>>>Какой-какой автоматизированый equals мне поможет это написать?

SR>>>Как-то определили, что мне знаком erlang?

M>>Ну, мы ж про паттерн-матчинг говорим? А тут вполне себе паттерн-матчинг. Вполне понятный даже незнакомому с Эрлангом

SR>Ладно попробую, хотя смысл ok слабо понятен. Какое-то ключевое слово в erlang, видимо. Так что пока без ok.
SR>
SR>    private Response getResponse() {
SR>        return new Response(list (
SR>            list ( "HTTP/1.1", 200, "OK" ),
SR>            list (
SR>                "Content-Type: text/html; charset=UTF-8", 
SR>                "Content-Length: 0" ),
SR>            list ( "" )
SR>        ));        
SR>    }
    
SR>    public void parse() {
SR>        Response response = getResponse();
        
SR>        Any _ = new Any();
SR>        Match version = new Match(), responsePhrase = new Match(), headers = new Match(), body = new Match();        
SR>        if (response.matches( list ( list (version, 200, responsePhrase), headers, body ))) {
SR>            System.out.println(responsePhrase.value);
SR>        }
SR>        if (response.matches( list (_, _, body))) {
SR>            System.out.println(body.value);
SR>        }        
SR>        if (response.matches( list ( list (_, 200, _), headers, body))) {
SR>            System.out.println(headers.value);
SR>        }
SR>    }
SR>


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

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

%% Первый пример, http://rsdn.ru/Forum/Message.aspx?mid=2766871&only=1
%% намеренно сокращен :)

match({0, x}) ->
    0;
match({1, x}) ->
    x;
match({a, b}) ->
    a*b;
    
%% Второй пример, с правилами валидации
%% http://rsdn.ru/Forum/Message.aspx?mid=2927907&only=1
%% Слегка сокращен

match({Field, Rule}) ->
    match_rule(Field, Rule);
match(Field) when is_atom(Field) ->
    field_exists(Field);
    
match_rule(Field, {Func, Value}) ->
  Func(Field, Value);
  
%% третий пример, http://rsdn.ru/Forum/Message.aspx?mid=2927730&only=1

match([]) ->
    ok;
match({i, _, empty}) ->
    ok;
match({i, m, {'Cons', x, y}}) ->
    ok;
    %% и так далее


%% четвертый пример, http://rsdn.ru/Forum/Message.aspx?mid=2929226&only=1

match({ok, {{Version, 200, ReasonPhrase}, Headers, Body}}) ->
    ok;
match({ok, {{_, 404, ReasonPhrase}, _, _}}) ->
    ok;



Я с удовольствием посмотрю на общую функцию match, которая разберется со всеми этими примерами одним махом.



SR>>>Гм, по вашему одна большая функция не разбитая на малые превращается сразу в язык программирования Tom. Интересная способ рассуждений.

M>>Или в нечто ему подобное. Потому что мы же хотим некую общую функцию, которая поможет разбирать образцы не только на одном примере разбора веб-форм
SR>Списки — простой случай, повторяю в который раз. Неужели сомневаетесь, что можно написать обобщенную функцию разбора?


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


SR>>>Нет. Вспомните, я и код такого вида не приводил.


M>>Ну, для калькулятора был код с term.equals, для проверки веб-=форм был код с if'ами. Для этого конкретного примера term.equals не подойдет, потому что нам не всегда все значения нужны. Так что if-ы

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

Зачем их тогда упоминать?

M>>Это, возможно, ограничения языков и/или JVM.

SR>В Nemerle тоже сопоставляются только варианты.

M>>На простых просто как раз и начинается- а вот тут я могу if'ом, а вот тут — функцией...

M>>Хотя... Опять же. ПМ предлагает одинаковый подход к решению всех приведенных здесь примеров. Который еще и очень легко читается.
SR>не вижу различий, еще раз считайте что if это case.

и if и case могут проверять только значения. ПМ позвляет проверять и структуру и значения сразу, без какойлибо дополнительной работы со сторноы программиста. В этом — главное и основное отличие
... << RSDN@Home 1.2.0 alpha 4 rev. 1084>>


dmitriid.comGitHubLinkedIn
Re[18]: Действительно ли ML языки хороши в компиляторописани
От: SmbdRsdn  
Дата: 26.04.08 21:46
Оценка: :)
Здравствуйте, Mamut, Вы писали:

M>>>>>При этом с ПМ рекрсия по списку тривиальна

SR>>>>Неужели считаете, что цикл нетривиален?

M>>>Он менее "читаем", чем ПМ

SR>>Цикл это цикл, причем тут сопоставление с образцом? Сопоставление происходит уже внутри цикла.

M>
M>match([]) ->
M>    not_ok.
M>match([H|T]) ->
M>    ok.
M>


M>намного понятнее. Тем более, что мы сразу на месте можем указать, что нам нужно:

Вы не поняли изначально. В вашем коде и моем нет сопоставления цикл — pattern matching. А есть сопоставление цикл — рекурсия.
А нужна она для того, чтобы после разбора начала списка, разобрать хвост списка. Это же стандартная тема сопоставления ФП и ИП.

M>И это называется удобным???


M>На каждый случай писать свою, отдельную, специализированную функцию, заточенную под разбор только данного конкретного случая?

Гм, у вас какое-то преувеличение насчет списков. Эта структура данных известна давным давно, все с ней более менее ясно.
С чего вы взяли, что там отдельная специализированная функция? Там обобщенная. А класс Response всего лишь обертка, которую можно и не заводить.
Я же его завел, потому что мне хотелось иметь инфиксную форму вызова matches.
А так было бы,
boolean matches(Object[] list, Object[] pattern) {
}

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

M>На четырех простейших примерах — это уже четвертая такая функция.

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

M>ПМ позволяет использовать унифицированый подход к разбору как структуры так и значений:

Сопоставление с образцом в Java позволяет ровно тоже самое.

M>Я с удовольствием посмотрю на общую функцию match, которая разберется со всеми этими примерами одним махом.

M>
M>match({0, x}) ->
M>    0;
M>match({1, x}) ->
M>    x;
M>match({a, b}) ->
M>    a*b;
M>

Match x = new Match();
if (list.matches(0, x))
  return 0;
if (list.matches(1, x))
  return x.value;
Match a = new Match, b = new Match();
if (list.matches(a, b))
  return a.value * b.value;

M>
M>match({Field, Rule}) ->
M>    match_rule(Field, Rule);
M>match(Field) when is_atom(Field) ->
M>    field_exists(Field)
M>match_rule(Field, {Func, Value}) ->
M>  Func(Field, Value);
M>

Match field = new Match(), rule = new Match();
if (list.matches(field, rule)) {
  Match func = new Match(), value = new Match();
  if (rule.value.matches(func, value))
    return func.value(field.value, value.value);
}
if (list.matches(field))
  return fieldExists(field.value);

M>
M>match([]) ->
M>    ok;
M>match({i, _, empty}) ->
M>    ok;
M>match({i, m, {'Cons', x, y}}) ->
M>    ok;
M>

if (list.matches())
  return ok;
Match i = new Match(), empty = new Match();
if (list.matches(i, _, empty))
  return ok;
Match m = new Match(), x = new Match(), y = new Match();
if (list.matches(i, m, list("Cons", x, y)))
  return ok;

M>
M>match({ok, {{Version, 200, ReasonPhrase}, Headers, Body}}) ->
M>    ok;
M>match({ok, {{_, 404, ReasonPhrase}, _, _}}) ->
M>    ok;
M>

Match ok = new Match(), version = new Match(), reasonPhrase = new Match(), headers = new Match(), body = new Match();
if (list.matches(ok, list (version, 200, reasonPhrase), headers, body)
  return ok;
if (list.matches(ok, list (_, 404, reasonPhrase), _, _)
  return ok;


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


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

Остальные два варианта с функцией validate и c циклом приводились, для уточнения условий задачи и там, действительно или не использовалось или не было ярко выражено сопоставление с образцом.

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

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

M>и if и case могут проверять только значения. ПМ позвляет проверять и структуру и значения сразу, без какойлибо дополнительной работы со сторноы программиста. В этом — главное и основное отличие

Так же и при сопоставлении с образцом в Java.
Re[19]: Действительно ли ML языки хороши в компиляторописани
От: FR  
Дата: 27.04.08 10:29
Оценка: 1 (1) :)
Здравствуйте, SmbdRsdn, Вы писали:

Вообще классно пишешь, и главное так хитро и тонко, я вот почитал и практическм перестал сомневатся в преимуществах ML образных
Re[20]: Действительно ли ML языки хороши в компиляторописани
От: SmbdRsdn  
Дата: 27.04.08 11:54
Оценка: :)
Здравствуйте, FR, Вы писали:

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

Спасибо, за похвалу.
Re[20]: Действительно ли ML языки хороши в компиляторописани
От: WolfHound  
Дата: 27.04.08 13:02
Оценка:
Здравствуйте, FR, Вы писали:

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

Давай-давай.
У нас конкурентов меньше будет.
... << RSDN@Home 1.2.0 alpha rev. 745>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[19]: Действительно ли ML языки хороши в компиляторописани
От: WolfHound  
Дата: 27.04.08 13:02
Оценка: +1
Здравствуйте, SmbdRsdn, Вы писали:

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

А причем тут вобще списки?

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

Вобще говоря списки это частный случай вариантов.
Не знал?
variant List[T]
{
| Cons { value : T; tail : List[T]; }
| Null
}

А компилятор их просто слегка подсахаривает.

А алгоритм генерации сопоставления с образцом уже не различает списки там или нет.

M>>ПМ позволяет использовать унифицированый подход к разбору как структуры так и значений:

SR>Сопоставление с образцом в Java позволяет ровно тоже самое.
Реализацию такую чтобы я ее не разломал в пыль с первой же попытки в студию.
Про то чтобы оно еще и работало хотябы со скоростью аналога на скале я думаю можно вобще не заикаться.

M>>Я с удовольствием посмотрю на общую функцию match, которая разберется со всеми этими примерами одним махом.

У этой горы кода есть 2 проблемы:
1)Куча грязи.
2)Он не работает.
А так да. Написать кучу неработающего псевдокода с кучей грязи может любой.

SR>Так же и при сопоставлении с образцом в Java.

А его нет.
... << RSDN@Home 1.2.0 alpha rev. 745>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[20]: Действительно ли ML языки хороши в компиляторописани
От: SmbdRsdn  
Дата: 27.04.08 16:07
Оценка:
Здравствуйте, WolfHound, Вы писали:

Гм, а раньше только улыбались в оценках...

WH>А причем тут вобще списки?

Если {0, {1, 2}} не список, тогда действительно не причем.

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

WH>Вобще говоря списки это частный случай вариантов.
WH>Не знал?
WH>
WH>variant List[T]
WH>{
WH>| Cons { value : T; tail : List[T]; }
WH>| Null
WH>}
WH>

WH>А компилятор их просто слегка подсахаривает.
А можно в этот вариант вложить {0, {1, 2}}? Или только {0, 1, 2}?

WH>А алгоритм генерации сопоставления с образцом уже не различает списки там или нет.

Тем лучше, значит и в java можно сделать единую функцию сопоставления с образцом

WH>Реализацию такую чтобы я ее не разломал в пыль с первой же попытки в студию.

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

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

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

WH>У этой горы кода есть 2 проблемы:

WH>1)Куча грязи.
"Грязь" — там только в необходимости заранее объявлять переменные.
Грязь в кавычках, потому что существует много доводов как за, так и против использования переменных без их объявления.
Сами же образцы для сопоставления отличаются несущественно.
WH>2)Он не работает.
Он не не работает, он не приведен целиком.
Впрочем с учетом того, что код проделывающий сопоставление с образцом является в достаточной мере обобщенным и может быть вынесен в библиотеку.
WH>А так да. Написать кучу неработающего псевдокода с кучей грязи может любой.
Псевдокод это, обычно, код, для которого пока не существует компилятора.
Мой же код с успехом компилируется существующими компиляторами Java.

WH>А его нет.

А она есть. Замечу, правда, что в эту игру — есть/нет — можно играть долго.
Re[19]: Действительно ли ML языки хороши в компиляторописани
От: Mamut Швеция http://dmitriid.com
Дата: 27.04.08 16:13
Оценка:
SR>Вы не поняли изначально. В вашем коде и моем нет сопоставления цикл — pattern matching. А есть сопоставление цикл — рекурсия.
SR>А нужна она для того, чтобы после разбора начала списка, разобрать хвост списка. Это же стандартная тема сопоставления ФП и ИП.

Ничего не понял

M>>И это называется удобным???


M>>На каждый случай писать свою, отдельную, специализированную функцию, заточенную под разбор только данного конкретного случая?

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


Причем тут списки? Идет речь не о списках, а о произвольных структурах.

SR>С чего вы взяли, что там отдельная специализированная функция? Там обобщенная. А класс Response всего лишь обертка, которую можно и не заводить.

SR>Я же его завел, потому что мне хотелось иметь инфиксную форму вызова matches.
SR>А так было бы,
SR>
SR>boolean matches(Object[] list, Object[] pattern) {
SR>}
SR>

SR>И сопоставлять она будет списки с произвольной структурой.
SR>В который уже раз повторяю — обратите внимание, практически всегда, когда идет нахваливание сопоставления с образцом речь идет о вариантах, а не о просто списках.

Так никто про списки изначально и не говорил


M>>На четырех простейших примерах — это уже четвертая такая функция.

SR>Не четыре, а два и приводилась декларативная форма представления. А как это реализовано внутри не важно, главное, что можно сделать это обобщенно.

Как это реализовано внутри — это очень важно. Во всех примерах на Яве приходилось задвигать передаваемые данные в прокрустово ложе if'а (case'а), потому что ни if ни case не разбирают структуру разбираемых данных.

SR>Неужели считаете, что в Scala сопоставление со списком и с вариантами это одна функция? Конечно, это может быть и так, но скорее всего их тоже две.


Да, но прогарммисту, это использующему — абсолютно все равно:
case input_data of
    [{elem1, elem2}|T] -> сделаем что-то одно
    [[L]|T] -> разбираем вложенный список
    {a, b} -> а ждесь вообще не список, оппаньки
    {[H|T], [H2|T2]} -> и здесь не список передали. но внутри список
    {a, {b, {c, d}}} -> здесь списком даже и не пахнет, но все разобрали
    {_, _, _, _, x} -> нам важен только 5-й параметр, хотя струкутра может быть такой:
    {{a, b, c}, [H|T], {[H2|T2]}, d, e} -> и все равно мы ее сможем разобрать
end




M>>ПМ позволяет использовать унифицированый подход к разбору как структуры так и значений:

SR>Сопоставление с образцом в Java позволяет ровно тоже самое.

Не позволяет. Его в Яве нет. Все, что есть — это if/case, которые структуру разобрать не позволяют.


M>>Я с удовольствием посмотрю на общую функцию match, которая разберется со всеми этими примерами одним махом.


SR>[поскипаны примеры псевдокода]


что за list.match()? кто его написал? откуда он взялся? он будет работать для произвольных данных?


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


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

SR>И случаев относящихся к сопоставление с образцом не четыре, а два. Сопоставление со списком, и сопоставление с вариантами.

И для каждого случая пришлось писать отдельную функцию, разбирающую отдельную структуру только в данном конкретном случае для того, чтобы вернуть true/false, чтобы это можно было проверить if/case'ом

M>>и if и case могут проверять только значения. ПМ позвляет проверять и структуру и значения сразу, без какойлибо дополнительной работы со сторноы программиста. В этом — главное и основное отличие

SR>Так же и при сопоставлении с образцом в Java.

Еще раз — Java такого не позволяет:

ПМ:
match({1, 2, 3}) ->
    ok;

match({"a", "b", "c"}) ->
    ok;

match([H|T]) ->
    ok.


Как общим кодом на Яве узнать, что:
— в первом случае у нас объект с тремя целочисленными полями
— во втором — с тремя текстовыми полями
— в третьем — вообще списко/массив
?

Более того, если нас не интересует тимп полей, а только их структура? Сколько перегруженых операторов equals придется писать для каждого отдельного случая?


dmitriid.comGitHubLinkedIn
Re[20]: Действительно ли ML языки хороши в компиляторописани
От: SmbdRsdn  
Дата: 27.04.08 17:08
Оценка: :)
Здравствуйте, Mamut, Вы писали:

M>Ничего не понял

Сочувствую.

M>Причем тут списки?

M>Так никто про списки изначально и не говорил
Притом, что в ваших образцах в большинстве случаев приводятся списки.
То есть, что-то типа {obj1, obj2, _, {obj3, _ }, _}.
Я же вам в который раз отвечаю, что такие образцы легко релизуются в java. Легко по сравнению со вторым типом.
А вот более интересные типа Obj1(Obj2(_, Obj3())) у вас встречаются значительно реже.

M>Как это реализовано внутри — это очень важно. Во всех примерах на Яве приходилось задвигать передаваемые данные в прокрустово ложе if'а (case'а), потому что ни if ни case не разбирают структуру разбираемых данных.

Конечно не разбирают. Разбирает метод matches. А if в зависимости от успешности разбора передает управление.
Кстати, когда я говорил вам обратить внимание, что if это case, я имел ввиду, case из erlang, а не из java.

M>Да, но прогарммисту, это использующему — абсолютно все равно:

M>
M>case input_data of
M>    [{elem1, elem2}|T] -> сделаем что-то одно
M>    [[L]|T] -> разбираем вложенный список
M>    {a, b} -> а ждесь вообще не список, оппаньки
M>    {[H|T], [H2|T2]} -> и здесь не список передали. но внутри список
M>    {a, {b, {c, d}}} -> здесь списком даже и не пахнет, но все разобрали
M>    {_, _, _, _, x} -> нам важен только 5-й параметр, хотя струкутра может быть такой:
M>    {{a, b, c}, [H|T], {[H2|T2]}, d, e} -> и все равно мы ее сможем разобрать
M>end
M>

if (data.matches(list(elem1, elem2), T))
if (data.matches(list(L), T))
if (data.matches(a, b)
if (data.matches(list(H, T), list(H2, T2))
if (data.matches(a, list(b, list(c, d)))
if (data.matches(_, _, _, _, x))
if (data.matches(list(a, b, c), list(H, T), list(list(H2, T2), d, e)))


M>Не позволяет. Его в Яве нет. Все, что есть — это if/case, которые структуру разобрать не позволяют.

Позволяют. Играть, в эту игру можно долго.

SR>>[поскипаны примеры псевдокода]

Какой же это псевдокод? Вполне себе успешно компилируется Java.

M>что за list.match()? кто его написал? откуда он взялся? он будет работать для произвольных данных?

Его написал я. Я. Я его написал. Да.

M>И для каждого случая пришлось писать отдельную функцию, разбирающую отдельную структуру только в данном конкретном случае для того, чтобы вернуть true/false, чтобы это можно было проверить if/case'ом

Нет код обобщенный, пишу уже в который раз.

M>Еще раз — Java такого не позволяет:

Позволяет. Играть в эту игру можно долго.

M>ПМ:

M>
M>match({1, 2, 3}) ->
M>    ok;

M>match({"a", "b", "c"}) ->
M>    ok;

M>match([H|T]) ->
M>    ok.
M>


M>Как общим кодом на Яве узнать, что:

M>- в первом случае у нас объект с тремя целочисленными полями
if (list.matches(1, 2, 3))
  return ok;

M>- во втором — с тремя текстовыми полями
if (list.matches("a", "b", "c")
  return ok;

M>- в третьем — вообще списко/массив
Match h = new Match(); Tail t = new Tail();
if (list.matches(h, t))
  return ok;

M>?

M>Более того, если нас не интересует тимп полей, а только их структура?

Что же не привели образец для сопоставления? Уверен я легко мог бы сделать такой и на Java.
M>Сколько перегруженых операторов equals придется писать для каждого отдельного случая?
0. equals пишется для вариантов, но при поддержке компилятора и среды его можно и не писать.
Re[21]: Действительно ли ML языки хороши в компиляторописани
От: Cyberax Марс  
Дата: 27.04.08 17:13
Оценка:
Здравствуйте, SmbdRsdn, Вы писали:

M>>Более того, если нас не интересует тимп полей, а только их структура?

SR>Что же не привели образец для сопоставления? Уверен я легко мог бы сделать такой и на Java.
Нельзя. Точнее, можно, но совершенно непрактично.

M>>Сколько перегруженых операторов equals придется писать для каждого отдельного случая?

SR>0. equals пишется для вариантов, но при поддержке компилятора и среды его можно и не писать.
?? equals можно автоматически сгенерировать с помощью IDE.
Sapienti sat!
Re[21]: Действительно ли ML языки хороши в компиляторописани
От: WolfHound  
Дата: 27.04.08 17:19
Оценка:
Здравствуйте, SmbdRsdn, Вы писали:

WH>>А причем тут вобще списки?

SR>Если {0, {1, 2}} не список, тогда действительно не причем.
Это вобще туплы.

SR>А можно в этот вариант вложить {0, {1, 2}}? Или только {0, 1, 2}?

В этот нельзя.
Язык статически типизированный.
В динамически типизированных языках таких как erlang можно.

SR>Тем лучше, значит и в java можно сделать единую функцию сопоставления с образцом

Теоритически все можно сделать... особенно на словах...

WH>>Реализацию такую чтобы я ее не разломал в пыль с первой же попытки в студию.

SR>Ожидаете устойчивый к разламыванию в пыль код сопоставления с образцом?
Да.

SR>Что вы кстати вкладываете в понятие разламывание в пыль?

Покажи код увидишь.

SR>До получения ответа, не рискну выкладывать код, так как не знаю требований.

Устойчивость к дуракам типа меня.
Ну и чтобы лишних проверок не делал.

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

SR>Убежден, что из этих кусков решение можно восстановить целиком.
Вот еще за тебя делать твою работу.

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

SR>Скорость сопоставления с образцом уже обсуждалась. Могу лишь вновь повторить свои доводы.
Ты где настолько умные компиляторы видел?
Я покачто видел только компиляторы которые генерили оптимальный код только если точно знали что происходит.

SR>"Грязь" — там только в необходимости заранее объявлять переменные.

Там ее еще много.

SR>Грязь в кавычках, потому что существует много доводов как за,

Аргументов за нет и быть не может.
Ибо невозможно обосновать наличие текста который совершенно ничего не дает.

SR>так и против использования переменных без их объявления.

А это вобще бред.
Переменные объявляются в коде паттерна.

SR>Сами же образцы для сопоставления отличаются несущественно.

На игрушечных примерах.

SR>Псевдокод это, обычно, код, для которого пока не существует компилятора.

SR>Мой же код с успехом компилируется существующими компиляторами Java.
Полный код в студию.
В чем проблема?
Ведь ты же его вроде как уже написал.
... << RSDN@Home 1.2.0 alpha rev. 745>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[21]: Действительно ли ML языки хороши в компиляторописани
От: Mamut Швеция http://dmitriid.com
Дата: 27.04.08 19:22
Оценка:
M>>Причем тут списки?
M>>Так никто про списки изначально и не говорил
SR>Притом, что в ваших образцах в большинстве случаев приводятся списки.
SR>То есть, что-то типа {obj1, obj2, _, {obj3, _ }, _}.
SR>Я же вам в который раз отвечаю, что такие образцы легко релизуются в java. Легко по сравнению со вторым типом.
SR>А вот более интересные типа Obj1(Obj2(_, Obj3())) у вас встречаются значительно реже.

{a, b, c} — это кортеж
[a, b, c] — это список

Птаница в незнакомом синтаксисе просто произошла

Таким образом,
match({a, b, c})


это сопоставление с экземпляром класса типа
class Elem {
  a;
  b;
  c;
}


где a, b, c — это поля произвольного типа

поэтому все остальное поскипано, потому что мы возвращаемся к коду из первого примера:
class Term
case class Num(n: int)           extends Term
case class Var(name: String)     extends Term
case class Mul(l: Term, r: Term) extends Term
case class Add(l: Term, r: Term) extends Term

// Now let's say we want to implement some simplification rules on such terms.
// Two useful simplifications apply the equalities:
// 0 * x  =  0
// 1 * x  =  x

def simplify(term: Term) = term match {
  case Mul(Num(0), x) => Num(0)
  case Mul(Num(1), x) => x
  case _ => term
}
... << RSDN@Home 1.2.0 alpha 4 rev. 1084>>


dmitriid.comGitHubLinkedIn
Re[22]: Действительно ли ML языки хороши в компиляторописани
От: SmbdRsdn  
Дата: 27.04.08 19:45
Оценка:
Здравствуйте, Cyberax, Вы писали:

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


M>>>Более того, если нас не интересует тимп полей, а только их структура?

SR>>Что же не привели образец для сопоставления? Уверен я легко мог бы сделать такой и на Java.
C>Нельзя. Точнее, можно, но совершенно непрактично.
Так нельзя или можно?
Если можно, то в чем будет непрактичность?

M>>>Сколько перегруженых операторов equals придется писать для каждого отдельного случая?

SR>>0. equals пишется для вариантов, но при поддержке компилятора и среды его можно и не писать.
C>?? equals можно автоматически сгенерировать с помощью IDE.
Это был вопрос? Если да, то что удивляет? Чего только сейчас IDE не генерируют.
Например Eclipse по
class A {
  final Object b;
  Object c;
}

в несколько щелчков мышью сделает
class A {
  final Class1 b;
  Class2 c;

  public A(Class1 b, Class2 c) {
    this.b = b;
    this.c = c;
  }

  public Class1 getB() { 
    return b; 
  }
  public void setC(Class2 c) { 
    this.c = c; 
  }
  public Class2 getC() { 
    return c; 
  }
}

Сами понимаете, что добавить еще и equals не сложно.
Re[22]: Действительно ли ML языки хороши в компиляторописани
От: SmbdRsdn  
Дата: 27.04.08 20:21
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>Это вобще туплы.

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

WH>В этот нельзя.

WH>Язык статически типизированный.
WH>В динамически типизированных языках таких как erlang можно.
Как раз в последних сообщениях разговор, насколько я понимаю, шел про erlang.

WH>Теоритически все можно сделать... особенно на словах...

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

WH>Покажи код увидишь.

Может быть покажете свою мощь на уже выложенных мной примерах?

WH>Устойчивость к дуракам типа меня.

Уже боюсь.
WH>Ну и чтобы лишних проверок не делал.
Что, совсем?

WH>Вот еще за тебя делать твою работу.

Что значит за меня, я ее уже проделал.

WH>Ты где настолько умные компиляторы видел?

Про интеллект компиляторов тоже отвечал. Могу только повторить.
Да, собственно в теме уже приводился пример, который развертывает сопоставление с образцом в набор if'ов на lua.
WH>Я покачто видел только компиляторы которые генерили оптимальный код только если точно знали что происходит.
Так и тут.

SR>>"Грязь" — там только в необходимости заранее объявлять переменные.

WH>Там ее еще много.
Да вроде все чисто. Впрочем с благодарностью приму указание на конкретную грязь.

WH>Аргументов за нет и быть не может.

WH>Ибо невозможно обосновать наличие текста который совершенно ничего не дает.
Все-таки это вопрос стиля конкретного языка. Есть в которых объявляют, а есть в которых нет.

SR>>так и против использования переменных без их объявления.

WH>А это вобще бред.
WH>Переменные объявляются в коде паттерна.
Пусть так, но все-таки в языке имеется и явный синтаксис объявления переменной.

SR>>Сами же образцы для сопоставления отличаются несущественно.

WH>На игрушечных примерах.
Как показывать преимущества Scala над Java так примеры нормальные, а как выяснится, что преимущества и нет, так примеры игрушечные.

WH>Полный код в студию.

WH>В чем проблема?
С моей точки зрения код тривиален. С точки зрения моих противников код не может существовать.
Так как мои противники люди нетривиальные (это похвала) вероятно мой код весьма интересен.
Поэтому может быть мне стоит его представить в более широковещательном виде, например в виде статьи в журнале и статьи на какой-либо конкурс.
Re[23]: Действительно ли ML языки хороши в компиляторописани
От: Mamut Швеция http://dmitriid.com
Дата: 27.04.08 21:49
Оценка:
SR>Это был вопрос? Если да, то что удивляет? Чего только сейчас IDE не генерируют.
SR>Например Eclipse по
SR>
SR>class A {
SR>  final Object b;
SR>  Object c;
SR>}
SR>

SR>в несколько щелчков мышью сделает
SR>
SR>class A {
SR>  final Class1 b;
SR>  Class2 c;

SR>  public A(Class1 b, Class2 c) {
SR>    this.b = b;
SR>    this.c = c;
SR>  }

SR>  public Class1 getB() { 
SR>    return b; 
SR>  }
SR>  public void setC(Class2 c) { 
SR>    this.c = c; 
SR>  }
SR>  public Class2 getC() { 
SR>    return c; 
SR>  }
SR>}
SR>

SR>Сами понимаете, что добавить еще и equals не сложно.

Потом кто-то это будет редактировать под vi через ssh
... << RSDN@Home 1.2.0 alpha 4 rev. 1084>>


dmitriid.comGitHubLinkedIn
Re[23]: Действительно ли ML языки хороши в компиляторописани
От: Cyberax Марс  
Дата: 27.04.08 21:54
Оценка:
Здравствуйте, SmbdRsdn, Вы писали:

SR>>>Что же не привели образец для сопоставления? Уверен я легко мог бы сделать такой и на Java.

C>>Нельзя. Точнее, можно, но совершенно непрактично.
SR>Так нельзя или можно?
Нельзя.

SR>Если можно, то в чем будет непрактичность?

Тонны кода.

M>>>>Сколько перегруженых операторов equals придется писать для каждого отдельного случая?

SR>>>0. equals пишется для вариантов, но при поддержке компилятора и среды его можно и не писать.
C>>?? equals можно автоматически сгенерировать с помощью IDE.
SR>Это был вопрос? Если да, то что удивляет? Чего только сейчас IDE не генерируют.
Нет, это было удивление. Я прекрасно знаю как сейчас работают Java IDE (чай не зря 8 лет на Java пишу...).

SR>Сами понимаете, что добавить еще и equals не сложно.

Ага. Только и получаются тонны ненужного кода в результате.
Sapienti sat!
Re[21]: Действительно ли ML языки хороши в компиляторописани
От: FR  
Дата: 28.04.08 03:12
Оценка:
Здравствуйте, WolfHound, Вы писали:

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


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

WH>Давай-давай.
WH>У нас конкурентов меньше будет.

Халва, халва, халва
Re[24]: Действительно ли ML языки хороши в компиляторописани
От: FR  
Дата: 28.04.08 03:31
Оценка:
Здравствуйте, Cyberax, Вы писали:

SR>>Сами понимаете, что добавить еще и equals не сложно.

C>Ага. Только и получаются тонны ненужного кода в результате.

Вообще у меня дежавью, помню спорил лет восемь назад с закоренелым сишником о пользе и необходимости классов, в общем аргументы практически один к одному и главный "все можно сделать".
Re[25]: Действительно ли ML языки хороши в компиляторописани
От: Cyberax Марс  
Дата: 28.04.08 04:09
Оценка: :)
Здравствуйте, FR, Вы писали:

C>>Ага. Только и получаются тонны ненужного кода в результате.

FR>Вообще у меня дежавью, помню спорил лет восемь назад с закоренелым сишником о пользе и необходимости классов, в общем аргументы практически один к одному и главный "все можно сделать".
Классы — это ещё фигня. Их, действительно, совсем не так уж сложно сделать.

А вот pattern matching — это вещь уже совсем другого уровня сложности.
Sapienti sat!
Re[26]: Действительно ли ML языки хороши в компиляторописани
От: Курилка Россия http://kirya.narod.ru/
Дата: 28.04.08 04:17
Оценка:
Здравствуйте, Cyberax, Вы писали:

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


C>>>Ага. Только и получаются тонны ненужного кода в результате.

FR>>Вообще у меня дежавью, помню спорил лет восемь назад с закоренелым сишником о пользе и необходимости классов, в общем аргументы практически один к одному и главный "все можно сделать".
C>Классы — это ещё фигня. Их, действительно, совсем не так уж сложно сделать.
Вопрос только, какие именно классы
Хотя, конечно, можно для каждой задачи свой вариант классов ваять
Re[23]: Действительно ли ML языки хороши в компиляторописани
От: WolfHound  
Дата: 28.04.08 10:35
Оценка:
Здравствуйте, SmbdRsdn, Вы писали:

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

Кортежи не списки.
Это совсем другие зверьки.

WH>>Теоритически все можно сделать... особенно на словах...

SR>Теоретически и опровергнуть можно, особенно на словах.
Опровергать то чему нет никаких подтверждений не имеет смысла.
Оно опровергнуто по умолчанию.

WH>>Покажи код увидишь.

SR>Может быть покажете свою мощь на уже выложенных мной примерах?
Примеры без того что их исполняет не имеют смысла ибо это не болие чем псевдокод и работать они не могут.

WH>>Вот еще за тебя делать твою работу.

SR>Что значит за меня, я ее уже проделал.
Вот и покажи раз проделал.
Иначе придется сделать вывод что все это пустой треп.

SR>Про интеллект компиляторов тоже отвечал. Могу только повторить.

Да хоть заповторяйся умнее они не станут.

SR>Да, собственно в теме уже приводился пример, который развертывает сопоставление с образцом в набор if'ов на lua.

Компилятор действовал в условиях полной определенности.

SR>Все-таки это вопрос стиля конкретного языка. Есть в которых объявляют, а есть в которых нет.

А тут переменные объявляют.
Это не бейсик какойнибуть где переменные объявляются при первом обращении.
Тут объявление явное.

SR>Пусть так, но все-таки в языке имеется и явный синтаксис объявления переменной.

Синтаксис дело десятое.
Главное что переменные всегда объявляются явно.

SR>С моей точки зрения код тривиален. С точки зрения моих противников код не может существовать.

Я могу придумать сотни вариантов того что делает вид что работает.
Так что код в студию.

SR>Так как мои противники люди нетривиальные (это похвала) вероятно мой код весьма интересен.

SR>Поэтому может быть мне стоит его представить в более широковещательном виде, например в виде статьи в журнале и статьи на какой-либо конкурс.
Да ты хотябы тут покажи.

Или таки все это пустой треп?
... << RSDN@Home 1.2.0 alpha rev. 745>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[22]: Действительно ли ML языки хороши в компиляторописани
От: SmbdRsdn  
Дата: 28.04.08 11:50
Оценка:
Здравствуйте, Mamut, Вы писали:

M>Птаница в незнакомом синтаксисе просто произошла

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

M>Таким образом,

M>
M>match({a, b, c})
M>


M>это сопоставление с экземпляром класса типа

Кортеж, я так понимаю, отдельный тип, а не любой класс с полями.
M>
M>class Elem {
M>  a;
M>  b;
M>  c;
M>}
M>

И сопоставлять должно что-то в духе — match(Elem(a,b,c))
Иначе возникает очевидная путаница между классами у которых одинаковые внутренние типы, например Add и Sum.

M>где a, b, c — это поля произвольного типа


M>поэтому все остальное поскипано, потому что мы возвращаемся к коду из первого примера:

Зачем возвращаемся не понятно. Код сопоставления к этому примеру я уже приводил.
Re[24]: Действительно ли ML языки хороши в компиляторописани
От: SmbdRsdn  
Дата: 28.04.08 11:56
Оценка:
Здравствуйте, Mamut, Вы писали:

M>Потом кто-то это будет редактировать под vi через ssh

Гм, это какой-то каменный век хотя может быть в erlang исходный код хранится рядом с бинарным?
В Java же ни на тестовом, ни на производственном сервере никаких java файлов и не будет — нечего редактировать.
Я уж молчу, что как правило у разработчиков отсутствует доступ к развертыванию не то что на производственный, но даже и на тестовый сервер.
Re[24]: Действительно ли ML языки хороши в компиляторописани
От: SmbdRsdn  
Дата: 28.04.08 12:01
Оценка: :)
Здравствуйте, Cyberax, Вы писали:

C>Нельзя.

То нельзя, то можно.

C>Тонны кода.

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

C>Нет, это было удивление. Я прекрасно знаю как сейчас работают Java IDE (чай не зря 8 лет на Java пишу...).

И что же вас удивило в генерации кода на IDE?

C>Ага. Только и получаются тонны ненужного кода в результате.

Если ненужного зачем генерировать?
Re[23]: Действительно ли ML языки хороши в компиляторописани
От: Mamut Швеция http://dmitriid.com
Дата: 28.04.08 12:34
Оценка: +1
M>>Птаница в незнакомом синтаксисе просто произошла
SR>Кортеж или список это примерно одно и тоже, с точки зрения сопоставления с образцом.

Ту хум хао, как говорится

M>>Таким образом,

M>>
M>>match({a, b, c})
M>>


M>>это сопоставление с экземпляром класса типа

SR>Кортеж, я так понимаю, отдельный тип, а не любой класс с полями.

Чем класс не тип?


M>>
M>>class Elem {
M>>  a;
M>>  b;
M>>  c;
M>>}
M>>

SR>И сопоставлять должно что-то в духе — match(Elem(a,b,c))
SR>Иначе возникает очевидная путаница между классами у которых одинаковые внутренние типы, например Add и Sum.


Что-то в духе? Что будет сопоставлять? Кто будет писать эту функцию match?

M>>где a, b, c — это поля произвольного типа


M>>поэтому все остальное поскипано, потому что мы возвращаемся к коду из первого примера:

SR>Зачем возвращаемся не понятно. Код сопоставления к этому примеру я уже приводил.

Еще раз.

На пример
def simplify(term: Term) = term match {
  case Mul(Num(0), x) => Num(0)
  case Mul(Num(1), x) => x
  case _ => term
}


Был приведен псевдо код с неким term.equals, причем кто будет писать этот equals — непонятно. Предполагается, что IDE

На пример
match(Field)
match({Field, {Func, Value})
match({Field, {'=', Value}})


был приведен совсем другой код, разбирающи списки


На пример
{ok, {{Version, 200, ReasonPhrase}, Headers, Body}}


будет приведена совсем третья функция, разбирающая эту структуру.



И каждй раз программисту (особенно новому) придется разбираться — что делает тот или иной цикл, те десять функций equals, тот десяток методов matches и т.п.

Это мы еще про байндинг переменных не упомянули.
... << RSDN@Home 1.2.0 alpha 4 rev. 1084>>


dmitriid.comGitHubLinkedIn
Re[21]: Действительно ли ML языки хороши в компиляторописани
От: Tonal- Россия www.promsoft.ru
Дата: 28.04.08 18:03
Оценка: 30 (1) +2
Здравствуйте, SmbdRsdn, Вы писали:

Давай таки по чесному сравним не только два этих отрывка кода, но и то, что за ними стоит

Мелкий ликбез по Erlang-у:
Атомы всегда начинаются с маленькой буквы — это просто имена. Больше всего похожи на перечисления в С++
Переменные начинаются с большой буквы.
Запись [H|T] означает: список из головы H и хвоста T, где T может быть любым списком, в том числе и пустым.
Для кортежей {...} такой синтаксис не возможен.
Запись [H] означает список из одного элемента H

M>>
M>>case input_data of
M>>    [{elem1, elem2}|T] -> сделаем что-то одно
M>>    [[L]|T] -> разбираем вложенный список
M>>    {a, b} -> а ждесь вообще не список, оппаньки
M>>    {[H|T], [H2|T2]} -> и здесь не список передали. но внутри список
M>>    {a, {b, {c, d}}} -> здесь списком даже и не пахнет, но все разобрали
M>>    {_, _, _, _, x} -> нам важен только 5-й параметр, хотя струкутра может быть такой:
M>>    {{a, b, c}, [H|T], {[H2|T2]}, d, e} -> и все равно мы ее сможем разобрать
M>>end
M>>

Это вполне законченный кусок кода.
Т.е. вместо русских комментариев после -> можно написать любое допустимое выражение Erlang-а
Кроме того, можно дописать сколько угодно условий, с какими угодно образцами.
Можно дописать условие, которое будет совпадать в том случае, если ни один другой образец не совпал.
И input_data и совпавшие литералы и забинденные переменные могут быть любого допустимого в Erlang-е типа: числом, сторокой, атомом, кортежем, списком, записью и т.д.
Т.о. код не накладывает никаких требований на типы элементов, с которыми мы тут работаем.

SR>
SR>if (data.matches(list(elem1, elem2), T))
SR>if (data.matches(list(L), T))
SR>if (data.matches(a, b)
SR>if (data.matches(list(H, T), list(H2, T2))
SR>if (data.matches(a, list(b, list(c, d)))
SR>if (data.matches(_, _, _, _, x))
SR>if (data.matches(list(a, b, c), list(H, T), list(list(H2, T2), d, e)))
SR>

Какого здесь типа будет data — у него как минимум должна быть реализована matches. Т.е. сразу ограничение в сравнении с вариантом Erlang-а
Ладно, давай предположим, что у нас есть некоторый класс PMatcher с функцией matches, которая, принимает 2 параметра, данные и паттерн, в результате выдаёт совпало/несовпало и биндит переменные указанные в шаблоне.
Данные понятно — Оbject — чтобы можно было любой тип подавать.
Отрывок под это дело переписывается элементарно.
Мы не будем придираться, что этот класс и его функцию matches нужно как-то реализовывать и это точно займёт не 2-3 строки. Ведь и в Erlang-е PM не по волшебству берётся.
Лучше посмотрим во что выливаются остальные требования.
Ну про данные понятно — они должны быть любые.
Теперь про шаблон — как его можно записать?
Попробуем создавать структуры-шаблоны. Причём, мы хотим от шаблонов как можно большей естественности — т.е. чтобы они как можно меньше отличались от кода, который мы пишем создавая наши структуры.
С константами вроде проблем нет.
А вот с массивами уже есть: предположим мы хотим нарисовать такой шаблон для массива целых, из 3х элементов, где первый нам не важен (_), второй всегда равен 2 а третий сбиндить в указанную переменную...
Кажется придётся отказатся от массивов, всё равно нормальные пацаны используют коллекции...
Едем дальше — Классы.
Значит как минимум одно требование у нас есть — в классе должен быть реализован некий метод equals который, как я понимаю, осушествляет глубокое сравнение с учётом биндинга и пропусков (_).
Ок. Расширяем Эклипс или НетБинс чтоб она за нас его рисовала.
Но этот код уже таки нужно учитывать — т.к. нам таки приходится изменять классы под PM.
Опять же, пусть есть класс:
class Elem {
  public int a;
  public double b;
  public string c;
  Elem(int aa, double bb, string cc) {a = aa; b = bb; c = cc;}
}

Хотим написать шпблон, где поле a нас не интересует, поле b должно быть 3.14, а поле c сбиндить в указанную переменную...
Если мы хотим, чтобы шаблон создавался таким же кодом, как и обычные структуры, то очевидно, здесь нужно менять типы, т.е. вместо int, double, string ставить Object.
Очевидно, что с таким классом будет изрядно неудобно работать в остальных местах.
Кроме того, в этом случае нельзя будет работать с классами, написанными не нами...

Значит такой способ задания шаблона не катит. Попробуем по другому: для каждого интересующего нас класса можно создать PM-двойника, который бы мы использовали при задании шаблонов. Этим кстати можно даже обойти проблему с массивами.
Наверное тоже можно нагнуть Эклипс и несколькими щелчками получить двойника заданного класса. Правда остаётся неприятная проблема с типизацией. Да и код от этих двойников раздувается...

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

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

P.S. С Java разбирался довольно давно. Поэтому, если кто-нибудь расскажет как обойти эти проблемы, с кодом, за которым понятно что стоит, буду признателен.
Только почему-то кажется, что таки легче скалу взять.
P.P.S. А ты правда правда считаешь что куски эквивклетны по понятности/объёму, или просто отстаиваешь любимый язык?
Несколько месяцев назад я примерно с такими же доводами выступал. Правда в качестве псевдокода использовал С++.
... << RSDN@Home 1.2.0 alpha 4 rev. 1065>>
Re[24]: Действительно ли ML языки хороши в компиляторописани
От: SmbdRsdn  
Дата: 28.04.08 21:16
Оценка:
Здравствуйте, WolfHound, Вы писали:

SR>>Может быть покажете свою мощь на уже выложенных мной примерах?

WH>Примеры без того что их исполняет не имеют смысла ибо это не болие чем псевдокод и работать они не могут.
Определение псевдокода в студию! Или это всего лишь треп?
Большинство остальных оппонентов скорее согласны, что код работать может, но будет много кода илл он его применение будет сильно рассогласовано.

WH>Компилятор действовал в условиях полной определенности.

Что мешает компилятору и тут действовать в условиях полной определенности?

WH>А тут переменные объявляют.

WH>Это не бейсик какойнибуть где переменные объявляются при первом обращении.
WH>Тут объявление явное.
WH>Главное что переменные всегда объявляются явно.
Вот-вот — явно. А не в середине или в конце набора скобок, групповых символов, имен классов, строковых, числовых и логических литералов.

WH>Синтаксис дело десятое.

Может быть для Lisp так и есть.

WH>Или таки все это пустой треп?

Конечно пустой, странно, что вы это так долго до этого доходили.
Re[24]: Действительно ли ML языки хороши в компиляторописани
От: SmbdRsdn  
Дата: 28.04.08 21:29
Оценка:
Здравствуйте, Mamut, Вы писали:

M>Чем класс не тип?

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

M>Что-то в духе? Что будет сопоставлять?

Это такие выражения в русском языке.

M>Кто будет писать эту функцию match?

А кто до этого писал? Имя match у вас же возникает, я просто заменил образец, то есть параметр функции.
Если бы я приводил пример на Java, то использовал бы new Elem(a, b, c).

M>Еще раз.


M>На пример

M>
M>def simplify(term: Term) = term match {
M>  case Mul(Num(0), x) => Num(0)
M>  case Mul(Num(1), x) => x
M>  case _ => term
M>}
M>


M>Был приведен псевдо код с неким term.equals, причем кто будет писать этот equals — непонятно. Предполагается, что IDE.



M>На пример

M>
M>match(Field)
M>match({Field, {Func, Value})
M>match({Field, {'=', Value}})
M>


M>был приведен совсем другой код, разбирающи списки

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

M>На пример

M>
M>{ok, {{Version, 200, ReasonPhrase}, Headers, Body}}
M>


M>будет приведена совсем третья функция, разбирающая эту структуру.

Для второго и третьего примера функция одна как я уже писал. validate и проход по циклу использовался для уточнения условий задачи.

M>И каждй раз программисту (особенно новому) придется разбираться — что делает тот или иной цикл, те десять функций equals, тот десяток методов matches и т.п.

Гм, зачем разбираться? Цикла вообще нет, функции equals тривиальны и многократно описаны до какого-бы-то-нибыло сопоставления с образцом, метод matches тоже один. Странно, что вы не видите, что все это можно легко привести к одному виду.

M>Это мы еще про байндинг переменных не упомянули.

Почему, кстати? Связывание я приводил со своего первого примера.
Re[25]: Действительно ли ML языки хороши в компиляторописани
От: Mamut Швеция http://dmitriid.com
Дата: 28.04.08 21:35
Оценка:
M>>И каждй раз программисту (особенно новому) придется разбираться — что делает тот или иной цикл, те десять функций equals, тот десяток методов matches и т.п.
SR>Гм, зачем разбираться? Цикла вообще нет, функции equals тривиальны и многократно описаны до какого-бы-то-нибыло сопоставления с образцом, метод matches тоже один. Странно, что вы не видите, что все это можно легко привести к одному виду.

Пока этого одного вида пока никто так и не увидел


M>>Это мы еще про байндинг переменных не упомянули.

SR>Почему, кстати? Связывание я приводил со своего первого примера.

Где он был не совсем корректным и не соответствовал условиям задачи.

Кстати, насчет связывания переменных.

[{elem1, elem2}|T]

data.matches(list(elem1, elem2), T)

Что такое T в примере на Java, и откуда оно взялось?
... << RSDN@Home 1.2.0 alpha 4 rev. 1084>>


dmitriid.comGitHubLinkedIn
Re[22]: Действительно ли ML языки хороши в компиляторописани
От: SmbdRsdn  
Дата: 28.04.08 22:06
Оценка:
Здравствуйте, Tonal-, Вы писали:

T>Давай таки по чесному сравним не только два этих отрывка кода, но и то, что за ними стоит


T>Мелкий ликбез по Erlang-у:

Замечу все-таки, что начинал я сравнение не с erlang'ом, а со Scala.
Конечно, мне бы хотелось и продолжать сравнивать со Scala, но возражающие мне в основном используют erlang.
А вникать в отдельный язык ФП с его тонкостями желания нет, поэтому думаю, что непонимания с обеих сторон будет еще немало.

T>Атомы всегда начинаются с маленькой буквы — это просто имена. Больше всего похожи на перечисления в С++

T>Переменные начинаются с большой буквы.
T>Запись [H|T] означает: список из головы H и хвоста T, где T может быть любым списком, в том числе и пустым.
T>Для кортежей {...} такой синтаксис не возможен.
T>Запись [H] означает список из одного элемента H

M>>>
M>>>case input_data of
M>>>    [{elem1, elem2}|T] -> сделаем что-то одно
M>>>    [[L]|T] -> разбираем вложенный список
M>>>    {a, b} -> а ждесь вообще не список, оппаньки
M>>>    {[H|T], [H2|T2]} -> и здесь не список передали. но внутри список
M>>>    {a, {b, {c, d}}} -> здесь списком даже и не пахнет, но все разобрали
M>>>    {_, _, _, _, x} -> нам важен только 5-й параметр, хотя струкутра может быть такой:
M>>>    {{a, b, c}, [H|T], {[H2|T2]}, d, e} -> и все равно мы ее сможем разобрать
M>>>end
M>>>

T>Это вполне законченный кусок кода.
T>Т.е. вместо русских комментариев после -> можно написать любое допустимое выражение Erlang-а
T>Кроме того, можно дописать сколько угодно условий, с какими угодно образцами.
T>Можно дописать условие, которое будет совпадать в том случае, если ни один другой образец не совпал.
T>И input_data и совпавшие литералы и забинденные переменные могут быть любого допустимого в Erlang-е типа: числом, сторокой, атомом, кортежем, списком, записью и т.д.
T>Т.о. код не накладывает никаких требований на типы элементов, с которыми мы тут работаем.

SR>>
SR>>if (data.matches(list(elem1, elem2), T))
SR>>if (data.matches(list(L), T))
SR>>if (data.matches(a, b)
SR>>if (data.matches(list(H, T), list(H2, T2))
SR>>if (data.matches(a, list(b, list(c, d)))
SR>>if (data.matches(_, _, _, _, x))
SR>>if (data.matches(list(a, b, c), list(H, T), list(list(H2, T2), d, e)))
SR>>

T>Какого здесь типа будет data — у него как минимум должна быть реализована matches. Т.е. сразу ограничение в сравнении с вариантом Erlang-а
Смешное возражение, data должна иметь matches только для более понятной инфиксной записи, в противном случае можно записать if (matches(data, pattern)).

T>Ладно, давай предположим, что у нас есть некоторый класс PMatcher с функцией matches, которая, принимает 2 параметра, данные и паттерн, в результате выдаёт совпало/несовпало и биндит переменные указанные в шаблоне.

T>Данные понятно — Оbject — чтобы можно было любой тип подавать.
T>Отрывок под это дело переписывается элементарно.
T>Мы не будем придираться, что этот класс и его функцию matches нужно как-то реализовывать и это точно займёт не 2-3 строки. Ведь и в Erlang-е PM не по волшебству берётся.
T>Лучше посмотрим во что выливаются остальные требования.
T>Ну про данные понятно — они должны быть любые.
T>Теперь про шаблон — как его можно записать?
T>Попробуем создавать структуры-шаблоны. Причём, мы хотим от шаблонов как можно большей естественности — т.е. чтобы они как можно меньше отличались от кода, который мы пишем создавая наши структуры.
T>С константами вроде проблем нет.
T>А вот с массивами уже есть: предположим мы хотим нарисовать такой шаблон для массива целых, из 3х элементов, где первый нам не важен (_), второй всегда равен 2 а третий сбиндить в указанную переменную...
new Object[] {_, 2, x}

T>Кажется придётся отказатся от массивов, всё равно нормальные пацаны используют коллекции...
Отказ от массивов не понятен.
T>Едем дальше — Классы.
T>Значит как минимум одно требование у нас есть — в классе должен быть реализован некий метод equals который, как я понимаю, осушествляет глубокое сравнение с учётом биндинга и пропусков (_).
T>Ок. Расширяем Эклипс или НетБинс чтоб она за нас его рисовала.
T>Но этот код уже таки нужно учитывать — т.к. нам таки приходится изменять классы под PM.
Код можно и не писать, я уже приводил пример, вполне можно расширить компилятор.
abstract class Term {};
final class Num extends Term {};
final class Var extends Term {};

@PatternMatching
Term simplify(Term term) {
  if (term.equals(new Num(1))) {
  }
}

И этот компилятор может например добавить необходимый equals в классы, либо переписать simplify на if (term instanceof Num) и т.д.

T>Значит такой способ задания шаблона не катит. Попробуем по другому: для каждого интересующего нас класса можно создать PM-двойника, который бы мы использовали при задании шаблонов. Этим кстати можно даже обойти проблему с массивами.

Я как раз и приводил код с созданием двойников _Term, _Num и .т.д. Но это для кода работающего здесь и сейчас.

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

Не очень понятно, почему беспокоит раздутие кода, если это отдельные классы. Они могут даже отсутствовать в проекте в виде java файлов, сразу в виде class на какой-либо из стадий сборки. Например по WSDL создается весьма объемный код, который не замедляет восприятие всего проекта отдельным разработчиком.

T>Получается, что общий код для поддержки твоего псевдокода по объёму его сильно превосходит, без учёта самого движка сопоставления.

В случае equals и движка-то никакого не надо.
А в случае списков, кортежей нет и общего кода для поддержки.

T>Кстати, а куда будем учитывать плагины которые тоже нужно писать и поддерживать?

А куда будем учитывать код затраченный на поддержку PM в Scala?

T>P.P.S. А ты правда правда считаешь что куски эквивклетны по понятности/объёму, или просто отстаиваешь любимый язык?

Куски очевидно не равны по объему и по понятности, но близки, правда это в коде, который приводил я.
А вот в первом сообщении на которое я отвечал, объемы различались чуть ли не в десятки раз.
Язык Java не является моим любимым.
T>Несколько месяцев назад я примерно с такими же доводами выступал. Правда в качестве псевдокода использовал С++.
Это не псевдокод, повторяю в который раз.
Re[25]: Действительно ли ML языки хороши в компиляторописани
От: Cyberax Марс  
Дата: 28.04.08 22:39
Оценка:
Здравствуйте, SmbdRsdn, Вы писали:

C>>Тонны кода.

SR>Если под тонной понимать тысячу строк, то это в современных условиях ерунда.
SR>Вот если бы речь шла о мегатоннах.
SR>Да и то, достоточно посчитать количество строк в JDK, а люди, тем не менее его легко используют.
Мне плевать сколько кода в JDK. Я его не отлаживаю.

Но мне совсем не плевать, сколько кода придётся читать лично мне.

C>>Нет, это было удивление. Я прекрасно знаю как сейчас работают Java IDE (чай не зря 8 лет на Java пишу...).

SR>И что же вас удивило в генерации кода на IDE?
Меня удивило, что это считается большим плюсом...

C>>Ага. Только и получаются тонны ненужного кода в результате.

SR>Если ненужного зачем генерировать?
Так как в языке нет средств, чтобы этого избежать.
Sapienti sat!
Re[25]: Действительно ли ML языки хороши в компиляторописани
От: WolfHound  
Дата: 29.04.08 10:03
Оценка:
Здравствуйте, SmbdRsdn, Вы писали:

SR>Определение псевдокода в студию!

Хрень похожая на код но которую нельзя запустить на исполнение.
И пока ты не приведешь тот код который может может оживить твои примерчики они останутся псевдокодом.

SR>Большинство остальных оппонентов скорее согласны, что код работать может, но будет много кода илл он его применение будет сильно рассогласовано.

Еще раз. Я могу придумать сотни вариантов того что делает вид что работает.

SR>Что мешает компилятору и тут действовать в условиях полной определенности?

То что ее нет.

SR>Вот-вот — явно. А не в середине или в конце набора скобок, групповых символов, имен классов, строковых, числовых и логических литералов.

Я думаю умные люди уже поняли чем отличается явное объявление переменной внутри match'а от неявного объявления переменной в какомнибудь позорном васике.

SR>Может быть для Lisp так и есть.

Причем тут лисп? Не меняй тему.

SR>Конечно пустой, странно, что вы это так долго до этого доходили.

Я понял это с первого поста.
Просто ты тут развел кучу демагогии на которую могли повестись мение опытные люди.
... << RSDN@Home 1.2.0 alpha rev. 745>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[26]: Действительно ли ML языки хороши в компиляторописани
От: SmbdRsdn  
Дата: 29.04.08 13:25
Оценка:
Здравствуйте, Mamut, Вы писали:

M>Пока этого одного вида пока никто так и не увидел

Так и общего кода на одном языке (желательно на Scala) тоже не приводилось.

M>Где он был не совсем корректным и не соответствовал условиям задачи.

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

M>Кстати, насчет связывания переменных.


M>
M>[{elem1, elem2}|T]
M>

M>
M>data.matches(list(elem1, elem2), T)
M>

M>Что такое T в примере на Java, и откуда оно взялось?
Tail T = new Tail();
class Tail {
  public object[] value;
}
Re[26]: Действительно ли ML языки хороши в компиляторописани
От: SmbdRsdn  
Дата: 29.04.08 13:36
Оценка:
Здравствуйте, Cyberax, Вы писали:

C>Мне плевать сколько кода в JDK. Я его не отлаживаю.

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

C>Меня удивило, что это считается большим плюсом...

По вашему большим плюсом было бы отсутствие кодогенерации в IDE?
Re[27]: Действительно ли ML языки хороши в компиляторописани
От: WolfHound  
Дата: 29.04.08 13:45
Оценка: +7
Здравствуйте, SmbdRsdn, Вы писали:

SR>По вашему большим плюсом было бы отсутствие кодогенерации в IDE?

Несомненно.
Это не дело IDE код генерировать.
Это работа компилятора.
... << RSDN@Home 1.2.0 alpha rev. 745>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[26]: Действительно ли ML языки хороши в компиляторописани
От: SmbdRsdn  
Дата: 29.04.08 13:54
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>И пока ты не приведешь тот код который может может оживить твои примерчики они останутся псевдокодом.

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

SR>>Большинство остальных оппонентов скорее согласны, что код работать может, но будет много кода илл он его применение будет сильно рассогласовано.

WH>Еще раз. Я могу придумать сотни вариантов того что делает вид что работает.
Если нечто выглядит как утка, крякает как утка и ходит как утка — наверное утка и есть.

SR>>Что мешает компилятору и тут действовать в условиях полной определенности?

WH>То что ее нет.
Подскажем аннотоцией недостающую определенность, делов-то.

WH>Я думаю умные люди уже поняли чем отличается явное объявление переменной внутри match'а от неявного объявления переменной в какомнибудь позорном васике.

Понять-то поняли, явность объявления под вопросом.
function a
  x = 1 * 2 * 3
  a = x * 2
end function

vs
Mul(Mul(Num(1), Num(2)), Num(x)) -> 2 * x


SR>>Может быть для Lisp так и есть.

WH>Причем тут лисп? Не меняй тему.
Притом что:
WH>Синтаксис дело десятое.
Говорят, что синтаксис не имеет значения для Lisp.
Возможно поэтому этот язык программироания не является достаточно понятным.

WH>Просто ты тут развел кучу демагогии на которую могли повестись мение опытные люди.

Чтобы пресечь подобное тут и находятся на дежурстве такие люди как вы.
Re[26]: Действительно ли ML языки хороши в компиляторописани
От: FR  
Дата: 29.04.08 13:59
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>Просто ты тут развел кучу демагогии на которую могли повестись мение опытные люди.


Я читаю и вообще фигею, ладно я с вашей групой ругался по общеидеологическим ссображения и плюс у вас был период необоснованного воспевания PM, но я хоть признавал преимущества PM, тут же я вообще не понимаю смысла всей этой дискуссии
Re[28]: Действительно ли ML языки хороши в компиляторописани
От: SmbdRsdn  
Дата: 29.04.08 14:00
Оценка:
Здравствуйте, WolfHound, Вы писали:

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


SR>>По вашему большим плюсом было бы отсутствие кодогенерации в IDE?

WH>Несомненно.
WH>Это не дело IDE код генерировать.
WH>Это работа компилятора.
Как думаете Eclipse само код генерит или при помощи компилятора?
Re[27]: Действительно ли ML языки хороши в компиляторописани
От: Курилка Россия http://kirya.narod.ru/
Дата: 29.04.08 14:01
Оценка: +2
Здравствуйте, FR, Вы писали:

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


WH>>Просто ты тут развел кучу демагогии на которую могли повестись мение опытные люди.


FR>Я читаю и вообще фигею, ладно я с вашей групой ругался по общеидеологическим ссображения и плюс у вас был период необоснованного воспевания PM, но я хоть признавал преимущества PM, тут же я вообще не понимаю смысла всей этой дискуссии


Ты надеешься ещё его тут найти? :
По-моему всё ещё с самого начала было ясно: некоторые предпочитают "закат солнца вручную", другие же просто пользуются удобным инструментом по назначению.
Re[27]: Действительно ли ML языки хороши в компиляторописани
От: WolfHound  
Дата: 29.04.08 14:19
Оценка: -1
Здравствуйте, SmbdRsdn, Вы писали:

SR>Навыки начинающего Java программиста действительно непросто передать через форум.

Ой какие мы важные.

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

Если все так просто то что же ты так и не привел код?
Он же простой и уже написан.

SR>Если нечто выглядит как утка, крякает как утка и ходит как утка — наверное утка и есть.

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

SR>Подскажем аннотоцией недостающую определенность, делов-то.

Полный код в студию.

WH>>Я думаю умные люди уже поняли чем отличается явное объявление переменной внутри match'а от неявного объявления переменной в какомнибудь позорном васике.

SR>Понять-то поняли, явность объявления под вопросом.
Ну если ты не в состоянии отличить объявление при первом использовании и объявление в паттерне то тебе ничем не помоч.
Разница меж тем существенна.
Если ты в васике в одном месте напишешь dashfgflodhbflkjzhxvcb, а в другом dashfgflodhblfkjzhxvcb васик и слова не скажет.
А если тоже самое сделать в скале то получишь по рукам от компилятора.

SR>Говорят, что синтаксис не имеет значения для Lisp.

Ну еще на заборе всякую фигню пишут.
В любом случае не меняй тему.

WH>>Просто ты тут развел кучу демагогии на которую могли повестись мение опытные люди.

SR>Чтобы пресечь подобное тут и находятся на дежурстве такие люди как вы.
Хочешь чтобы я удалил все твои сообщения и отправил в баню за попытку ввести людей в заблуждение?
Это можно устроить.
... << RSDN@Home 1.2.0 alpha rev. 745>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[29]: Действительно ли ML языки хороши в компиляторописани
От: WolfHound  
Дата: 29.04.08 14:32
Оценка:
Здравствуйте, SmbdRsdn, Вы писали:

SR>Как думаете Eclipse само код генерит или при помощи компилятора?

Детали.
Главное чтобы код который я пишу был самодостаточным и не требовал помощи IDE для того чтобы он начал работать.
... << RSDN@Home 1.2.0 alpha rev. 745>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[27]: Действительно ли ML языки хороши в компиляторописани
От: Mamut Швеция http://dmitriid.com
Дата: 29.04.08 14:47
Оценка: 13 (1) +1
M>>Пока этого одного вида пока никто так и не увидел
SR>Так и общего кода на одном языке (желательно на Scala) тоже не приводилось.

Какой общий код? При поддержке ПМа языком, любой код, его использующий, будет более-менее общим

Если поддержки ПМа нет, то при


M>>Где он был не совсем корректным и не соответствовал условиям задачи.

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

Байндились ненужные переменные


M>>Кстати, насчет связывания переменных.


M>>
M>>[{elem1, elem2}|T]
M>>

M>>
M>>data.matches(list(elem1, elem2), T)
M>>

M>>Что такое T в примере на Java, и откуда оно взялось?
SR>
SR>Tail T = new Tail();
SR>class Tail {
SR>  public object[] value;
SR>}
SR>


чаво чаво? T у нас может быть любым объектом — списком, кортежем, классом, встроенным типом и т.п.

Более того, этот T мы можем сразу взять и использовать дальше — в последующих сопоставлениях или сразу по назначению:

match_list([H|T]) ->
    case T of 
        1 -> что-то делаем
        "text" -> делаем что-то еще
        какая-то_сложная_структура -> делаем что-то третье
        _ -> нас вообще T не интересует, работаем с H


Вот из примеров на Scala:
object MatchTest2 extends Application {
  def matchTest(x: Any): Any = x match {
    case 1 => "one"
    case "two" => 2
    case y: Int => "scala.Int"
  }
  println(matchTest("two"))
}


Ключевой момент — в выделенном. Тут мы создаи и заюзали переменную y встроенного типа Int. А могли бы дополнить:
    case z: MyClass => z.MyMethod(); z.field1 = 2;



И вообще — здесь, ответ на аргумент "Pattern matching is unnecessary" а также отсюда

Scala Pattern Matching = Visitor

Scala Pattern Matching from a Java perspective и особенно:
// The simple type match pattern

object MySingleton
val single = MySingleton
single match {case _:MySingleton.type => println("OK")}



Scala for Java Refugees Part 4: Pattern Matching and Exceptions, особенно
class Color(val red:Int, val green:Int, val blue:Int)
 
case class Red(r:Int) extends Color(r, 0, 0)
case class Green(g:Int) extends Color(0, g, 0)
case class Blue(b:Int) extends Color(0, 0, b)
 
def printColor(c:Color) = c match {
  // байндинг переменной
  case Red(v) => println("Red: " + v)
  case Green(v) => println("Green: " + v)
  case Blue(v) => println("Blue: " + v)
 
    // проверка на тип и байндинг переменной
  case col:Color => {
    print("R: " + col.red + ", ")
    print("G: " + col.green + ", ")
    println("B: " + col.blue)
  }
 
  case null => println("Invalid color")
}
 
printColor(Red(100))
printColor(Blue(220))
 
printColor(new Color(100, 200, 50))
printColor(null)





Ну и где же пресловутая всеобщая функция, которая:

— сможет разобрать тип передаваемых данных
— сами данные
— забайндить переменные по желанию программиста?


С ПМ'ом о таких мелочах не надо думать. Тебе нужно узнать структуру данных? Тип данных? Ты так и пишешь: "хочу структуру. хочу тип. хочу это все в куче переменных, чтобы сотни раз не писать var x = Elem.field1"
... << RSDN@Home 1.2.0 alpha 4 rev. 1084>>


dmitriid.comGitHubLinkedIn
Re[23]: Действительно ли ML языки хороши в компиляторописани
От: Tonal- Россия www.promsoft.ru
Дата: 29.04.08 15:26
Оценка: 14 (1)
Здравствуйте, SmbdRsdn, Вы писали:
T>>Мелкий ликбез по Erlang-у:
SR>Замечу все-таки, что начинал я сравнение не с erlang'ом, а со Scala.
SR>Конечно, мне бы хотелось и продолжать сравнивать со Scala, но возражающие мне в основном используют erlang.
SR>А вникать в отдельный язык ФП с его тонкостями желания нет, поэтому думаю, что непонимания с обеих сторон будет еще немало.
В свою очередь не знаю скалы, а по erlang-у прочитал несколько статеек.
Но по ответам, мне показалось, что некоторые синтаксические конструкции не всем очивидны.

T>>А вот с массивами уже есть: предположим мы хотим нарисовать такой шаблон для массива целых, из 3х элементов, где первый нам не важен (_), второй всегда равен 2 а третий сбиндить в указанную переменную...

SR>
SR>new Object[] {_, 2, x}
SR>

Как будем различать массивы интов, даблов и собственно Object-ов?

T>>Но этот код уже таки нужно учитывать — т.к. нам таки приходится изменять классы под PM.

SR>Код можно и не писать, я уже приводил пример, вполне можно расширить компилятор.
SR>
SR>abstract class Term {};
SR>final class Num extends Term {};
SR>final class Var extends Term {};

SR>@PatternMatching
SR>Term simplify(Term term) {
SR>  if (term.equals(new Num(1))) {
SR>  }
SR>}
SR>

SR>И этот компилятор может например добавить необходимый equals в классы, либо переписать simplify на if (term instanceof Num) и т.д.
Вот про это тебе и говорят "псевдокод". То что можно построить некий тул, который будет переписывать АСД никто не сомнивается.
Но ведь его нет — стало быть и код нельзя ни выполнить ни проверить его корректность.
Кроме того, раз уж мы взялиcь перекраивать АСД, то можем выбрать и более явный код чем какскд if-ов, например switch/case:
@PatternMatching
void matches(data) {
  switch(data) {
    case list(elem1, elem2), T: {...};
    case list(L), T: {...};
    case a, b: {...};
    case list(H, T), list(H2, T2): {...};
    case a, list(b, list(c, d)): {...};
    case _, _, _, _, x: {...};
    case list(a, b, c), list(H, T), list(list(H2, T2), d, e): {...};
  }
}

При этом, PM-компилятор автоматом объявит все нужные для связывания переменные, и проведёт остальные нужные преобразования.

T>>Значит такой способ задания шаблона не катит. Попробуем по другому: для каждого интересующего нас класса можно создать PM-двойника, который бы мы использовали при задании шаблонов. Этим кстати можно даже обойти проблему с массивами.

SR>Я как раз и приводил код с созданием двойников _Term, _Num и .т.д. Но это для кода работающего здесь и сейчас.
T>>Наверное тоже можно нагнуть Эклипс и несколькими щелчками получить двойника заданного класса. Правда остаётся неприятная проблема с типизацией. Да и код от этих двойников раздувается...
SR>Не очень понятно, почему беспокоит раздутие кода, если это отдельные классы. Они могут даже отсутствовать в проекте в виде java файлов, сразу в виде class на какой-либо из стадий сборки. Например по WSDL создается весьма объемный код, который не замедляет восприятие всего проекта отдельным разработчиком.
Таки есть для такого решения несколько неочевидных вещей:
Где, в каком пакете, эти невидимые класс-файлы будут распологаться?
В том где мы решили использовать @PatternMatching? — тогда очевидно мы получим дублирование при использовании PM чужих классов.
Можно предварительно искать — есть ли уже сгенерённые двойники в пакетах используемых классов. Или в наших родительских.
Идеальное решение — сразу создавать вместе с классом их PM-двойников, а двойников стандартных типов запихать в библиотеки рантайма.
Кроме того, что с отладкой будем делать?

T>>Получается, что общий код для поддержки твоего псевдокода по объёму его сильно превосходит, без учёта самого движка сопоставления.

SR>В случае equals и движка-то никакого не надо.
SR>А в случае списков, кортежей нет и общего кода для поддержки.
В erlang-е, проверяется непротиворечивость и полнота шаблонов. Думаю в скале тоже.
Кроме того, по шаблонам строится некий вычислитель (конечный автомат?) и собственно распознавание выполняется гораздо быстрее, чем последовательное тестирование каждого шаблона.

T>>Кстати, а куда будем учитывать плагины которые тоже нужно писать и поддерживать?

SR>А куда будем учитывать код затраченный на поддержку PM в Scala?
Ну, вот, мы уже и придумали некоторый кусок скалы.
Т.е. раз уж мы начали менять АСД и рантайм для работы с PM, почему не пойти дальше, и не включить например списковые дополнения или вывод типов?
К тому же оба нам всё равно понадобятся для нормального PM — мы ведь хотим удобства — значит типизация связываемых переменных — забота компилятора, да и возможность указывать только нужную часть массива или контейнера, какой бы он не был длинны — тоже очень удобная штука, особенно если мы хотим хвост сбиндить и тоже обработать.
Вполне возможно, для поддержки этого потребуется ещё что-то выносить на уровень рантайма...

Идём далее — у нас теперь получается язык с 2мя разными семантиками — одна, новая, работает в функциях отмеченных тагом @PatternMatching, другая, старая, во всех остальных местах.
Что не есть гуд — т.к. об этом надо постоянно помнить, и нельзя просто взять какой-то кусок кода — нужно указывать из какой он функции, отмеченной или нет.
Кроме того, все эти фичи довольно удобны — стало быть при работе с таким языком многие начнут просто сразу помечать все функции этим тегом а уж дальше разбираться нужен он реально или нет.
Стало быть проще сразу обрабатывать этим тулзом все функции и не париться.

Вот у нас и получился новый язык программирования, со своей семантикой и таким же как у java синтаксисом.
Но синтаксис нас всё же ограничивает. В java мы не можем работать с переменноё без объявления её типа, а хотелось бы, ведь у нас уже есть вывод типов. Да и списковые дополнения хотелось бы использовать не только для описания шаблонов а и для конструирования массивов и других контейнеров.

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

T>>P.P.S. А ты правда правда считаешь что куски эквивклетны по понятности/объёму, или просто отстаиваешь любимый язык?

SR>Куски очевидно не равны по объему и по понятности, но близки, правда это в коде, который приводил я.
SR>А вот в первом сообщении на которое я отвечал, объемы различались чуть ли не в десятки раз.
SR>Язык Java не является моим любимым.
Мне кажется, что без учёта инфроструктуры и ограничений, код получается больше как минимум в 2-3 раза для простых случаев...
... << RSDN@Home 1.2.0 alpha 4 rev. 1065>>
Re[27]: Действительно ли ML языки хороши в компиляторописани
От: Cyberax Марс  
Дата: 30.04.08 07:54
Оценка: +2
Здравствуйте, SmbdRsdn, Вы писали:

C>>Мне плевать сколько кода в JDK. Я его не отлаживаю.

SR>8 лет, говорите и не приходилось отлаживать по JDK? Кхм, кхм.
Попробуйте поставить брейкпоинт где-нибудь в java.util.collections. Запустите программу. Удивитесь.

А всё потому, что JDK в стандартной поставке не имеет отладочных символов. Их можно скачать дополнительно, но это отдельный разговор.

Так вот, код в JDK мне не приходилось отлаживать ни разу.

C>>Меня удивило, что это считается большим плюсом...

SR>По вашему большим плюсом было бы отсутствие кодогенерации в IDE?
Плюсом была бы ненужность кодогенерации.
Sapienti sat!
Re[28]: Действительно ли ML языки хороши в компиляторописани
От: SmbdRsdn  
Дата: 30.04.08 11:58
Оценка: :)
Здравствуйте, WolfHound, Вы писали:

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

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

SR>>Если нечто выглядит как утка, крякает как утка и ходит как утка — наверное утка и есть.

WH>Не разводи демагогию.
WH>Тут у нас не утки, а программная система которая должна работать четко и устойчиво.
WH>И если то что есть у тебя (если вобще есть) ломается с пол пинка то в качестве инструмента для создания промышленных систем оно ну никак не годится.
WH>А мы ведь тут говорим не о игрушках. Или как?
Кому как. Зависит от уровня разработчика.

SR>>Подскажем аннотоцией недостающую определенность, делов-то.

WH>Полный код в студию.
Недостающие определенности в студию.

WH>>>Я думаю умные люди уже поняли чем отличается явное объявление переменной внутри match'а от неявного объявления переменной в какомнибудь позорном васике.

SR>>Понять-то поняли, явность объявления под вопросом.
WH>Ну если ты не в состоянии отличить объявление при первом использовании и объявление в паттерне то тебе ничем не помоч.
Я в состоянии. Вопрос именно в объявлении. Суть объявления именно в том, чтобы сделать нечно явным.
А явность в более-менее сложном образце отсутствует.

SR>>Говорят, что синтаксис не имеет значения для Lisp.

WH>Ну еще на заборе всякую фигню пишут.
Стало быть синтаксис имеет значение даже для List?
WH>В любом случае не меняй тему.
Тема та же. С первого сравнения сопоставления с образцом в Scala и Java говорилось, что представление (синтаксис) образца имеет значение.

WH>>>Просто ты тут развел кучу демагогии на которую могли повестись мение опытные люди.

SR>>Чтобы пресечь подобное тут и находятся на дежурстве такие люди как вы.
WH>Хочешь чтобы я удалил все твои сообщения и отправил в баню за попытку ввести людей в заблуждение?
Начало проглядывать лицо садиста, которые часто общаются подобным образом:

В морду хочешь?

WH>Это можно устроить.
Впрочем, спасибо за предупреждение. На всякий случай сохранил все свои сообщения.
Re[30]: Действительно ли ML языки хороши в компиляторописани
От: SmbdRsdn  
Дата: 30.04.08 12:00
Оценка:
Здравствуйте, WolfHound, Вы писали:

SR>>Как думаете Eclipse само код генерит или при помощи компилятора?

WH>Детали.
Важные. IDE именно потому и IDE, что integrated и включает в себя компилятор.
WH>Главное чтобы код который я пишу был самодостаточным и не требовал помощи IDE для того чтобы он начал работать.
С учетом, того что в IDE имеется компилятор и именно при его помощи и создается код.
При желании именно поддержку создания кода вполне можно вынести из IDE.
Re[28]: Действительно ли ML языки хороши в компиляторописани
От: SmbdRsdn  
Дата: 30.04.08 12:23
Оценка:
Здравствуйте, Mamut, Вы писали:

SR>>Так и общего кода на одном языке (желательно на Scala) тоже не приводилось.


M>Какой общий код? При поддержке ПМа языком, любой код, его использующий, будет более-менее общим

Такой общий код. Ранее сопоставление с вариантами и со списками приводилось на двух разных языках.

M>>>Где он был не совсем корректным и не соответствовал условиям задачи.

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

M>Байндились ненужные переменные

Связывать ненужные переменные можно и в Scala, так что мимо.


M>>>Кстати, насчет связывания переменных.


M>>>
M>>>[{elem1, elem2}|T]
M>>>

M>>>
M>>>data.matches(list(elem1, elem2), T)
M>>>

M>>>Что такое T в примере на Java, и откуда оно взялось?
SR>>
SR>>Tail T = new Tail();
SR>>class Tail {
SR>>  public object[] value;
SR>>}
SR>>


M>чаво чаво? T у нас может быть любым объектом — списком, кортежем, классом, встроенным типом и т.п.

Стало быть это мне надо спрашивать?
M>>>Что такое T в примере на Scala, и откуда оно взялось?

M>Более того, этот T мы можем сразу взять и использовать дальше — в последующих сопоставлениях или сразу по назначению:

Так и в Java, неужели не видите, что раз term переменная и ее можно и использовать в соспоставлении с образцом, то и T переменная и ее тоже можно использовать далее как угодно, в том числе и при сопоставлении с образцом.

M>Ключевой момент — в выделенном. Тут мы создаи и заюзали переменную y встроенного типа Int. А могли бы дополнить:

Если нужна типизация, так в Java есть обобщенные классы. z = new Match<MyClass>().
M>
M>    case z: MyClass => z.MyMethod(); z.field1 = 2; 
M>



M>И вообще — здесь, ответ на аргумент "Pattern matching is unnecessary" а также отсюда

С обсуждения этого сообщения и началос обсуждение.

M>Scala Pattern Matching = Visitor

То же самое, что и у Одерски.

M>Scala Pattern Matching from a Java perspective и особенно:

Выше приводил пример на Java с типизацией.
M>
M>// The simple type match pattern

M>object MySingleton
M>val single = MySingleton
M>single match {case _:MySingleton.type => println("OK")}
M>



M>Scala for Java Refugees Part 4: Pattern Matching and Exceptions, особенно

Да все, примерно тоже самое.

M>Ну и где же пресловутая всеобщая функция, которая:

С чего вы взяли, что это будет одна и та же функция? Функции в Java поддерживают перегрузку параметров.
Применение функций будет выглядеть примерно одинаково.

M>- сможет разобрать тип передаваемых данных

Обобщенные классы.
M>- сами данные
Уже было.
M>- забайндить переменные по желанию программиста?
Связывание переменных уже тоже приводилось.
Re[29]: Действительно ли ML языки хороши в компиляторописани
От: WolfHound  
Дата: 30.04.08 12:34
Оценка:
Здравствуйте, SmbdRsdn, Вы писали:

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

Так собери в кучу.
Причем так чтобы компилировалось и работало.
А то потом меня начнешь обвинять в том что я что-то не так собрал.

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

WH>>И если то что есть у тебя (если вобще есть) ломается с пол пинка то в качестве инструмента для создания промышленных систем оно ну никак не годится.
WH>>А мы ведь тут говорим не о игрушках. Или как?
SR>Кому как. Зависит от уровня разработчика.
Те ты в продакшен решениях используешь то что болтается на соплях и падает при любом не осторожном движении?
Хорошь же твой уровень.

SR>Я в состоянии.

Не похоже.

SR>Вопрос именно в объявлении. Суть объявления именно в том, чтобы сделать нечно явным.

Без объявление использовать переменные нельзя.
Место объявления четко определено.
Что еще надо?

SR>А явность в более-менее сложном образце отсутствует.

Да ладно.
Особенно если учесть что мы работаем в IDE и она вполне себе раскрашивает образци.

SR>Начало проглядывать лицо садиста, которые часто общаются подобным образом:

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

Или таки приведешь код?
Или засчитать тебе давно заслуженный слив?
... << RSDN@Home 1.2.0 alpha rev. 745>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[31]: Действительно ли ML языки хороши в компиляторописани
От: WolfHound  
Дата: 30.04.08 12:36
Оценка:
Здравствуйте, SmbdRsdn, Вы писали:

SR>С учетом, того что в IDE имеется компилятор и именно при его помощи и создается код.

SR>При желании именно поддержку создания кода вполне можно вынести из IDE.
Те предлагаешь таки менять язык?
... << RSDN@Home 1.2.0 alpha rev. 745>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[24]: Действительно ли ML языки хороши в компиляторописани
От: SmbdRsdn  
Дата: 30.04.08 12:53
Оценка: -1
Здравствуйте, Tonal-, Вы писали:

T>В свою очередь не знаю скалы, а по erlang-у прочитал несколько статеек.

T>Но по ответам, мне показалось, что некоторые синтаксические конструкции не всем очивидны.
Конечно не очевидны, что естественно.

T>>>А вот с массивами уже есть: предположим мы хотим нарисовать такой шаблон для массива целых, из 3х элементов, где первый нам не важен (_), второй всегда равен 2 а третий сбиндить в указанную переменную...

SR>>
SR>>new Object[] {_, 2, x}
SR>>

T>Как будем различать массивы интов, даблов и собственно Object-ов?
Трудности с различением не очевидны.

T>>>Но этот код уже таки нужно учитывать — т.к. нам таки приходится изменять классы под PM.

SR>>Код можно и не писать, я уже приводил пример, вполне можно расширить компилятор.
SR>>
SR>>abstract class Term {};
SR>>final class Num extends Term {};
SR>>final class Var extends Term {};

SR>>@PatternMatching
SR>>Term simplify(Term term) {
SR>>  if (term.equals(new Num(1))) {
SR>>  }
SR>>}
SR>>

SR>>И этот компилятор может например добавить необходимый equals в классы, либо переписать simplify на if (term instanceof Num) и т.д.
T>Вот про это тебе и говорят "псевдокод". То что можно построить некий тул, который будет переписывать АСД никто не сомнивается.
И где это говорят про псевдокод применительно к аннотоциям? Наоборот, мне предлагают привести, код раз он уже написан.
А про аннотации и про компилятор поддерживающий их я никогда не заявлял, что они готовы.
T>Но ведь его нет — стало быть и код нельзя ни выполнить ни проверить его корректность.
T>Кроме того, раз уж мы взялиcь перекраивать АСД, то можем выбрать и более явный код чем какскд if-ов, например switch/case:
Мы, в смысле я, не можем, так как код не компилируется Java компилятором.
И что такое АСД? Можеть быть AST?
T>
T>@PatternMatching
T>void matches(data) {
T>  switch(data) {
T>    case list(elem1, elem2), T: {...};
T>    case list(L), T: {...};
T>    case a, b: {...};
T>    case list(H, T), list(H2, T2): {...};
T>    case a, list(b, list(c, d)): {...};
T>    case _, _, _, _, x: {...};
T>    case list(a, b, c), list(H, T), list(list(H2, T2), d, e): {...};
T>  }
T>}
T>

T>При этом, PM-компилятор автоматом объявит все нужные для связывания переменные, и проведёт остальные нужные преобразования.
Зачем новый язык, когда и на старом все не сильно больше? Я как раз выступал против этого.

T>Таки есть для такого решения несколько неочевидных вещей:

T>Где, в каком пакете, эти невидимые класс-файлы будут распологаться?
Посмешили, какие трудности с выбором пакета?
T>В том где мы решили использовать @PatternMatching? — тогда очевидно мы получим дублирование при использовании PM чужих классов.
При правильной обработке аннотация и классы двойники не нужны.
T>Можно предварительно искать — есть ли уже сгенерённые двойники в пакетах используемых классов. Или в наших родительских.
Двойники, как раз нужны, чтобы сопоставление работало без изменения компилятора.
T>Идеальное решение — сразу создавать вместе с классом их PM-двойников, а двойников стандартных типов запихать в библиотеки рантайма.
T>Кроме того, что с отладкой будем делать?
А что сейчас-то с отладкой, все ровно тоже самое, например при заходе в методы, которые сделаны при помощи JNI.
Как, например, производится отладка веб-служб, классы которых доступны только во время выполнения?

T>В erlang-е, проверяется непротиворечивость и полнота шаблонов. Думаю в скале тоже.

Про exhaustive уже писал.
T>Кроме того, по шаблонам строится некий вычислитель (конечный автомат?) и собственно распознавание выполняется гораздо быстрее, чем последовательное тестирование каждого шаблона.
Это опять производительность. Доводы те же.

T>Ну, вот, мы уже и придумали некоторый кусок скалы.

Вы, но не я.
T>Т.е. раз уж мы начали менять АСД
Опять АСД.
T>и рантайм для работы с PM,
Что понимается под изменением рантайма? У меня ничего такого нет, что не вытекало бы из изменения AST.
T>почему не пойти дальше, и не включить например списковые дополнения или вывод типов?
Скорее надо бы объяснить почему надо включить.

T>К тому же оба нам всё равно понадобятся для нормального PM — мы ведь хотим удобства — значит типизация связываемых переменных — забота компилятора, да и возможность указывать только нужную часть массива или контейнера, какой бы он не был длинны — тоже очень удобная штука, особенно если мы хотим хвост сбиндить и тоже обработать.

Меня из нам вычеркивайте.

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

Что опять понимается под выносом на уровень рантайма?

T>Идём далее — у нас теперь получается язык с 2мя разными семантиками — одна, новая, работает в функциях отмеченных тагом @PatternMatching, другая, старая, во всех остальных местах.

Но-но, меня в эти с кем "идём" не записывайте. У меня никаких двух семантик нет.

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

У меня такой проблемы не возникает.

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

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

T>Стало быть проще сразу обрабатывать этим тулзом все функции и не париться.


T>Вот у нас и получился новый язык программирования, со своей семантикой и таким же как у java синтаксисом.

У вас, не у меня.
T>Но синтаксис нас всё же ограничивает.
Вас, не меня.
T>В java мы не можем работать с переменноё без объявления её типа, а хотелось бы, ведь у нас уже есть вывод типов.
Мне не хотелось бы.

T>Да и списковые дополнения хотелось бы использовать не только для описания шаблонов а и для конструирования массивов и других контейнеров.

Мне не хотелось бы.

T>Получился ответ на вопрос — зачем изобретать какой-то дополнительный язык, если на java всё это можно и так написать.

У меня такой ответ не получился.
T>Ну и ответ на вопрос "в чём отличия" думаю тоже понятен — в удобстве использования и инфроструктуре.
Мне не понятен, впрочем давно потерял суть ваших рассуждений. Одна из первых посылок, вероятно была неверной. Для меня по-крайней мере.

T>Мне кажется, что без учёта инфроструктуры и ограничений, код получается больше как минимум в 2-3 раза для простых случаев...

Но не в 30 раз по объему, если сравнивать с изначальным сообщением, что уже неплохо.
К тому же для сложных случаев, соотношение, как мне кажется будет даже уменьшаться.
Re[28]: Действительно ли ML языки хороши в компиляторописани
От: SmbdRsdn  
Дата: 30.04.08 13:07
Оценка:
Здравствуйте, Cyberax, Вы писали:

SR>>8 лет, говорите и не приходилось отлаживать по JDK? Кхм, кхм.

C>Попробуйте поставить брейкпоинт где-нибудь в java.util.collections. Запустите программу. Удивитесь.
Ах вот оно что, отладка для вас означает установку точки останова.

C>А всё потому, что JDK в стандартной поставке не имеет отладочных символов. Их можно скачать дополнительно, но это отдельный разговор.

Скачиваете Eclipse, ставите точку останова, запускаете на отладку.

C>Так вот, код в JDK мне не приходилось отлаживать ни разу.

Ну раз 8 лет, значит так и надо.
Re[29]: Действительно ли ML языки хороши в компиляторописани
От: Mamut Швеция http://dmitriid.com
Дата: 30.04.08 13:28
Оценка:
M>>>>Где он был не совсем корректным и не соответствовал условиям задачи.
SR>>>Не припоминаю особых некорректностей, также как и несоответствия условиям задачи.

M>>Байндились ненужные переменные

SR>Связывать ненужные переменные можно и в Scala, так что мимо.

Ключевой момент состоит в том, что не нужные переменные в Скала (и в любом языке с ПМом) можно и не связывать:

single match {case _:MySingleton.type => println("OK")}


Символ подчеркивания виден? Он означает: сама переменная мне нафиг не сдалась, но главное, чтобы она была типа MySingleton

M>>>>Кстати, насчет связывания переменных.


M>>>>
M>>>>[{elem1, elem2}|T]
M>>>>

M>>>>
M>>>>data.matches(list(elem1, elem2), T)
M>>>>

M>>>>Что такое T в примере на Java, и откуда оно взялось?
SR>>>
SR>>>Tail T = new Tail();
SR>>>class Tail {
SR>>>  public object[] value;
SR>>>}
SR>>>


M>>чаво чаво? T у нас может быть любым объектом — списком, кортежем, классом, встроенным типом и т.п.

SR>Стало быть это мне надо спрашивать?

Что — это? В списке у нас есть Head, который может быть любым типом, и Tail, который может быть любым типом. Причем принимающей функции иногда даже не надо знать, что это за переменная, а передать ее дальше.


M>>>>Что такое T в примере на Scala, и откуда оно взялось?


M>>Более того, этот T мы можем сразу взять и использовать дальше — в последующих сопоставлениях или сразу по назначению:

SR>Так и в Java, неужели не видите, что раз term переменная и ее можно и использовать в соспоставлении с образцом, то и T переменная и ее тоже можно использовать далее как угодно, в том числе и при сопоставлении с образцом.

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


M>>Ключевой момент — в выделенном. Тут мы создаи и заюзали переменную y встроенного типа Int. А могли бы дополнить:

SR>Если нужна типизация, так в Java есть обобщенные классы. z = new Match<MyClass>().

Мывсе еще ждем реализацию этой мега функции/класса Match, который, как оказалось, уже и типы проверять может.

M>>Ну и где же пресловутая всеобщая функция, которая:

SR>С чего вы взяли, что это будет одна и та же функция? Функции в Java поддерживают перегрузку параметров.
SR>Применение функций будет выглядеть примерно одинаково.

Правильно. И вместо того, чтобы использовать 2 строчки ПМа, будем писать n строчек перегруженных функций, отличающихся только одним символом, ага
... << RSDN@Home 1.2.0 alpha 4 rev. 1084>>


dmitriid.comGitHubLinkedIn
Re[25]: Действительно ли ML языки хороши в компиляторописани
От: Tonal- Россия www.promsoft.ru
Дата: 30.04.08 15:26
Оценка:
Здравствуйте, SmbdRsdn, Вы писали:

SR>>>
SR>>>new Object[] {_, 2, x}
SR>>>

T>>Как будем различать массивы интов, даблов и собственно Object-ов?
SR>Трудности с различением не очевидны.
Если неочивидны, приведи пример, как будут выглядеть соответствующие паттерны.
Только вместе с описанием типов _ и x.

T>>Вот про это тебе и говорят "псевдокод". То что можно построить некий тул, который будет переписывать АСД никто не сомнивается.

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

Давай тогда просто сравним минимальные програмки.
Возмём, например, задачку про переписывание
Автор: Lazy Cjow Rhrr
Дата: 14.12.07
:

rational n + rational m -> rational(n + m)
rational n * rational m -> rational(n * m)
symbol x -> symbol x
0+f -> f
f+0 -> f
0*f -> 0
f*0 -> 0
1*f -> f
f*1 -> f
a+(b+c) -> (a+b)+c
a*(b*c) -> (a*b)*c


-module(rewrite).
-export([rewrite/1]).

rewrite({sum, N, M}) when is_number(N), is_number(M)
  -&gt; N + M;
rewrite({mul, N, M}) when is_number(N), is_number(M)
  -&gt; N * M;
rewrite(A) when is_atom(A)
  -&gt; A;
rewrite({sum, 0, F})
  -&gt; rewrite(F);
rewrite({sum, F, 0})
  -&gt; rewrite(F);
rewrite({mul, 0, _})
  -&gt; 0;
rewrite({mul, _, 0})
  -&gt; 0;
rewrite({mul, 1, F})
  -&gt; rewrite(F);
rewrite({mul, F, 1})
  -&gt; rewrite(F);
rewrite({sum, A, {sum, B, C}})
  -&gt; rewrite({sum, {sum, A, B}, C});
rewrite({mul, A, {mul, B, C}})
  -&gt; rewrite({mul, {mul, A, B}, C});

rewrite(N) when is_number(N)
  -&gt; N;
rewrite({sum, A, B}) 
  -&gt; rewrite({sum, rewrite(A), rewrite(B)});
rewrite({mul, A, B})
  -&gt; rewrite({mul, rewrite(A), rewrite(B)}).

Лог консоли erlang-а:
35&gt; c(rewrite).                             
{ok,rewrite}
36&gt; rewrite:rewrite({mul, 4, {sum, -2, 2}}).
0
37&gt; rewrite:rewrite({mul, 4, {sum, 1, 2}}). 
12
38&gt; rewrite:rewrite({mul, {sum, 1, 2}, 4}). 
12

Итого: 33 строки. Из них 2 служебных, 2 — пустые, для улучшения восприятия.
На каждое правило из задания — 2 строки реализации + 6 строк на 3 "подразумеваемые" правила.

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

P.S. Правила, как мне кажется, замечательно читаются и в 1 строку, но учитывая, что пост могут чить люди совершенно не знакомые с синтаксисом erlang-а, я решил более наглядно отделить шаблоны от выводов.
... << RSDN@Home 1.2.0 alpha 4 rev. 1065>>
Re[26]: Действительно ли ML языки хороши в компиляторописани
От: Tonal- Россия www.promsoft.ru
Дата: 30.04.08 15:30
Оценка:
Здравствуйте, Tonal-, Вы писали:
T>
T&gt;rewrite({sum, N, M}) when is_number(N), is_number(M)
  -&gt; N + M;

Вот блин, как исходник искарячило. вместо &gt; следует читать >
... << RSDN@Home 1.2.0 alpha 4 rev. 1065>>
Re[29]: Действительно ли ML языки хороши в компиляторописани
От: Cyberax Марс  
Дата: 30.04.08 19:20
Оценка:
Здравствуйте, SmbdRsdn, Вы писали:

C>>Попробуйте поставить брейкпоинт где-нибудь в java.util.collections. Запустите программу. Удивитесь.

SR>Ах вот оно что, отладка для вас означает установку точки останова.
По большей части — да. Отладочную печать в JDK воткнуть затруднительно.

Хотя ещё иногда объекты из JDK инспектирую в отладчике — это да.

C>>А всё потому, что JDK в стандартной поставке не имеет отладочных символов. Их можно скачать дополнительно, но это отдельный разговор.

SR>Скачиваете Eclipse, ставите точку останова, запускаете на отладку.
Нафиг? У меня IDEA в фоне открыта. Отладочные символы тоже есть.

C>>Так вот, код в JDK мне не приходилось отлаживать ни разу.

SR>Ну раз 8 лет, значит так и надо.
А вот код в разных библиотеках и приложениях (Hibernate, JBoss, Jetty, Tomcat, ....) мне приходилось отлаживать неоднократно.
Sapienti sat!
Re[9]: Действительно ли ML языки хороши в компиляторописани
От: Lazy Cjow Rhrr Россия lj://_lcr_
Дата: 01.05.08 00:40
Оценка: 140 (9)
SmbdRsdn,

SR>Не забывайте, что Скала не может выйти за пределы JVM.

Тем не менее компилятор Scala в курсе, что такое выражение match, а компилятору Java вызов функции matches абсолютно фиолетов — они для него все на одно лицо.

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

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

Вместе с тем, проблема очень даже реальная. Это та же самая проблема, из-за которой компилятор не может элиминировать косвенные вызовы методов и сделать инлайнинг — в подавляющем большинстве случаев он просто не знает реальный тип объекта на этапе компиляции. Это может сделать только JIT и то в очень специальных случаях (ну вот как твой) — потому что есть ещё кастом класслоадеры. Однако JIT не может содержать достаточно глубокий анализатор, поскольку здесь уже очень критично время анализа. Отсюда следует, что магическое превращение средствами самой Java-мащины метода
public Term simplify(Term term) {
  _Term x = new _Term();
  if (term.matches(new Mul(new Num(0), x)))
    return new Num(0);
  if (term.matches(new Mul(new Num(1), x))
    return x.value;
  _Term f = new _Term();
  if (term.matches(new Add(new Num(0), f))
    return f.value;
  if (term.matches(new Add(f, new Num(0)))
    return f.value;
  return term;
}

в
public Term simplify(Term term)
{
    if(term instanceof Mul)
    {
        Mul term2 = (Mul) term;
        Term term3 = term2.l();
        Term term4 = term2.r();
        if (term3 instanceof Num)
        {
            switch(((Num)term3).n())
            {
            case 0:
                return new Num(0);
            case 1:
                return term4;
            default:
                return term;
            }
        }
    }
    else if (term instanceof Add)
    {
        Add term2 = (Add) term;
        Term term3 = term2.l();
        Term term4 = term2.r();
        if (term3 instanceof Num && ((Num)term3).n() == 0)
            return term4;
        else if (term4 instanceof Num && ((Num)term4).n() == 0)
            return term3;
    }
    return term;
}

ну, кхм... очень маловероятно.

SR>>>Не отдельные if, а отдельный метод. Помеченный аннотацией. Что является законным способом добавления мета-данных в Java.

LCR>>Как ты собираешься отделять "паттерн-матчинговские" if-ы от обычных, в которых объекты просто сравниваются между собой?
SR>Зачем? Вполне разумно вынести сопоставление с образцом в отдельный метод, в котором не будет if'ов вида (if (object.equals(new Object()))) не представляющих сопоставление с образцом.
Тогда эти подпорки никогда не сравняются с ПМ в плане юзабилити. Видишь ли, в Скале (а также Nemerle, *ML, Haskell etc) match — это выражение, в отличие от Java, где if — это оператор. Отсюда следует, что написать
mylist.map(x => match x { ... })

в "твоей яве" невозможно в принципе.

Ещё вот в Эрланге например
T1 = insert(K, T0)

это никакое не присваивание, а паттерн матчинг, прикинь! Отсюда следует, что выражения
[H | T] = get_list()
{A1, A2} = get_tuple()

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

В языках с паттерн-матчингом встречаются и хардкорные возможности, зависящие от языка. Скажем, в Скале можно сделать так:
  override def flatMap[B](f: A => Iterable[B]): Stream[B] =
    if (isEmpty) Stream.empty
    else
    {
      val s: Stream[B] = f(head) match
      {
        case x: Stream[_] => x
        case y: List[_]   => y.toStream
        case z            => z.toList.toStream
      }
      s append (tail flatMap f)
    }

Обрати внимание, вайлдкардом является параметр типа.

Ещё одно наблюдение. Пишем
@PatternMatching
Term simplify(Term term, MyPattern p) {
    if (!p.matches("hola"))
    {
        if (term.matches(new Num(1))) 
        ...
    }
}

и у нас всё упало, потому что в MyPattern метод matches — это просто метод реализующий регэкспы, и никакого отношения к "твоей яве" с её паттерн-матчингом не имеет. Выход? Правильно:
Term simplify(Term term, MyPattern p) {
    if (!p.matches("hola"))
        return trueSimplify(term);
}

@PatternMatching
Term trueSimplify(Term term)
        if (term.matches(new Num(1))) 
        ...

Или специальные паттерн-матчинговые методы надо называть __matches__ дабы не было конфликта имён.

LCR>>возвращает значения через параметры (то есть метод имеет побочные эффекты!),

SR>Не забывайте, это же Java!
SR>Что еще за требование, что метод не может иметь побочных эффектов?
SR>Может и от оператора присваивания отказаться?
Это требование к equals, спека надеюсь известна. И вообще, согласно принципу наименьшего удивления, если метод всего-лишь что-то проверяет, то результат проверки должен быть либо true, либо false, результат очередной проверки не должен зависеть от результатов предыдущих проверок, то есть проверять можно любые объекты в любом порядке. Если есть метод checkThatStuffAndAdvancePosition, то должны быть веские причины для того, чтобы не разбивать это на два метода isThatStuffOk и advancePosition. В моём случае я это делал для эффективности, и, соответственно, тщательно комментировал.

LCR>>Код стал более понятным? Щаз. Лично меня ты ввёл в конкретное заблуждение.

SR>Ну если так легко ввести в заблуждением кодом вида if (object.equals(new Object())), тогда не знаю.
SR>Видимо надо начинать спрашивать про опыт программирования на Java.
Гы, ну спроси. Java такой примитивный язык, что если не разбавлять этот экспириенс чем-нибудь сильно другим, то чем больше на нём программируешь, тем больше тупеешь. Привычка видеть объекты и классы везде и всюду оказывается палкой в колесе, когда сталкиваешься, например с Прологом, Хаскелем и подобными (да даже со Скалой при попытках понять вещи, которых в Java нет). А эту несчастную строчку понять можно и без опыта на java, а бить копытом в грудь это как-нть без меня.

LCR>>4. код неявно предполагает, что объекты типов Term, Num, Mul, Add и т.п. иммутабельны, а конструкторы не имеют побочных эффектов.

SR>Из кода не видно, зачем ему это предположение, видимо очень не явно. На Java с Yo можно сопоставлять аналогично предыдущим классам.
Ну вот мы и добрались до сути...

Вообще, рассматривать паттерн матчинг в отрыве от алгебраических типов слегка неправильно. Поэтому правильный вопрос: как реализовать алгебраические типы в Java, а потом думать, как их матчить. Лично я знаю 2 способа, как честно (то есть без всяких кодогенераторов, препроцессоров и прочей фигни, чисто на языке) реализовать алгебраические типы и паттерн-матчинг. Для алгебраических типов определяются две операции — пересечение и объединение. Их аналоги в ООП: пересечение — это класс с полями, объединение — это наследование от общего предка (я просто повторил для полноты картины, всё это известно).

Способ первый: внутренние интерфейсы и рефлекшн.
interface Term
{
    interface Num extends Term { int n(); }
    interface Mul extends Term { Term l(); Term r(); }
    interface Add extends Term { Term l(); Term r(); }
}
// реализации
class NumClass implements Term.Num
{
    int n;
    public NumClass(int n) { this.n = n; }
    public int n() { return n; }
}
class MulClass implements Term.Mul
{
    Term l, r;
    public MulClass(Term l, Term r) { this.l = l; this.r = r; }
    public int l() { return l; }
    public int r() { return r; }
}
class AddClass implements Term.Num
{
    Term l, r;
    public AddClass(Term l, Term r) { this.l = l; this.r = r; }
    public int l() { return l; }
    public int r() { return r; }
}

// у него методы объявлены final чтобы случайно не перекрыли
class PatternMatcher
{
    // общий выковыриватель типов объектов
    public final Object matches(Object[] a)
    {
        Class c[] = new Class[a.length];
        for (int k = 0; k < a.length; k++)
            c[k] = a[k].getClass();
        return matches(a, c);
    }
    // вызывальщик методов, которые матчат
  public final Object matches(Objec[] a, Class[] c)
  {
        try { this.getClass().getMethod("matches", c).invoke(this, a); }
        catch(Exception e) {throw new MatchingException(); }
  }
}

class Simplifier extends PatternMatcher
{
    public Term matches(Mul m)
    {
        if (m.l().equals(new Num(0))
            return new Num(0);
        else if (m.l().equals(new Num(1))
            return m.r();
        else
            return m;
    }
    
    public Term matches(Add a)
    {
        if (a.l().equals(new Num(0))
            return a.r();
        else if (a.r().equals(new Num(0))
            return a.l();
        else
            return a;
    }
    
    // вот этот метод должен пользователь
    // вызывать явно в своём коде
    public Term matches(Term t)
    {
        return matches(new Object[]{t}); // вызывается метод в классе PatternMatcher
    }
}

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


Способ второй: визиторы. Стандартная унылая тягомотина...
abstract class Term {    public void accept(TermVisitor v); }

class Num extends Term
{
    int n;
    public Num(int n) { this.n = n; }
    public void accept(TermVisitor v) { v.visit(this); }
}
class Mul extends Term
{ 
    Term l, r;
    public Mul(Term l, Term r) { this.l = l; this.r = r; }
    public void accept(TermVisitor v) { v.visit(this); }}
}
class Add extends Term
{ 
    Term l, r;
    public Add(Term l, Term r) { this.l = l; this.r = r; }
    public void accept(TermVisitor v) { v.visit(this); }}
}

interface TermVisitor
{
    public void visit(Num n);
    public void visit(Mul m);
    public void visit(Add a);
}

class SimplifyVisitor implements TermVisitor
{
    Term t; // возвращаемое значение
    public SimplifyVisitor(Term t) { this.t = t; }

    public void visit(Num n) {}
    public void visit(Mul m)
    {
        if (m.l().equals(new Num(0))
            t = new Num(0);
        else if (m.l().equals(new Num(1))
            t = m.r();
    }
    public void visit(Add a)
    {
        if (a.l().equals(new Num(0))
            t = a.r();
        else if (a.r().equals(new Num(0))
            t = a.l();
    }
}

(Оба способа достаточно уродливы, только второй чаще упоминается)

Вот здесь и видно, зачем нужно отсутствие побочных эффектов и иммутабельность. Если методы l(), r() и подобные будут иметь побочные эффекты, то результат matches будет зависеть от порядка вызова методов, от состояния матчера, от фазы Луны... А иммутабельность как раз и позволяет изничтожить создания объектов на каждый чих (вон там повсюду new Num(0)), а расшаривать несколько объектов среди многих точек использования. Тот самый пулинг, о котором ты говорил немного ранее.



А теперь на закуску. Вроде ты где-то жаловался, что примеры слишком простые. Ну вот 3 не слишком простых примера. Первый пример — это балансировка красно-чёрного дерева с помощью ПМ:
    private def mkTree[B](isBlack: Boolean, k: A, v: B, l: Tree[B], r: Tree[B]) = 
      if (isBlack) BlackTree(k, v, l, r) else RedTree(k, v, l, r)

    def upd[B1 >: B](k: A, v: B1): Tree[B1] = 
    {
      def balanceLeft(isBlack: Boolean, z: A, zv: B, l: Tree[B1], d: Tree[B1]) = l match
      {
        case RedTree(y, yv, RedTree(x, xv, a, b), c) => 
          RedTree(y, yv, BlackTree(x, xv, a, b), BlackTree(z, zv, c, d))
        case RedTree(x, xv, a, RedTree(y, yv, b, c)) =>
          RedTree(y, yv, BlackTree(x, xv, a, b), BlackTree(z, zv, c, d))
        case _ =>
          mkTree(isBlack, z, zv, l, d)
      }
      def balanceRight(isBlack: Boolean, x: A, xv: B, a: Tree[B1], r: Tree[B1]) = r match
      {
        case RedTree(z, zv, RedTree(y, yv, b, c), d) => 
          RedTree(y, yv, BlackTree(x, xv, a, b), BlackTree(z, zv, c, d))
        case RedTree(y, yv, b, RedTree(z, zv, c, d)) =>
          RedTree(y, yv, BlackTree(x, xv, a, b), BlackTree(z, zv, c, d))
        case _ =>
          mkTree(isBlack, x, xv, a, r)
      }
      if (k < key)
              balanceLeft(isBlack, key, value, left.upd(k, v), right)
      else if (key < k)
        balanceRight(isBlack, key, value, left, right.upd(k, v))
      else
              mkTree(isBlack, k, v, left, right)
    }

Обрати внимание, как классно здесь помогает type inference — локальные функции внутри принимают обобщённые параметры, и это учитывается и паттерн-матчинге! Это вообще здорово, когда фичи языка вот в такой гармонии работают. А вот теперь я тебе щас зарисую твой эквивалент
private <A, B> Tree<B> mkTree(Boolean isBlack, A k, B v, Tree<B> l, Tree<B> r)
{
    if (isBlack) 
        return new BlackTree<B>(k, v, l, r);
    else 
        return new RedTree<B>(k, v, l, r);
}

@PatternMatching
private <A, B, B1> Tree<B> balanceLeft(Boolean isBlack, A z, B zv, Tree<B1> l, Tree<B1> d)
{
    _Boolean x = new _Boolean();
    _Boolean y = new _Boolean();
    _A yv = new _A();
    _A xv = new _A();
    _Tree<B1> a = new _Tree<B1>();
    _Tree<B1> b = new _Tree<B1>();
    _Tree<B1> c = new _Tree<B1>();
    if (l.matches(new RedTree<B>(y, yv, new RedTree<B>(x, xv, a, b), c))) 
        return new RedTree<B>(y.value, yv.value, 
            new BlackTree<B>(x.value, xv.value, a.value, b.value), 
            new BlackTree<B>(z.value, zv.value, c.value, d.value));
    else if (l.matches(RedTree<B>(x, xv, a, new RedTree<B>(y, yv, b, c)))) 
        return new RedTree<B>(y.value, yv.value, 
            new BlackTree<B>(x.value, xv.value, a.value, b.value), 
            new BlackTree<B>(z.value, zv.value, c.value, d.value));
    else
        return mkTree(isBlack, z, zv, l, d);
}

@PatternMatching
private <A, B, B1> Tree<B> balanceRight(Boolean isBlack, A x, B xv, Tree<B1> a, Tree<B1> r)
{
    _Boolean z = new _Boolean();
    _Boolean y = new _Boolean();
    _A zv = new _A();
    _A yv = new _A();
    _Tree<B1> b = new _Tree<B1>();
    _Tree<B1> c = new _Tree<B1>();
    _Tree<B1> d = new _Tree<B1>();
    if (r.matches(new RedTree<B>(z, zv, new RedTree<B>(y, yv, b, c), d))) 
        return new RedTree<B>(y.value, yv.value, 
            new BlackTree<B>(x.value, xv.value, a.value, b.value), 
            new BlackTree<B>(z.value, zv.value, c.value, d.value));
    else if (r.matches(RedTree<B>(y, yv, b, new RedTree<B>(z, zv, c, d)))) 
        return new RedTree<B>(y.value, yv.value, 
            new BlackTree<B>(x.value, xv.value, a.value, b.value), 
            new BlackTree<B>(z.value, zv.value, c.value, d.value));
    else
        return mkTree(isBlack, x, xv, a, r);
}
      
public <A, B> Tree<B> upd(A k, B v)
{
    if (k < key)
        balanceLeft(isBlack, key, value, left.upd(k, v), right);
    else if (key < k)
        balanceRight(isBlack, key, value, left, right.upd(k, v));
    else
        mkTree(isBlack, k, v, left, right);
}

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

Во-первых, этот код не работает вообще. То есть я как-то начал переводить, а потом наткнулся на дженерик параметры, и что с ними делать — Я тупо заполнил эти места _A. Не, ну что-то с ними конечно можно сделать, нарисовать холдеры Object-ов, кастинг там в нужном месте сделать... Но это криво.

Во-вторых, конструкторы BlackTree тоже должны быть от типов-параметров — где-то от <B>, где-то от <B1>, но я везде взял и налепил <B>. Тут, извини, нужна усидчивость. А у меня её упс — нету. Я люблю когда всё легко и просто.

В-третьих, холдеры для Boolean-ов я обозначил _Boolean. Продолжая в том же духе, можно пройтись по всем типам стандартной библиотеки. Ну ты можешь, конечно, круто обобщить, и сделать обобщённый холдер Holder<T> который можно будет толкать во все дыры в твоём паттерн-матчинге. Это наверное будет прадедушка всех алгебраических типов. Самое интересное начнётся, когда потребуется матчить какие-нибудь типы наследующие от Holder<T>, тогда появятся F-ограничения типа Holder<T extends Holder<T>>, интереснейшие
хреновины, надо сказать. Если это вот-так вот вколотить в редактор, компилятор будет нехорошо ругаться. Чтобы можно было инстанцировать эти штуки, потребуется предварительно их замкнуть. Вах, какая захватывающая работа тебе предстоит, аж завидно!

Ну, а в-четвёртых, напрягает предварительно объявлять все переменные. Раз уж у нас есть препроцессинг, пусть он как-нибудь сам нагенерит объявления, что-ли...

Второй пример — это проверка, могут ли процессы взаимодействовать (из реализации pi-calculus)
  private def matches(gs1: List[UGP], gs2: List[UGP]): Option[(() => Unit, () => Any, () => Any)] =
    (gs1, gs2) match {
      case (Nil, _) => None
      case (_, Nil) => None
      case (UGP(a1, d1, v1, c1) :: rest1, UGP(a2, d2, v2, c2) :: rest2) =>
        if (a1 == a2 && d1 == !d2)
          Some(((() => if (d1) a1.log(v2) else a1.log(v1)), (() => c1(v2)), (() => c2(v1))))
        else matches(gs1, rest2) match {
          case None => matches(rest1, gs2)
          case Some(t) => Some(t)
        }
    }

Обрати внимание, как на лету создаётся тупл, а потом он разбирается на кусочки и в else-ветке происходит рекурсивный вызов себя же и результат рекурсивного вызова прямо на месте опять матчится. Перевод в каноническую форму "твоей java" 1-в-1 снова обломится. Там нужно будет заводить 2 взаимно-рекурсивных метода, рисовать аннотации и создавать несуществующий Tuple<A,B>(gs1, gs2) у которого вдруг должен оказаться снова волшебный метод matches. Но переводить что-то уже лень. Я ж говорю, усидчивость нужна.

Ладно, у меня ещё есть не слишком простой пример, пример под номером три
Автор: Lazy Cjow Rhrr
Дата: 16.12.05
. Это AVL-деревья. На сей раз на Эрланге. Там тоже деревья изящно так разбираются на кусочки, а потом из этих кусочков склеиваются новые деревья. Вот только возможно тебе не понравится, слишком уж там всё кратко. Я бы даже сказал чересчур. Так и хочется куда-нибудь впихнуть new. Или @PatternMatching...
quicksort =: (($:@(<#[),(=#[),$:@(>#[)) ({~ ?@#)) ^: (1<#)
Например...
От: Mamut Швеция http://dmitriid.com
Дата: 01.05.08 06:30
Оценка: +1
Примечание. Ниже код, особенно на Яве — этакий полупсевдокод В Яве я намного ольше читатель, чем писатель. Functor — это анонимная функция, принимающая на вход параметр типа FieldType и возвращающая FieldType. Возможно, в Яве это реализуется делегатами или анонимными классами — не суть важно.

Итак...

ПМ позволяет уменьшить количество кода, увеличивая его читаемость (что плохо видно на мелких примерах, но все же)


// Scala

def runFilters(in_val: FieldType, filter: List[FieldType => FieldType]): FieldType =
     filter match {
       case Nil => in_value
       case x :: xs => runFilters(x(in_val), xs)
     }
     
// Java

FieldType runFilters(FiledType in_val, Functor filter[])
{
        for(filter in filters)
        {
            if(filter != NULL)
                in_val = filter(in);
        }
        return in_val;
}


ПМ позволяет легче вносить изменения (безусловно не везде, но в большом классе задач, свзаных с проверкой), не ухудшая читаемости и декларативности кода:

// Scala

def runFilters(in_val: FieldType, filter: List[FieldType => FieldType]): FieldType =
     filter match {
       case Nil => in_val
       case x:MyFilter.type :: xs => runFilters(x(in_val), xs)
       // мы еще не реализовали другие фильтры
       case _ :: xs => runFilters(in_val, xs)
     }
     
// Java

FieldType runFilters(FiledType in_val, Functor filter[])
{
    for(filter in filters)
    {
            if(filter != NULL && filter instanceof MyFilter)
                filter(in_val);
    }
}



Если логика усложняется, декларативность остается:
// Scala
// Реализованы только фильтры MyFilter и ComplexFlter
// Для ComplexFilter необходимо елаь препроцессинг

def runFilters(in_val: FieldType, filter: List[FieldType => FieldType]): FieldType =
     filter match {
       case Nil => in_val

       case x:MyFilter.type :: xs => runFilters(x(in_val), xs)

       case x:ComplexFilter.type :: xs =>
           in_val = Preprocess(in_val);
           runFilters(in_val, xs)

       case _ :: xs => runFilters(in_val, xs)
     }
     
// Java
// Реализованы только фильтры MyFilter и ComplexFlter
// Для ComplexFilter необходимо елаь препроцессинг

FieldType runFilters(FiledType in_val, Functor filter[])
{
    for(filter in filters)
    {
            if(filter != NULL)
            {
                if(filter instanceof MyFilter)
                {
                    in_val = filter(in_val);
                }
                else if(filter instanceof ComplexFilter)
                {
                    in_val = Preprocess(in_val);
                    in_val = filter(in_val);
                }
            }
    }
    
    return in_val;
}


И так далее. Уже видно, что ПМ полностью соответствует комментариям, там даже комментарии не нужны, в коде и так все понятно. В то время как без ПМа с усложнением логики код становится все менее и менее читаемым из-за леса if'ов.
... << RSDN@Home 1.2.0 alpha 4 rev. 1084>>


dmitriid.comGitHubLinkedIn
Re: Например...
От: Andrei N.Sobchuck Украина www.smalltalk.ru
Дата: 01.05.08 11:51
Оценка:
Здравствуйте, Mamut, Вы писали:

M>// Java

M>// Реализованы только фильтры MyFilter и ComplexFlter
M>// Для ComplexFilter необходимо елаь препроцессинг

Ерунда. Я несколько раз уже пытался донести мысль
Автор: Andrei N.Sobchuck
Дата: 11.09.06
, что не нужно один в один переносить код с ЯП с ПМ на java (или что-то еще). Потому как на ней будет всё иначе.
http://www.smalltalk.ru << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Я ненавижу Hibernate
Автор: Andrei N.Sobchuck
Дата: 08.01.08
!
Re[2]: Например...
От: Mamut Швеция http://dmitriid.com
Дата: 01.05.08 14:55
Оценка: +1
M>>// Java
M>>// Реализованы только фильтры MyFilter и ComplexFlter
M>>// Для ComplexFilter необходимо елаь препроцессинг

ANS>Ерунда. Я несколько раз уже пытался донести мысль
Автор: Andrei N.Sobchuck
Дата: 11.09.06
, что не нужно один в один переносить код с ЯП с ПМ на java (или что-то еще). Потому как на ней будет всё иначе.


Вот мы примерно про это же и говорим — без ПМ это каждый раз буде по-другому. С ПМ это будет некий унифицированый подход
... << RSDN@Home 1.2.0 alpha 4 rev. 1084>>


dmitriid.comGitHubLinkedIn
Re[3]: Например...
От: Курилка Россия http://kirya.narod.ru/
Дата: 01.05.08 15:42
Оценка: +1 :))
Здравствуйте, Mamut, Вы писали:

M>>>// Java

M>>>// Реализованы только фильтры MyFilter и ComplexFlter
M>>>// Для ComplexFilter необходимо елаь препроцессинг

ANS>>Ерунда. Я несколько раз уже пытался донести мысль
Автор: Andrei N.Sobchuck
Дата: 11.09.06
, что не нужно один в один переносить код с ЯП с ПМ на java (или что-то еще). Потому как на ней будет всё иначе.


M>Вот мы примерно про это же и говорим — без ПМ это каждый раз буде по-другому. С ПМ это будет некий унифицированый подход


Ну ПМ он тоже не совсем везде одинаков, да и в том же Эрланге можно ещё и бинарисы паттернматчить, но это уже настолько мощная магия, что многие приготовят целые ящики тухлых помидоров
Re[10]: Действительно ли ML языки хороши в компиляторописани
От: Mirrorer  
Дата: 02.05.08 18:02
Оценка: +1 :))
Здравствуйте, Lazy Cjow Rhrr, Вы писали:


LCR> Это AVL-деревья. На сей раз на Эрланге. Там тоже деревья изящно так разбираются на кусочки, а потом из этих кусочков склеиваются новые деревья. Вот только возможно тебе не понравится, слишком уж там всё кратко. Я бы даже сказал чересчур. Так и хочется куда-нибудь впихнуть new. Или @PatternMatching...


А может пойти от противного ? Записать примеры на J и показать что скала с эрлангом очень даже многословные языки
Re[11]: Действительно ли ML языки хороши в компиляторописани
От: Lazy Cjow Rhrr Россия lj://_lcr_
Дата: 03.05.08 17:15
Оценка:
Mirrorer,

M>А может пойти от противного ? Записать примеры на J и показать что скала с эрлангом очень даже многословные языки


Сложность реализации будет чуток зашкаливать, потому что дерево надо будет закодировать в массив каким-нибудь извращенским способом.
quicksort =: (($:@(<#[),(=#[),$:@(>#[)) ({~ ?@#)) ^: (1<#)
Re[12]: Действительно ли ML языки хороши в компиляторописани
От: Mirrorer  
Дата: 03.05.08 18:30
Оценка: :))) :))
Здравствуйте, Lazy Cjow Rhrr, Вы писали:


LCR>Сложность реализации будет чуток зашкаливать, потому что дерево надо будет закодировать в массив каким-нибудь извращенским способом.


Ну можно влоб боксами. Аля ЛЫСП
Правда эффективность будет не ахти, и ограничения есть на глубину боксинга..
Смотреть раздел obstacles http://www.jsoftware.com/jwiki/DanBron/Temp/Tree
Наверное ты прав, получится как в том стишке.

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

Re[3]: Паттерн-матчинг - отличие от обычных конструкций
От: BulatZiganshin  
Дата: 04.05.08 20:43
Оценка:
Здравствуйте, z00n, Вы писали:

Z>У меня есть самопальный компилятор, который умеет переписывать патернматчинг как каскад вложенных if-else, правда таргетит язык с динамической типизацией(Lua)


хм. а про metalua ты слышал?

--
-- The general form of a pattern matching statement is:
--
-- match <tested_term> with
-- | <pattern_1_1> | <pattern_1_2> | <pattern_1_3> -> <block_1>
-- | <pattern_2> -> <block_2>
-- | <pattern_3_1> | <pattern_3_2> if <some_condition> -> <block_3>
-- end
--

там вообще дофига интереснейших расширений языка: adt, list comprehension, ?:, type checking, try/catch, RAII, lambdas/lazy values, statements in expressions. словом, metalua можно рассматривать как двольно полноценный динамичсекий императивный ФП язык. а самое сочное там — расширяемость с синтаксическими макросами. собственно, половина вышеописанных вещей в базовый язык не входит, а порсто включены в качестве примеров. разница, собственно говоря невелика — metalua основана на parsec-подобной комбинаторной библиотеке парсинга gg, НО — поддерживающей расширение на ходу синтаксиса разюираемого языка. так что большой разницы где описан синтаксис этих расширений нету, ну а генератор кода опять же в любом случае пишется на самом Lua. ну и сам возможности метапрограммирования похожи на Template Haskell — на уровень вверх, на уровень вниз. код на Lua автоматом ковертируется в AST и пожалуйста — ходи по нему сколько хочешь
Люди, я люблю вас! Будьте бдительны!!!
Re[4]: Паттерн-матчинг - отличие от обычных конструкций
От: z00n  
Дата: 06.05.08 01:00
Оценка: 48 (5)
Здравствуйте, BulatZiganshin, Вы писали:

BZ>хм. а про metalua ты слышал?

Слышал.

BZ>там вообще дофига интереснейших расширений языка: adt, list comprehension, ?:, type checking, try/catch, RAII, lambdas/lazy values, statements in expressions. словом, metalua можно рассматривать как двольно полноценный динамичсекий императивный ФП язык. а самое сочное там — расширяемость с синтаксическими макросами. собственно, половина вышеописанных вещей в базовый язык не входит, а порсто включены в качестве примеров.

Я готов добавить хоть поддержку монадного сахара и Arrows — если есть потребность конечно

BZ> разница, собственно говоря невелика — metalua основана на parsec-подобной комбинаторной библиотеке парсинга gg, НО — поддерживающей расширение на ходу синтаксиса разюираемого языка. так что большой разницы где описан синтаксис этих расширений нету, ну а генератор кода опять же в любом случае пишется на самом Lua. ну и сам возможности метапрограммирования похожи на Template Haskell — на уровень вверх, на уровень вниз. код на Lua автоматом ковертируется в AST и пожалуйста — ходи по нему сколько хочешь


У меня тоже конвертируется, просто AST на Scala. Вы на чем предпочли бы работать с AST: на Haskell или на Lua? Если серьезно — в свете появления Lpeg (PEG парсера для Lua) — я, когда у меня выпадет свободная неделя переписал бы это на луа, бутстрэпнув его нынешним компилятором.

(Часть посвященная Философии программирования)
По природе своей я lisp-guy, но по поводу макросов для языков с инфиксной нотацией у меня есть большие сомнения. Макросы нужны когда нужно изменить компилятор, но в его недра залезть нереально. Макросы для не-лиспов сложнее писать, ими легче сломать синтаксис, и постоянно возникает ощущение что вам недодают выразительных средств (см. например топик про Nemerle и LINQ: http://www.rsdn.ru/forum/message/2913896.1.aspx
Автор: _nn_
Дата: 12.04.08
). C другой стороны, программу можно трансформировать и внешними средствами, и это может быть даже проще. И все равно 99% процентов программистов никогда не будут делать ни того ни другого, а будут брать, что дают.

(Часть посвяшенная практическим вещам)
Все началось с того, что мне понадобился в Луа паттерн-матчинг и я радостно схатился за металуа, в тот момент версии 0.2 alpha. К сожалению, в тот момент (во многом и сейчас) metalua не была готова к практическому использованию.
-- Там был огромный нечитаемый рукописный парсер. Поскольку он рукописный, он никак не проверяет непротиворечивость синтаксиса расширений, которые вы пишете – а синтаксис то не лисповый. Металуа вообще сильно сложнее и раза в 2-3 больше того, что я написал. В результате у меня получилось ~3K строк на скале (из которых треть pattern-matching compiler) + ~250 строк грамматики core lua на Xtc Rats! + ~250 строк грамматики расширений + 200 сток грамматики литералов, ключевых слов и прочих тривиальных вещей. Core metalua сейчас (раньше больше) занимает ~6K строк на луа + 1.5K собственно расширений на металуа + 1.5K библиотека.
-- Паттерн матчинг был (и есть) реализован наивно – т.е имеет сложность N*M в патологическом случае. Правда, я подозреваю, что в Erlang он тоже реализован наивно, и с этим можно жить, и будь это единственной проблемой – можно было бы смириться. Я молчу про то, что pattern-language бедноват.
-- Все это для работы требует изрядного рантайма написанного на lua, причем автор подхачил механизм загрузки модулей и у меня сразу начались всякие непонятные чудеса, которые усугублялись тем, что автор разрабатывал под Linux, а я пытался использовать это под Win.
-- В AST были очевидные переупрощения (их поправили в следующей версии), например в большинстве языков скобки в (expression) не несут семантической нагрузки. В lua, если выражение возвращает несколько значений заключение его в скобки урезает (как по русски будет coercion?) его до первого. Переупрощения появились, разумеется из-за желания иметь для макросов AST как можно меньшего размера.
-- Ну и главное – metalua порождает бинарный файл и в ней нет даже нормального претти-принтера (там есть некий рудиментарный механизм дампа AST – но ничего серьезного им не посмотришь). Искать место, в котором возникла ошибка или отлаживать макрос – приключение, поскольку луа ничего о металуа не знает. Бинарник она порождает для lua5.1 – а мне вот как раз недавно понадобилось таргетить lua 5.0 – минут за 20 я добавил опцию совместимости в паре мест подправил кодогенератор и написал на луа пару недостающих в 5.0 функций.

Что я получил написав свой компилятор?
-- У меня есть практически все, что есть в металуа, а чего нет, можно добавить примерно за час – два -- я добавил все что мне понравилось/показалось полезным.
-- Алгоритм паттерн-матчинга лучше, pattern-language – лучше. Бесплатная диагностика достижимости rhs (полноты тоже, но в динамическом языке не особенно нужно), линеарности паттерна, правильности употребления переменных в OR-паттерне (а в Scala их просто запретили) etc.
-- Есть то, чего нет в metalua, а мне хотелось иметь: инфиксные операторы, ML-like списки x::y::[], которые можно паттерн-матчить.
-- На выходе я получаю красиво отформатированную, ни от чего не зависящую программу. Единственная опциональная внешняя зависимость – 20 строк поддержки списков, которых ни в луа ни в металуа нет.
-- Имея свой компилятор с PEG парсером — расширять синтаксис достаточно просто:
— описываем грамматтику расширения на роскошном(по сравнению с металуа) языке Xtc Rats!
— пишем пару примеров и смотрим красиво отформатированное дерево разбора.
— запускаем официальные тесты луа, убеждаемся, что мы не сломали обратную совместимость с языком. Этого не случалось ни разу(хотя я нашел так пару тонких мест), поскольку PEG грамматики по настоящему расширяемые.
— дописываем клаузу в преобразование “разбор->AST_EX” – эта лишняя стадия необходима из-за того, что Rats! таргетит Java, а не Scala.
— дописываем клаузу в неявное преобразование AST_EX -> AST .
Все стадии претти-принтятся, включая всякие тонкие места типа генерации decision trees.

Ну и разумеется куча фана и всяких полезных наблюдений и ошибок.
Re[3]: Паттерн-матчинг - отличие от обычных конструкций
От: VladD2 Российская Империя www.nemerle.org
Дата: 12.05.08 20:02
Оценка:
Здравствуйте, SmbdRsdn, Вы писали:

LCR>>1. Паттерн-матчинг осуществляет разбор одновременно с биндингом, так что в первом случае x получит в качестве значения всё поддерево, чего бы там ни было

SR>Также и в моем примере.

У тебя вообще нет биндинга. Тебе же сказали, что в "х" может быть любое выражение.

LCR>>2. Паттерн-матчинг не пересоздаёт выражения чтобы выяснить соответствие выражений паттерну

LCR>>3. Алгоритмы паттерн-матчинга не выясняют структуры подвыражений, если структура стала известна на предыдущих шагах
SR>Это лишь вопросы (2. и 3.) производительности, соответственно достаточно интеллектуальный компилятор, особенно если ему помочь аннотацией, вполне способен развернуть equals в набор if'ов. В расширении же синтаксиса и тем более в переходе на новый язык нет необходимости.

Елы палы. Ну, попробуй реализуй свой "достаточно интеллектуальный компилятор" (с). Как только ты дойдешь до реальной реализации, то поймешь, что то что ты назвал "достаточно интеллектуальный компилятор" на самом деле является "думателем" (с). Этот думатель есть очень серьезно продуманный и математически обоснованный (доказанный) код. Под ним лежит железная теория. Твой "достаточно интеллектуальный компилятор" конечно сделать можно, но это и будет тот самый думатель запахнутый в рамки синтаксиса Явы. Ты будешь вынужден ввести все ограничения которые есть в алгебраических типах данных (case class-ы Скалы), так как без них нельзя гарантировать что конструкторы или методы не создают неких побочных эффектов, ты должен будешь ограничить наследование, чтобы иметь право предсказывать доказательство полноты... в общем, ты создашь тоже самое, но с более привычным синтаксисом... привычным тебе и таким как ты. Не проще ли просто выучить новый синтаксис и не заниматься велосипедостроением на пустом месте?
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[7]: Действительно ли ML языки хороши в компиляторописани
От: VladD2 Российская Империя www.nemerle.org
Дата: 12.05.08 20:15
Оценка:
Здравствуйте, SmbdRsdn, Вы писали:

SR>зачем прогоняться? В ASTParser можно на лету заменять отдельные ветки на другие. Короче, в чем-то аналог R#.


Как автор R# скажу, что закончил его развитие я как раз когда вплотную познакомился с Nemerle, который является братом-близнецом Scala, но на платформе .NET. Правда причиной, по началу, было не наличие ПМ, а наличие более совершенной мета-подсистемы, но мета-подсистема была только приманкой, а когда я разобрался в том как она устроена, то я понял, что базисом этой подсистемы как раз и является паттерн-матчинг и алгебраические типы (с которыми ты борешься).

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

Так что твои слоа не более чем предложение добавить в Яву паттерн-матчинг, но с синтаксисом похожим на вызовы методов Явы.
Это конечно же вполне возможно. Но как я уже скзал, дело далеко не в синтаксисе.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.