Re: Как сделать активные паттрены.
От: Рысцов Денис  
Дата: 08.11.10 18:26
Оценка: 56 (3)
Решил попрактиковаться в написании макросов и реализовал прямую (и медленную) реализацию активных паттернов. Планирую использовать библиотеку для декомпозиции сложных и длинных правил при pattern matching'е в своих home pet проектах.

Несколько примеров доступны по ссылке — http://code.google.com/p/nemerleactivepatterns/source/browse/Test/Main.n, собственно как и исходники проекта. Может быть кому-нибудь будет интересно
Как сделать активные паттрены.
От: WolfHound  
Дата: 19.10.10 09:18
Оценка: 26 (3)
Ответ на: Re[12]: Scala / F# / Nemerle и мейнстрим
Автор: VladD2
Дата: 19.10.10

Получилось много и по делу. По этому пишу сюда.

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

WH>>Всетки активные паттерны это очень мощьная штука.

VD>Это очень медленная штука. Как я понимаю, они там создают копии объектов.
То что авторы F# тормоза не значит что и я тормоз
Там можно все сделать очень эффективно.

VD>У меня на этот вопрос есть свое мнение. Можно просто описывать так называемый виртуальный (не существующий в реалии) конструктор который будет сообщать компилятору какие поля или свойства использовать для эмуляции конструктора. Тогда можно будет любой объект любого класса "можно будет матчить прямо как варианты".

Тут можно сделать все еще интересней.
1)Можно в паттернах использовать функции.
Первый аргумент (в случае методов this) будет принимать тот объект который матчим.
Если есть еще аргументы их нужно будет указать явно.
Возвращаемое значение и out параметры будут возвращаемыми значениями паттерна.
Их можно связать с переменной или счемнибудь сматчить.
Тогда можно будет делать так
match (someString)
{
    | string.IsNullOrEmpty(true) =>
    | int.TryParse(value, true) =>
    | Contains("qwe", true) =>
    | Contains("asd", true) =>
    | Contains("zxc", true) =>
}

Для функций возвращающих bool имеет смысл ввести сахар который матчит возвращаемое значенис с true.
Тогда код станет таким
match (someString)
{
    | string.IsNullOrEmpty =>
    | int.TryParse(value) =>
    | Contains("qwe") =>
    | Contains("asd") =>
    | Contains("zxc") =>
}

match (someDictionary)
{
    | TryGetValue("qwe", value) =>
    | TryGetValue("asd", value) =>
    | TryGetValue("zxc", value) =>
}

Эта функциональность перекрывает твой "виртуальный конструктор" с большим запасом.
Просто пишем такую функцию:
SomeTypeVirtualConstructor(obj : SomeType, field1 : out Type1, field3 : out Type4, field6 : out Type21) : void
{
    field1 = obj.field1;
    field3 = obj.field3;
    field6 = obj.field6;
}

В качестве бонуса можно возвращать bool и проверять состояние объекта.
Можно будет для этого даже макру сделать.

2)Функции конечно хорошо но bool не всегда достаточно.
Иногда при анализе объекта может выясниться что есть более чем один вариант который матчится или нет.
Например:
Можно написать так
variant EvenOdd
{
    | Even
    | Odd
}
IsEvenOdd(value : int) : EvenOdd
{
    if (value % 2 == 0) Even() else Odd()
}
match (someInt)
{
    | IsEvenOdd(Even) =>
    | IsEvenOdd(Odd) =>
}

Но это громоздко и не эффективно.

Для этого можно ввести такую конструкцию:
pattern EvenOdd
{
    | Even
    | Odd

    match (value : int)
    {
        if (value % 2 == 0) Even() else Odd()
    }
}
match (someInt)
{
    | Even =>
    | Odd =>
}

Рассахаривается это во что-то типа:
class EvenOdd
{
    public enum Patterns
    {
        | Even
        | Odd
    }

    public Match (value : int) : Patterns
    {
        if (value % 2 == 0) Even() else Odd()
    }
}


Если у нас варианты с параметрами то получится что-то типа такого
pattern Asdasdasd
{
    | Asd { a : int; b : string; x : float; }
    | Qwe { c : string; d : int; }

    match (value : SomeType)
    {
        ...
    }
}

Рассахаривается это во что-то типа:
class Asdasdasd
{
    public enum Patterns
    {
        [ArgumentsMap("1 2 3", "a b x")]//Это метаданные для того чтобы из других сборок можно было использовать
        | Asd
        [ArgumentsMap("2 1", "c d")]
        | Qwe
    }

    public Match (value : SomeType, res1 : out int, res2 : out string, res3 : out float) : Patterns
    {
        ...
    }
}

Таким образом никаких лишних выделений памяти не происходит.
На практике поля внутри разных опций одного варианта не отличаются разнообразием типов. По этому out параметры функции будут очень хорошо склееваться.
... << RSDN@Home 1.2.0 alpha 4 rev. 1472>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[2]: активные паттрены: перезагрузка :)
От: VladD2 Российская Империя www.nemerle.org
Дата: 20.10.10 18:58
Оценка: 24 (1)
Здравствуйте, VladD2, Вы писали:

VD>Задача:

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

Мое решение предполагает добавление следующих объявлений:
[assembly: PMCtor(BinaryExpression,      Bin(conv=Conversion, left=Left, right=Right, method=Method))]
[assembly: PMCtor(ConditionalExpression, If(ifFalse=IfFalse, ifTrue=IfTrue, cond=Test))]
[assembly: PMCtor(ConstantExpression,    Const(value=Value))]
[assembly: PMCtor(InvocationExpression,  Invoc(lambda=Expression, args=Arguments))]
[assembly: PMCtor(LambdaExpression,      Lambda(parms=Parameters, body=Body))]
[assembly: PMCtor(ListInitExpression,    ListInit(what=NewExpression, inits=Initializers))]
[assembly: PMCtor(MemberExpression,      Member(obj=Expression, member=Member))]
[assembly: PMCtor(MemberInitExpression,  MemberInit(what=NewExpression, bindings=Bindings))]
[assembly: PMCtor(MethodCallExpression,  Call(obj=Object, method=Method, args=Arguments))]
[assembly: PMCtor(NewArrayExpression,    New(ty=Type, inits=Expressions))]
[assembly: PMCtor(NewExpression,         NewArray(ctor=Constructor, args=Arguments, bindings=Members))]
[assembly: PMCtor(ParameterExpression,   Param(name=Name, ty=Type))]
[assembly: PMCtor(TypeBinaryExpression,  Is(expr=Expression, ty=TypeOperand))]
[assembly: PMCtor(UnaryExpression,       Unary(operator=Method, operand=Operand))]


После этого мы имеем возможность использовать описанные конструкторы в паттерн-матчинге.
Можно даже немного упростить эти объявления приняв соглашение по которому параметры имя которых совпадает со свойствами без учета регистар, можно описывать сокращенно. Например, вместо "left=Left" можно просто писать "Left".

Данные описания позволят компилятору просто переписать образец вида:
Bin(conv, left, right, method)

в образец вида:
BinaryExpression where(Conversion=conv, Left=left, Right=right, Method=method)

Что приведет к формированию эффективного кода без какого-либо рантайм-оверхэда.



Собственно жду аналогичного описания для активных партернов.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[2]: Как сделать активные паттрены.
От: WolfHound  
Дата: 08.11.10 18:34
Оценка: 4 (1)
Здравствуйте, Рысцов Денис, Вы писали:

РД>Решил попрактиковаться в написании макросов и реализовал прямую (и медленную) реализацию активных паттернов. Планирую использовать библиотеку для декомпозиции сложных и длинных правил при pattern matching'е в своих home pet проектах.

Вот тут что-то странное написано:

Realization of F#'s active patterns in Nemerle language.


ИМХО implementation будет более к месту.
... << RSDN@Home 1.2.0 alpha 4 rev. 1472>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[2]: Как сделать активные паттрены.
От: _nn_ www.nemerleweb.com
Дата: 09.11.10 08:52
Оценка: 1 (1)
Здравствуйте, Рысцов Денис, Вы писали:

РД>Решил попрактиковаться в написании макросов и реализовал прямую (и медленную) реализацию активных паттернов. Планирую использовать библиотеку для декомпозиции сложных и длинных правил при pattern matching'е в своих home pet проектах.


РД>Несколько примеров доступны по ссылке — http://code.google.com/p/nemerleactivepatterns/source/browse/Test/Main.n, собственно как и исходники проекта. Может быть кому-нибудь будет интересно


А может лучше в Nemerle/snippets, так можно будет потом и в инсталлятор добавить
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[6]: Как сделать активные паттрены.
От: VladD2 Российская Империя www.nemerle.org
Дата: 19.10.10 19:59
Оценка: :)
Здравствуйте, catbert, Вы писали:

C>Вообще, не могу придумать ни одного юз-кейса к фиче, который не сводился бы разбору по свойствам.


На мой взгляд — это результат погони за общностью реализации. Некоторым товарищам общность важнее производительности, а иногда и здравого смыла.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[6]: Как сделать активные паттрены.
От: Jack128  
Дата: 20.10.10 05:53
Оценка: +1
Здравствуйте, VladD2, Вы писали:

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


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


VD>В мои планы и не входила реализация этих финтифлюшек.


ну так бы сразу и сказал. А то тема то назвывается активные паттрены, а не "ПМ по свойствам объекта"
Re[9]: Как сделать активные паттрены.
От: Воронков Василий Россия  
Дата: 20.10.10 09:10
Оценка: +1
Здравствуйте, WolfHound, Вы писали:

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

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

ИМХО тут было бы интересней другое. Хотелось бы сначала понять, что фича в таком виде действительно полезна. Скажем, мне неясно, что мешает просто написать функцию-конвертер, превращающую исходный объект в вариант, и вызывать ее до входа в матч — при этом никаких изменений в язык вводить не требуется.
То, что это есть в F# по большому счету не есть критерий полезности фичи, в F# много весьма "академических" и чисто экспериментальных вещей. Я бы для примера смотрел на более практичный и широко используемый язык.
Re[2]: Как сделать активные паттрены.
От: catbert  
Дата: 08.11.10 19:34
Оценка: +1
Здравствуйте, Рысцов Денис, Вы писали:

РД>Решил попрактиковаться в написании макросов и реализовал прямую (и медленную) реализацию активных паттернов. Планирую использовать библиотеку для декомпозиции сложных и длинных правил при pattern matching'е в своих home pet проектах.


РД>Несколько примеров доступны по ссылке — http://code.google.com/p/nemerleactivepatterns/source/browse/Test/Main.n, собственно как и исходники проекта. Может быть кому-нибудь будет интересно


Ну вот, собственно, Nemerle-way для активных паттернов
Re: Как сделать активные паттрены.
От: VladD2 Российская Империя www.nemerle.org
Дата: 19.10.10 11:54
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>1)Можно в паттернах использовать функции.

WH>Первый аргумент (в случае методов this) будет принимать тот объект который матчим.
WH>Если есть еще аргументы их нужно будет указать явно.
WH>Возвращаемое значение и out параметры будут возвращаемыми значениями паттерна.
WH>Их можно связать с переменной или счемнибудь сматчить.

Вот эта функция и съест всю производительность. Меж тем весь механизм имеется. Например, следующий код работает:
using System.Console;

[Record]
class A
{
  public Prop1 : int { get; set; }
}

[Record]
class B : A
{
  public Prop2 : A { get; set; }
}

module Program
{
  Main() : void
  {
    def a : A = B(1, B(2, null));

    match (a)
    {
      | B where(Prop1=1, Prop2=B where(Prop1=2)) => WriteLine("OK");
      | _ => WriteLine("Fail");
    }
  }
}

/*
BEGIN-OUTPUT
OK
END-OUTPUT
*/


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

WH>Тогда можно будет делать так

WH>
WH>match (someString)
WH>{
WH>    | string.IsNullOrEmpty(true) =>
WH>    | int.TryParse(value, true) =>
WH>    | Contains("qwe", true) =>
WH>    | Contains("asd", true) =>
WH>    | Contains("zxc", true) =>
WH>}
WH>


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

...
    def a : A = B(1, B(2, null));

    match (a)
    {
      | B(1, B(2, _)) => WriteLine("OK");
      | _ => WriteLine("Fail");
    }
...

А вот функции нам особо не нужны. Ну, или это какой-то совершенно другой случай.

Так вот для того чтобы такой код стал возможен нам нужно всего лишь научиться передавать компилятору описание отображения параметров вымышленного конструктора на члены класса. Например, это можно сделать так:
[assembly: PatternMatchingCtorMapping(B(prop1=Prop1, prop2=Prop2))]

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

WH>Для функций возвращающих bool имеет смысл ввести сахар который матчит возвращаемое значенис с true.

WH>Тогда код станет таким
WH>
WH>match (someString)
WH>{
WH>    | string.IsNullOrEmpty =>
WH>    | int.TryParse(value) =>
WH>    | Contains("qwe") =>
WH>    | Contains("asd") =>
WH>    | Contains("zxc") =>
WH>}
WH>


Это и сейчас делается с помощью защитников (when ...). Я бы не отаказался если бы защитники можно было бы внедрить в паттерн, так как это позволит делать более сложные рекрсивыне паттерны. Но подобную переделку точно нужно отложить до 2.0.

WH>Эта функциональность перекрывает твой "виртуальный конструктор" с большим запасом.


Это будет "тормоз", так как потребуются действия в рантайме, и сильное изменение компилятора.

WH>Просто пишем такую функцию:

WH>
WH>SomeTypeVirtualConstructor(obj : SomeType, field1 : out Type1, field3 : out Type4, field6 : out Type21) : void
WH>{
WH>    field1 = obj.field1;
WH>    field3 = obj.field3;
WH>    field6 = obj.field6;
WH>}
WH>

WH>В качестве бонуса можно возвращать bool и проверять состояние объекта.

Здорово! И это реализовано в Скале, если не ошибаюсь. Но все же это не то.

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

В общем, как дополнительно расширение для 2.0 — это приемлемо.

Но тем не менее декларативное объявление виртуального конструктора удобнее и проще в реализации. Его можно и в этой версии реализовать.

WH>2)Функции конечно хорошо но bool не всегда достаточно...


Поскипанное вообще мрак. Целый огород на ровном месте. Это я бы просто отправил в лес.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[2]: Как сделать активные паттрены.
От: catbert  
Дата: 19.10.10 16:07
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Вот эта функция и съест всю производительность. МНам нужно только придумать как описать для компилятора вымышленный конструктор для класса и связать параметры этого конструктора с членами класса (полями или свойствами).


А почему, собственно, функция съест производительность, а свойства не съедят?
Re[3]: Как сделать активные паттрены.
От: VladD2 Российская Империя www.nemerle.org
Дата: 19.10.10 16:12
Оценка:
Здравствуйте, catbert, Вы писали:

C>А почему, собственно, функция съест производительность, а свойства не съедят?


А нет никаких свойств. Декларация подразумеваемого конструктора нужна только в качестве метаинформции — подсказки компилятору о том как надо разбирать паттерн. В конечном коде будет прямая работа с объектом.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[4]: Как сделать активные паттрены.
От: Jack128  
Дата: 19.10.10 18:53
Оценка:
Здравствуйте, VladD2, Вы писали:

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


C>>А почему, собственно, функция съест производительность, а свойства не съедят?


VD>А нет никаких свойств. Декларация подразумеваемого конструктора нужна только в качестве метаинформции — подсказки компилятору о том как надо разбирать паттерн. В конечном коде будет прямая работа с объектом.


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

как ты предлагаешь хотя бы самый простой пример описывать?:
let (|Even|Odd|) i = if i % 2 = 0 then Even else Odd
Re[5]: Как сделать активные паттрены.
От: catbert  
Дата: 19.10.10 18:59
Оценка:
Здравствуйте, Jack128, Вы писали:

J>как ты предлагаешь хотя бы самый простой пример описывать?:

J>
J>let (|Even|Odd|) i = if i % 2 = 0 then Even else Odd
J>


Проблема с самыми простыми примерами — они не дают представления о чем фича.
Почему не написать if (i % 2) ... else ...; ?

Вообще, не могу придумать ни одного юз-кейса к фиче, который не сводился бы разбору по свойствам.
Re[6]: Как сделать активные паттрены.
От: Jack128  
Дата: 19.10.10 19:07
Оценка:
Здравствуйте, catbert, Вы писали:

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


J>>как ты предлагаешь хотя бы самый простой пример описывать?:

J>>
J>>let (|Even|Odd|) i = if i % 2 = 0 then Even else Odd
J>>


C>Проблема с самыми простыми примерами — они не дают представления о чем фича.

C>Почему не написать if (i % 2) ... else ...; ?

C>Вообще, не могу придумать ни одного юз-кейса к фиче, который не сводился бы разбору по свойствам.


ну вот посложение пример:

match str with
| DateTime dt -> "это - дата"
| Integer i -> "это - число"
| Float d -> "это - вещ. число"
| _ -> "а хз, что это такое"
Re[6]: Как сделать активные паттрены.
От: Рысцов Денис  
Дата: 19.10.10 19:31
Оценка:
Здравствуйте, catbert, Вы писали:

C>Вообще, не могу придумать ни одного юз-кейса к фиче, который не сводился бы разбору по свойствам.


Насколько я понял одна из хороших сторон активных паттернов — декомпозиция: если match разросся до внушительных размеров из-за правил (части, которые после '|' и до '=>'), то обычными средствами сократить код не получится и получается неудобочитаемая каша. Активные паттерны позволяют внести правила в отдельные функции и, таким образом, сократить тело match.
Re[5]: Как сделать активные паттрены.
От: VladD2 Российская Империя www.nemerle.org
Дата: 19.10.10 19:53
Оценка:
Здравствуйте, Jack128, Вы писали:

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


В мои планы и не входила реализация этих финтифлюшек.

J>как ты предлагаешь хотя бы самый простой пример описывать?:

J>
J>let (|Even|Odd|) i = if i % 2 = 0 then Even else Odd
J>


А зачем оно нужно то? Чем хуже:
if (i %|| 2) a else b

?

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

Как я уже сказал, в 2.0, если у кого-то будет желание и время можете реализовать описанную Вольфхаундом идею. А ПМ по объектам можно и в 1.0 добавить.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[7]: Как сделать активные паттрены.
От: VladD2 Российская Империя www.nemerle.org
Дата: 19.10.10 20:03
Оценка:
Здравствуйте, Jack128, Вы писали:

J>ну вот посложение пример:


J>
J>match str with
J>| DateTime dt -> "это - дата"
J>| Integer i -> "это - число"
J>| Float d -> "это - вещ. число"
J>| _ -> "а хз, что это такое"
J>


Ага. Отлично демонстрирует бесполезность данной фичи. Взять и затормозить код который можно написать так же кратко и понятно, но быстро и без выпендрежей:
match (str)
{
  | dt is DateTime => "это - дата"
  | i  is int      => "это - число"
  | d  is float    => "это - вещ. число"
  | _              => "а хз, что это такое"
}


В общем, понятно, что придумать что-то наверно можно. Только вот реального преимущество от этого будет стремиться к нулю, время будет тратиться на создание объектов, плюс потребуется тратить время на доработку компилятора.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[7]: Как сделать активные паттрены.
От: VladD2 Российская Империя www.nemerle.org
Дата: 19.10.10 20:05
Оценка:
Здравствуйте, Рысцов Денис, Вы писали:

РД>Насколько я понял одна из хороших сторон активных паттернов — декомпозиция: если match разросся до внушительных размеров из-за правил (части, которые после '|' и до '=>'), то обычными средствами сократить код не получится и получается неудобочитаемая каша. Активные паттерны позволяют внести правила в отдельные функции и, таким образом, сократить тело match.


И заодно его затормозить, так как появляются объекты которые ранее отсутствовали, а вызов приводит к тому, что алгоритм построения дерева решений не сможет высчитать оптимальное дерево и скатится к последовательному перебору.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[8]: Как сделать активные паттрены.
От: Jack128  
Дата: 20.10.10 05:47
Оценка:
Здравствуйте, VladD2, Вы писали:

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


J>>ну вот посложение пример:


J>>
J>>match str with
J>>| DateTime dt -> "это - дата"
J>>| Integer i -> "это - число"
J>>| Float d -> "это - вещ. число"
J>>| _ -> "а хз, что это такое"
J>>


VD>Ага. Отлично демонстрирует бесполезность данной фичи. Взять и затормозить код который можно написать так же кратко и понятно, но быстро и без выпендрежей:

VD>
VD>match (str)
VD>{
VD>  | dt is DateTime => "это - дата"
VD>  | i  is int      => "это - число"
VD>  | d  is float    => "это - вещ. число"
VD>  | _              => "а хз, что это такое"
VD>}
VD>


Мне казалось, что название перемнной должно явно указать на её тип. str — это строка. у меня не тип тестируется, а содержимое строки.

аналог на си шарпе

if (DateTime.Parse(str, out dt)) return "это - дата"; else
if (int.TryParse(str, out i)) return "это - чисто"; else
if (float.TryParse(str, out d) return "это - вещ. число"; else
return "а хз, что это такое";
Re[6]: Как сделать активные паттрены.
От: Воронков Василий Россия  
Дата: 20.10.10 06:40
Оценка:
Здравствуйте, catbert, Вы писали:

C>Проблема с самыми простыми примерами — они не дают представления о чем фича.

C>Почему не написать if (i % 2) ... else ...; ?

Фича, мне казалось, "о том", чтобы собрать в кучку весь императивный код, спрятать его в этом самом актив паттерне, а наружу выставить красивую декларативную хрень. Ведь насколько же лучше будут выглядеть эти псевдоконструкторы Event/Odd по сравнению с твоим if.
Re[8]: Как сделать активные паттрены.
От: WolfHound  
Дата: 20.10.10 08:34
Оценка:
Здравствуйте, VladD2, Вы писали:

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

Ты споришь со страшилками которые ты сам выдумал.
Прочитай внимательно то что я сейчас напишу.
Берем код:
pattern Asdasdasd
{
    | Asd { a : int; b : string; x : float; }
    | Qwe { c : string; d : int; }

    match (value : SomeType)//*
    {
    ...
    }
}

И вот такой матч
match (someTypeValue)
{
    | Asd (a, b, x) =>
    | Qwe (c, d) =>
}

Сколько раз управление попадет в метод отмеченый *?
Правильный ответ: один.

Сколько объектов создает этот код не считая тех что программист явно создал внутри функции?
class Asdasdasd
{
    public enum Patterns
    {
        [ArgumentsMap("1 2 3", "a b x")]//Это метаданные для того чтобы из других сборок можно было использовать
        | Asd
        [ArgumentsMap("2 1", "c d")]
        | Qwe
    }

    public Match (value : SomeType, res1 : out int, res2 : out string, res3 : out float) : Patterns
    {
        ...
    }
}

Правильный ответ: 0.

Можно ли использовать опкод switch если у нас много вариантов?
Правильный ответ: да.

Так что где ты тут нашол тормоза я не понимаю.
Хватит уже спорить со своим воображением.
... << RSDN@Home 1.2.0 alpha 4 rev. 1472>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[7]: Как сделать активные паттрены.
От: VladD2 Российская Империя www.nemerle.org
Дата: 20.10.10 09:03
Оценка:
Здравствуйте, Jack128, Вы писали:

J>ну так бы сразу и сказал. А то тема то назвывается активные паттрены, а не "ПМ по свойствам объекта"


Тема является развитием сообщения на которое приведена ссылка в начале темы.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[9]: Как сделать активные паттрены.
От: VladD2 Российская Империя www.nemerle.org
Дата: 20.10.10 09:10
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>Ты споришь со страшилками которые ты сам выдумал...


Пока что я вижу сложное, не рекурсивное решине которое еще к тому же требуте каких-то рантайм-вызовов.

И это в то время когда есть простое решение не трбующее рантайм-вызовов и легко реализуемое без серьезного изменения компилятора.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[9]: Как сделать активные паттрены.
От: VladD2 Российская Империя www.nemerle.org
Дата: 20.10.10 09:35
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>Берем код:

WH>
WH>pattern Asdasdasd
WH>{
WH>    | Asd { a : int; b : string; x : float; }
WH>    | Qwe { c : string; d : int; }

WH>    match (value : SomeType)//*
WH>    {
WH>    ...
WH>    }
WH>}
WH>

WH>И вот такой матч
WH>
WH>match (someTypeValue)
WH>{
WH>    | Asd (a, b, x) =>
WH>    | Qwe (c, d) =>
WH>}
WH>

WH>Сколько раз управление попадет в метод отмеченый *?
WH>Правильный ответ: один.

Тут еще вопрос — зачем мне писать кучу ненужного кода, когда задача — упростить синтаксис ПМ по объектам?
Ты не забыл какую задачу надо было решить в начале?

Представь себе здадчу — нам нужно написать LINQ-провайдер. Для этого нужно разбирать с помощью ПМ деревья объектов составляющих Expression tree. Там куча дремучих иерархий. Для каждой из них мне потребуется написать вот такой вот "pattern". Получится гора кода. Плю мы получаем кучу вызовов в рнтайме и менее эффективный код. В случае же с декларативным подходом мы просто описываем отображение конструкторов для каждого типа и приступаем к работе. При этом генерируется оптимальный код. Никаких проблем с рекурсией и т.п. В общем, простой, быстрое и декларативное решение. Единственная беда — конкретное, а не абстракное. Но беда ли это?

В ощем, если у тебя еще не пропадет желание, можешь попробовать реализовать вою задумку в 2.0. А отображение кострукторов стоит сделать уже сейчас.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[7]: Как сделать активные паттрены.
От: VladD2 Российская Империя www.nemerle.org
Дата: 20.10.10 09:41
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

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


Для этого есть функции (инкапсуляция). Идея инкапсуляции для паттернов мне нравится. Но это слишком сложно и не очень шустро.

Получается, что реальная проблема — рыхлый синтаксис — подменяется введением навороченного решения которое чтобы реализовать надо встать раком и при реализации которого по всей видимости не удастся обойтись без рантайм-оверхэда.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[10]: Как сделать активные паттрены.
От: WolfHound  
Дата: 20.10.10 09:54
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Тут еще вопрос — зачем мне писать кучу ненужного кода, когда задача — упростить синтаксис ПМ по объектам?

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

Трмоза и "не рекурсивность" это твое воображение.

И я даже и не думал встраивать это в 1.0
Там вывод типов и построитель решений придется весьма не слабо покорежить. В прочем их по любому нужно полностью переписывать.
... << RSDN@Home 1.2.0 alpha 4 rev. 1472>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[8]: Как сделать активные паттрены.
От: Воронков Василий Россия  
Дата: 20.10.10 10:02
Оценка:
Здравствуйте, VladD2, Вы писали:

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

VD>Для этого есть функции (инкапсуляция). Идея инкапсуляции для паттернов мне нравится. Но это слишком сложно и не очень шустро.

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

Основная фишка актив паттернов, если мне не изменяет маразм, это то, что они позволяют имитировать row type полиморфизм. Опять же — с одной стороны круто. С другой — тоже неясно, насколько это востребованно. Потом, если нужен row type полиморфизм, почему бы не вводить его явно, как в OCaml? При этом ценность актив паттернов как фичи тут же падает, и ничего, кроме сахара, не остается.

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


Ну честно то, что Вольфхаунд предлагает, мне вообще не понятно. Может, я не "секу фишку"? Зачем мне делать:

pattern Asdasdasd
{
    | Asd { a : int; b : string; x : float; }
    | Qwe { c : string; d : int; }

    match (value : SomeType)//*
    {
    ...
    }
}


match (someTypeValue)
{
    | Asd (a, b, x) =>
    | Qwe (c, d) =>
}


Когда я могу написать:

match (ToAsdQwe <| someTypeValue)
{
    | Asd (a, b, x) =>
    | Qwe (c, d) =>
}
Re[9]: Как сделать активные паттрены.
От: WolfHound  
Дата: 20.10.10 10:18
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Ну честно то, что Вольфхаунд предлагает, мне вообще не понятно. Может, я не "секу фишку"? Зачем мне делать:

А попробуй вот это переписать:
pattern Asdasdasd
{
    | Asd { a : int; b : SomeType; x : float; }
    | Qwe { c : string; d : int; }

    match (value : SomeType)//*
    {
    ...
    }
}

match (someTypeValue)
{
    | Asd (a1, Asd (a2, b, x2), x1) =>
    | Asd (a, Qwe (c, d), x) =>
    | Qwe (c, d) =>
}

Это не считая того что твой вариант медленней.
... << RSDN@Home 1.2.0 alpha 4 rev. 1472>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[10]: Как сделать активные паттрены.
От: Воронков Василий Россия  
Дата: 20.10.10 11:01
Оценка:
Здравствуйте, WolfHound, Вы писали:

ВВ>>Ну честно то, что Вольфхаунд предлагает, мне вообще не понятно. Может, я не "секу фишку"? Зачем мне делать:

WH>А попробуй вот это переписать:

Переписать что? У тебя же внутри match троеточие У меня там тоже... эээ... "троеточие". Вернее, функция ToAsdQwe будет рекурсивной, что в принципе на объеме кода практически не скажется.

WH>Это не считая того что твой вариант медленней.


Ты, видимо, забыл главную мантру ФП — No premature optimization.

Кстати, раз уж зашла речь... Как в твоей реализации будет выглядеть вот такое:

let (|DivisibleBySeven|_|) input = if input % 7 = 0 then Some() else None

let (|IsPerfectSquare|_|) (input : int) = 
    let sqrt = int (Math.Sqrt(float input))
    if sqrt * sqrt = input then 
        Some() 
    else 
        None

let describeNumber x =
    match x with
    | DivisibleBySeven & IsPerfectSquare -> printfn "x is divisible by 7 and is a perfect square."
    | DivisibleBySeven                   -> printfn "x is divisible by seven"
    | IsPerfectSquare                    -> printfn "x is a perfect square"
    | _                                  -> printfn "x looks normal."
Re[11]: Как сделать активные паттрены.
От: WolfHound  
Дата: 20.10.10 11:27
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Переписать что? У тебя же внутри match троеточие У меня там тоже... эээ... "троеточие". Вернее, функция ToAsdQwe будет рекурсивной, что в принципе на объеме кода практически не скажется.

Выделенное
| Asd (a1, Asd (a2, b, x2), x1) =>
| Asd (a, Qwe (c, d), x) =>
| Qwe (c, d) =>

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

WH>>Это не считая того что твой вариант медленней.

ВВ>Ты, видимо, забыл главную мантру ФП — No premature optimization.
Не правильно.
Не оптимизируей руками.

ВВ>Кстати, раз уж зашла речь... Как в твоей реализации будет выглядеть вот такое:

Для тех кто не читал первое сообщение показываю:
def DivisibleBySeven(input) { input % 7 = 0 }

def IsPerfectSquare(input : int)
{
    def sqrt = int (Math.Sqrt(float input));
    sqrt * sqrt = input
}

def describeNumber(x)
{
    match (x)
    {
        | DivisibleBySeven & IsPerfectSquare => WriteLine("x is divisible by 7 and is a perfect square.")
        | DivisibleBySeven                   => WriteLine("x is divisible by seven")
        | IsPerfectSquare                    => WriteLine("x is a perfect square")
        | _                                  => WriteLine("x looks normal.")
    }
}

Вот прямо так.
Обычными функциями.
... << RSDN@Home 1.2.0 alpha 4 rev. 1472>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[12]: Как сделать активные паттрены.
От: Воронков Василий Россия  
Дата: 20.10.10 11:39
Оценка:
Здравствуйте, WolfHound, Вы писали:

ВВ>>Переписать что? У тебя же внутри match троеточие У меня там тоже... эээ... "троеточие". Вернее, функция ToAsdQwe будет рекурсивной, что в принципе на объеме кода практически не скажется.

WH>Выделенное
WH>
WH>| Asd (a1, Asd (a2, b, x2), x1) =>
WH>| Asd (a, Qwe (c, d), x) =>
WH>| Qwe (c, d) =>
WH>

WH>Пожалуйста читай то что тебе пишут.
WH>Мне уже надоело говорить с людьми которые даже не пытаются читать то что я пишу.

Что выделенное? У меня своя рукописная функция ToAsdQwe, которая принимает someTypeValue и возвращает экземпляр варианта. Определение варианта может быть рекурсивным. Может быть каким угодно. Кроме такого, которое запрещает система типов.

WH>>>Это не считая того что твой вариант медленней.

ВВ>>Ты, видимо, забыл главную мантру ФП — No premature optimization.
WH>Не правильно.
WH>Не оптимизируей руками.

И чем же ты собрался оптимизировать?

WH>def describeNumber(x)

WH>{
WH> match (x)
WH> {
WH> | DivisibleBySeven & IsPerfectSquare => WriteLine("x is divisible by 7 and is a perfect square.")
WH> | DivisibleBySeven => WriteLine("x is divisible by seven")
WH> | IsPerfectSquare => WriteLine("x is a perfect square")
WH> | _ => WriteLine("x looks normal.")
WH> }
WH>}
WH>[/ocaml]

А чем это отличается от:

def describeNumber(x)
{
    match (x)
    {
        | _ when DivisibleBySeven(x) && IsPerfectSquare(x) => WriteLine("x is divisible by 7 and is a perfect square.")
        | _ when DivisibleBySeven(x)                   => WriteLine("x is divisible by seven")
        | _ when IsPerfectSquare(x)                    => WriteLine("x is a perfect square")
        | _                                  => WriteLine("x looks normal.")
    }
}


Ты мне давай честный вариант.
Для интриги давай добавим в коллекцию такую продукцию IsRemNotZero(rem), которая должна биндить rem к остатку при делении.
Re[13]: Как сделать активные паттрены.
От: WolfHound  
Дата: 20.10.10 12:01
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Что выделенное? У меня своя рукописная функция ToAsdQwe, которая принимает someTypeValue и возвращает экземпляр варианта. Определение варианта может быть рекурсивным. Может быть каким угодно. Кроме такого, которое запрещает система типов.

То выделеное.
Там может быть использован другой паттерн.
Что еще одну функцию писать будешь?
А не озвереешь?

ВВ>А чем это отличается от:

Хотябы тем что меньше букв.
Плюс можно написать так:
| SomePattern(DivisibleBySeven, IsPerfectSquare) =>

сравни с
| SomePattern(x1, x2) when DivisibleBySeven(x1) && IsPerfectSquare(x2) =>

Больше букв. Больше конструкций. Нужно придумывать имена, а потом искать их.

Вот эта конструкция в F#
let (|DivisibleBySeven|_|) input =

Не дает ничего по сравнению с обычной функцией.
По этому я ее порезал бритвой Оккама.

ВВ>Ты мне давай честный вариант.

ВВ>Для интриги давай добавим в коллекцию такую продукцию IsRemNotZero(rem), которая должна биндить rem к остатку при делении.
Отличный пример того что ты не читаешь то что я пишу.
Я в первом же сообщении показал как это сделать.
Повторяю второй раз:
match (someString)
{
    | string.IsNullOrEmpty =>
    | int.TryParse(value) =>
    | Contains("qwe") =>
    | Contains("asd") =>
    | Contains("zxc") =>
}

match (someDictionary)
{
    | TryGetValue("qwe", value) =>
    | TryGetValue("asd", value) =>
    | TryGetValue("zxc", value) =>
}
... << RSDN@Home 1.2.0 alpha 4 rev. 1472>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[14]: Как сделать активные паттрены.
От: Воронков Василий Россия  
Дата: 20.10.10 12:30
Оценка:
Здравствуйте, WolfHound, Вы писали:

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


ВВ>>Что выделенное? У меня своя рукописная функция ToAsdQwe, которая принимает someTypeValue и возвращает экземпляр варианта. Определение варианта может быть рекурсивным. Может быть каким угодно. Кроме такого, которое запрещает система типов.

WH>То выделеное.
WH>Там может быть использован другой паттерн.
WH>Что еще одну функцию писать будешь?

Я так понимаю, у меня есть определение вида:

variant AsdQwe
{
 | Asd { a : int; b : AsdQwe; x : float; }
 | Qwe { c : string; d : int; }
}
  
def val = ToAsdQwe(...);
 
match (val : AsdQwe) {
 | Asd(a1, Asd(a2, b, x2), x1) => {}
 | Asd(a, Qwe(c, d), x) => {}
 | Qwe(c, d) => {}
}


Что там внутри AsdQwe — хз. Зависит от входных данных. Как и в твоем случае, естественно. Может, придется еще одну функцию написать. Может, даже две. А может, и не придется.
Пока лишь понятно, что твой вариант должен быть как бы короче, но насколько и как короче — еще непонятно.

WH>А не озвереешь?


Не беспокойся. Я уже давно озверел. Теперь вот успокоительное пью.

WH>
WH>| SomePattern(x1, x2) when DivisibleBySeven(x1) && IsPerfectSquare(x2) =>
WH>

WH>Больше букв. Больше конструкций. Нужно придумывать имена, а потом искать их.

Ну разница в количестве букв пока не впечатляет. Да дело даже не в этом. Т.е. и это все? Тупо сахар и ничего больше?

WH>Вот эта конструкция в F#

WH>
WH>let (|DivisibleBySeven|_|) input = 
WH>

WH>Не дает ничего по сравнению с обычной функцией.
WH>По этому я ее порезал бритвой Оккама.

Она дает ровно то же самое, что ты пытаешься дать и своим "законопроектом". Скажем, partial pattern вида:

match x with
| Int 1 -> ...


Распарсит x и, в случае, если это целое, сравнит его с единицей. Если результат не равен 1, то мы переходим к следующему паттерну. Как это будет выглядеть в твоем случае? "Много букаф"?

И, кстати, тут у нас начинается интересное — все partial patterns по умолчанию irrefutable, т.е. мы можем успешно "пройти сопоставление" и с Int, и с String, и с Float и т.д. Причем у тебя судя по всему будет абсолютно та же петрушка. И вот что-то мне начинает казаться, что не все так хорошо с этим.

ВВ>>Ты мне давай честный вариант.

ВВ>>Для интриги давай добавим в коллекцию такую продукцию IsRemNotZero(rem), которая должна биндить rem к остатку при делении.
WH>Отличный пример того что ты не читаешь то что я пишу.

Ты не прав, читаю. Уже примерно половину прочитал.
Re[11]: Как сделать активные паттрены.
От: VladD2 Российская Империя www.nemerle.org
Дата: 20.10.10 17:19
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>Я с твоим воображение даже пытаться спорить не будут.


Мое воображение тут не причем. Это ты так объясняешь.

WH>И я даже и не думал встраивать это в 1.0


Тогда и обсуждать нечего. Я говорил о фичи которую можно добавить здесь и сейчас.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[9]: Как сделать активные паттрены.
От: VladD2 Российская Империя www.nemerle.org
Дата: 20.10.10 17:21
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Ну честно то, что Вольфхаунд предлагает, мне вообще не понятно. Может, я не "секу фишку"?


Судя по словам того же Вольфхаунда
Автор: WolfHound
Дата: 20.10.10
мне смысл тоже не понятен.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re: активные паттрены: перезагрузка :)
От: VladD2 Российская Империя www.nemerle.org
Дата: 20.10.10 18:11
Оценка:
Не люблю абстракции, так как они обычно приводят к массе трепа без понимания происходящего.

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

Так давайте разберем конкретный пример — работу с деревьями выражений.

Итак...

Дано System.Linq.Expressions.Expression и его наследники:
* BinaryExpression
* ConditionalExpression
* ConstantExpression
* InvocationExpression
* LambdaExpression
* ListInitExpression
* MemberExpression
* MemberInitExpression
* MethodCallExpression
* NewArrayExpression
* NewExpression
* ParameterExpression
* TypeBinaryExpression
* UnaryExpression

Задача:
Продемонстрировать как будет выглядеть необходимый код чтобы для данных типов можно было использовать упрощенный "конструкторный" синтаксис в сопоставлении с образцом. Например, чтобы можно было писать так:
match (someExpr)
{
  | Bin(ExpressionType.And, Const(1), Call(null, method, args)) => 
    // что-то делаем с method и args

  | _ => ...
}


В демонстрационном коде не должно быть никаких "..." и т.п. Код должен быть полным.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[3]: активные паттрены: перезагрузка :)
От: Рысцов Денис  
Дата: 20.10.10 21:33
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Не люблю абстракции, так как они обычно приводят к массе трепа без понимания происходящего.

VD>Что приведет к формированию эффективного кода без какого-либо рантайм-оверхэда.
VD>Собственно жду аналогичного описания для активных партернов.

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

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

Достаточно краткое и понятное введение в активные паттерны доступно по следующей ссылке: http://msdn.microsoft.com/en-us/library/dd233248.aspx

Ниже я привел пример на F# и "порт" на Nemerle

let (|Integer|_|) (str: string) =
   let mutable intvalue = 0
   if System.Int32.TryParse(str, &intvalue) then Some(intvalue)
   else None

let (|Float|_|) (str: string) =
   let mutable floatvalue = 0.0
   if System.Double.TryParse(str, &floatvalue) then Some(floatvalue)
   else None

let parseNumeric str =
   match str with
     | Integer i -> printfn "%d : Integer" i
     | Float f -> printfn "%f : Floating point" f
     | _ -> printfn "%s : Not matched." str



[Pattern] Integer(obj : string) : option[int]
{
  mutable intvalue = 0;
  if (int.TryParse(obj, out intvalue)) Some(intvalue) else None
}

[Pattern] Float(obj : string) : option[float]
{
  mutable floatvalue = 0;
  if (float.TryParse(obj, out floatvalue)) Some(floatvalue) else None
}

MatchExample(str : string) : string
{
  match(str)
  {
    | Integer(i) => $"str : int = $i"
    | Float(f) => $"str : float = $f"
    | _ => $"$str : Not matched"
  }
}


Реализация, я думаю, очевидна:

match(Integer(str))
{
  | Some(i) => $"str : int = $i"
  | _ => match(Float(str))
    {
      | Float(f) => $"str : float = $f"
      | _ => $"$str : Not matched"
    }
}


В принципе из реализации виден еще один юзкейс — это декомпозиция вложенных match.
Re[3]: активные паттрены: перезагрузка :)
От: IT Россия linq2db.com
Дата: 21.10.10 04:00
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Мое решение предполагает добавление следующих объявлений:

VD>
VD>[assembly: PMCtor(BinaryExpression,      Bin(conv=Conversion, left=Left, right=Right, method=Method))]
VD>[assembly: PMCtor(ConditionalExpression, If(ifFalse=IfFalse, ifTrue=IfTrue, cond=Test))]
VD>[assembly: PMCtor(ConstantExpression,    Const(value=Value))]
VD>[assembly: PMCtor(InvocationExpression,  Invoc(lambda=Expression, args=Arguments))]
VD>[assembly: PMCtor(LambdaExpression,      Lambda(parms=Parameters, body=Body))]
VD>[assembly: PMCtor(ListInitExpression,    ListInit(what=NewExpression, inits=Initializers))]
VD>[assembly: PMCtor(MemberExpression,      Member(obj=Expression, member=Member))]
VD>[assembly: PMCtor(MemberInitExpression,  MemberInit(what=NewExpression, bindings=Bindings))]
VD>[assembly: PMCtor(MethodCallExpression,  Call(obj=Object, method=Method, args=Arguments))]
VD>[assembly: PMCtor(NewArrayExpression,    New(ty=Type, inits=Expressions))]
VD>[assembly: PMCtor(NewExpression,         NewArray(ctor=Constructor, args=Arguments, bindings=Members))]
VD>[assembly: PMCtor(ParameterExpression,   Param(name=Name, ty=Type))]
VD>[assembly: PMCtor(TypeBinaryExpression,  Is(expr=Expression, ty=TypeOperand))]
VD>[assembly: PMCtor(UnaryExpression,       Unary(operator=Method, operand=Operand))]
VD>


Думаю, указание базового класса тоже понадобится, т.к. иерархии не всегда плоские. Ну и для одного типа желательна возможность указывать более одного шаблона.
Если нам не помогут, то мы тоже никого не пощадим.
Re[14]: Как сделать активные паттрены.
От: Jack128  
Дата: 21.10.10 05:57
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>Вот эта конструкция в F#

WH>
WH>let (|DivisibleBySeven|_|) input = 
WH>

WH>Не дает ничего по сравнению с обычной функцией.

он избавляет от вложенных матчей. представь, что DivisibleBySeven возвращает какой нить сложный объект, который тоже нужно отматчить..
Re[4]: активные паттрены: перезагрузка :)
От: Воронков Василий Россия  
Дата: 21.10.10 07:09
Оценка:
Здравствуйте, Рысцов Денис, Вы писали:

РД>
РД>let (|Integer|_|) (str: string) =
РД>   let mutable intvalue = 0
РД>   if System.Int32.TryParse(str, &intvalue) then Some(intvalue)
РД>   else None

РД>let (|Float|_|) (str: string) =
РД>   let mutable floatvalue = 0.0
РД>   if System.Double.TryParse(str, &floatvalue) then Some(floatvalue)
РД>   else None

РД>let parseNumeric str =
РД>   match str with
РД>     | Integer i -> printfn "%d : Integer" i
РД>     | Float f -> printfn "%f : Floating point" f
РД>     | _ -> printfn "%s : Not matched." str
РД>


Это мы уже обсуждали. Partial patterns хорошо, но ведь по сути что это как не сахар над when? Код вида

| Integer i ->

Полностью аналогичен

| _ when int.TryParse(val) => ...

Код вида

| Integer 42 ->

Полностью аналогичен

| _ when int.TryParse(val) && val == 42 => ...

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

А по поводу, являются ли актив паттерны чем-то большим чем сахаром — вернее, скажем, так, позволяют ли они сделать что-то такое, что нельзя десахаризировать в when — есть по кр. мере у меня лично большие сомнение. По-моему актив паттерны — это сахар и есть.
Re[5]: активные паттрены: перезагрузка :)
От: Jack128  
Дата: 21.10.10 07:54
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>А по поводу, являются ли актив паттерны чем-то большим чем сахаром — вернее, скажем, так, позволяют ли они сделать что-то такое, что нельзя десахаризировать в when — есть по кр. мере у меня лично большие сомнение. По-моему актив паттерны — это сахар и есть.


При такой постановке — любой язык программирования — сахар над машинным кодом.

Кстати — ТОЛЬКО через when актив патерны ты не рассахаришь, нужен еще набор вложенных match'ей.
Re[6]: активные паттрены: перезагрузка :)
От: Воронков Василий Россия  
Дата: 21.10.10 07:59
Оценка:
Здравствуйте, Jack128, Вы писали:

J>При такой постановке — любой язык программирования — сахар над машинным кодом.


Не совсем. Скажем, обычные паттерны можно представить через when, однако тогда компилятор не будет строить дерево достижимости, проверять, является ли match exhaustive, и все его вхождения станут irrefutable. Т.е. у нас изменится поведение.

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

J>Кстати — ТОЛЬКО через when актив патерны ты не рассахаришь, нужен еще набор вложенных match'ей.


Вложенные паттерны — без проблем. В when может быть любой expression. К тому же вариант Влада поддерживает вложенные паттерны, но прекрасно рассахаривается в when.
Вопрос — что конкретно в актив паттернах на самом деле не является сахаром? Какие случаи вариант Влада покрывать не будет? У меня есть большое подозрение, что такие случаев нет.
Re[7]: активные паттрены: перезагрузка :)
От: Jack128  
Дата: 21.10.10 08:49
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

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


J>>При такой постановке — любой язык программирования — сахар над машинным кодом.


ВВ>Не совсем. Скажем, обычные паттерны можно представить через when, однако тогда компилятор не будет строить дерево достижимости, проверять, является ли match exhaustive, и все его вхождения станут irrefutable. Т.е. у нас изменится поведение.


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


J>>Кстати — ТОЛЬКО через when актив патерны ты не рассахаришь, нужен еще набор вложенных match'ей.


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


ВВ>Вопрос — что конкретно в актив паттернах на самом деле не является сахаром?

ну если "настоящим паттерном" считать только те, для которым компилер может дерево достижимости, то ничего. Хотя и вообще ПМ это тоже сахар, потому что ничто не мешает компилятору проверить достижимость цепочки аналогичной цепочки if'ов.

ВВ>Какие случаи вариант Влада покрывать не будет? У меня есть большое подозрение, что такие случаев нет.

Э-э-э. Вариант Влада — это матч по свойствам объекта. Для любого варианта, где у объекта нету свойства, по которому мы хотим матчить, придется городить when.
Ну и как реюзать конкретный паттерн — не очень понятно.

match (someExpr)
{
| Bin(ExpressionType.And, Const(1), Call(null, method, args)) =>
// что-то делаем с method и args

| _ => ...
}

допустим мне нужно заюзать в другом месте аналогичный паттерн, мне его полностью копировать??
в F# можно было бы так написать:

let (|ExpressionOneAndStaticMethodCall|_|) = function
| Bin(ExpressionType.And, Const(1), Call(null, method, args)) -> Some (method, args)
| None

И потом юзать где нуно:
match exp
| ExpressionOneAndStaticMethodCall (method, args) ->
| ... -> ...
Re[15]: Как сделать активные паттрены.
От: WolfHound  
Дата: 21.10.10 08:54
Оценка:
Здравствуйте, Jack128, Вы писали:

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

Ну так функции тоже можно использовать во вложенных матчах
... << RSDN@Home 1.2.0 alpha 4 rev. 1472>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[7]: активные паттрены: перезагрузка :)
От: WolfHound  
Дата: 21.10.10 09:06
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Поэтому, извините, но на мой взгляд от них несет сахарной пудрой.

От почти 100% немерла несет сахороной пудрой.
Но если ее не будет немерле будет страшнее С++са.
Если не веришь отключи все стандартные макросы.
И попробуй пописать на базовом немерле.
Взвоешь минут через 10.

ВВ>Вопрос — что конкретно в актив паттернах на самом деле не является сахаром? Какие случаи вариант Влада покрывать не будет? У меня есть большое подозрение, что такие случаев нет.

В первом сообщении (которое ты так и не прочитал) этих случаев...
... << RSDN@Home 1.2.0 alpha 4 rev. 1472>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[8]: активные паттрены: перезагрузка :)
От: Воронков Василий Россия  
Дата: 21.10.10 09:13
Оценка:
Здравствуйте, WolfHound, Вы писали:

ВВ>>Поэтому, извините, но на мой взгляд от них несет сахарной пудрой.

WH>От почти 100% немерла несет сахороной пудрой.
WH>Но если ее не будет немерле будет страшнее С++са.
WH>Если не веришь отключи все стандартные макросы.
WH>И попробуй пописать на базовом немерле.
WH>Взвоешь минут через 10.

Я не против пудры. Но пудра должна быть реализована как пудра. Скажем, прекрасно понятно, что "if" это сахар, и он реализован по схеме, аналогичной той, которую сейчас предлагает Влад. Компилятор любезно генерит для тебя немножко кода.

ВВ>>Вопрос — что конкретно в актив паттернах на самом деле не является сахаром? Какие случаи вариант Влада покрывать не будет? У меня есть большое подозрение, что такие случаев нет.

WH>В первом сообщении (которое ты так и не прочитал) этих случаев...

Эти случаи из статьи "что такое актив паттерны и как с ними бороться". Кроме бесконечных конверсий в Integer из строки, можно ли придумать что-то *реально полезное*, что не будет по сути сводиться к разбору объекта по св-вам?

Плюс при желании вариант Влада можно, наверное, расширить, разрешив писать не только "разбор по полям", но и полноценные выражения.
Фактически тут лучше всего подходит этакий хитрый макрос, который будет "как бы актив паттерн" превращать с несколько более нудный код с использованием when.
Re[5]: активные паттрены: перезагрузка :)
От: Рысцов Денис  
Дата: 21.10.10 10:16
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>А по поводу, являются ли актив паттерны чем-то большим чем сахаром — вернее, скажем, так, позволяют ли они сделать что-то такое, что нельзя десахаризировать в when — есть по кр. мере у меня лично большие сомнение. По-моему актив паттерны — это сахар и есть.


Верно, активные паттерны можно реализовать через when, но тогда они потребуют чуть большего оверхэда, так как нужно будет использовать вместо одной функции — две: предикат и селектор, кроме того усложниться описание правил. Возвращаясь к примеру выше, перепишем правила Integer и Float
[PatternPredicate] IntegerPredicate(obj : string) : bool
{
  mutable intvalue = 0;
  int.TryParse(obj, out intvalue)
}

[PatternSelector] IntegerSelector(obj : string) : bool { int.Parse(obj) }

[PatternPredicate] FloatPredicate(obj : string) : bool
{
  mutable floatvalue = 0;
  float.TryParse(obj, out floatvalue)
}

[PatternSelector] FloatSelector(obj : string) : bool { float.Parse(obj) }

Тогда использование
match(str)
{
  | Integer(i) => $"str : int = $i"
  | Float(f) => $"str : float = $f"
  | _ => $"$str : Not matched"
}

Раскроется следующим образом:
match(str)
{
  | _ when IntegerPredicate(str) => match(IntegerSelector(str)){ | i => $"str : int = $i"}
  | _ when FloatPredicate(str) => match(FloatSelector(str)){ | f => $"str : float = $f"}
  | _ => $"$str : Not matched"
}

option позволяет объединить предикат и селектор в одну функцию и упростить описание правил.
Re: Как сделать активные паттрены.
От: catbert  
Дата: 21.10.10 13:14
Оценка:
Здравствуйте, WolfHound, Вы писали:

Мое дилетантское мнение таково: у матча есть вполне конкретная семантика. Он работает с типами данных и их свойствами (если не считать when-паттерна и встроенной синтактической поддержки списков).

Если нужна другая семантика, то не стоит перегружать match новыми и новыми видами образцов. Можно ведь просто ввести свой match.
Re[4]: активные паттрены: перезагрузка :)
От: VladD2 Российская Империя www.nemerle.org
Дата: 21.10.10 14:17
Оценка:
Здравствуйте, IT, Вы писали:

IT>Думаю, указание базового класса тоже понадобится, т.к. иерархии не всегда плоские.


Насколько я помню для алгоритма построения дерева вывода базовый тип не имеет значений. Код переписывается во что-то вроде:
if (x is Type1) // для каждого объектного паттерна
{
  def boundVar1 = ...;
  def boundVar2 = ...;
  def boundVarN = ...;
  // код обработчика
}
else if (x is Type1)
  ...


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

IT>Ну и для одного типа желательна возможность указывать более одного шаблона.


Думаю, что это будет сделать не сложно. Но при этом им придется давать разные имена. Например, для двух вариантов ConditionalExpression можно ввести два конструктора If и When.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[5]: активные паттрены: перезагрузка :)
От: VladD2 Российская Империя www.nemerle.org
Дата: 21.10.10 14:20
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>А по поводу, являются ли актив паттерны чем-то большим чем сахаром — вернее, скажем, так, позволяют ли они сделать что-то такое, что нельзя десахаризировать в when — есть по кр. мере у меня лично большие сомнение. По-моему актив паттерны — это сахар и есть.


Если эти замечательные активные паттерны позволяет объявлять связанные переменные и рекурсивные паттерны внутри них, то это будет больше чем сахар.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[7]: активные паттрены: перезагрузка :)
От: VladD2 Российская Империя www.nemerle.org
Дата: 21.10.10 14:22
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Не совсем. Скажем, обычные паттерны можно представить через when, однако тогда компилятор не будет строить дерево достижимости, проверять, является ли match exhaustive, и все его вхождения станут irrefutable. Т.е. у нас изменится поведение.


Справедливости ради для объектных паттернов достижимость тоже не проверяется.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[7]: активные паттрены: перезагрузка :)
От: VladD2 Российская Империя www.nemerle.org
Дата: 21.10.10 14:37
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Вопрос — что конкретно в актив паттернах на самом деле не является сахаром? Какие случаи вариант Влада покрывать не будет? У меня есть большое подозрение, что такие случаев нет.


Понятно какие! Случае когда эктив-паттерн будет сложной функцией производящей кучу вычислений.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[6]: активные паттрены: перезагрузка :)
От: Воронков Василий Россия  
Дата: 21.10.10 14:39
Оценка:
Здравствуйте, VladD2, Вы писали:

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


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

Под "не сахаром" я в данном случае подразумевал бы некую логику исполнения актив паттернов, которая отличалась бы от исполнения того же самого кода в блоке when. Я так понимаю — такой разницы нет. Раз ее нет — то введение еще одного "типа паттернов", который, как правильно заметил катберг, нарушает семантику ПМ, не очень-то оправдано. Вот этакий макрос для генерации кода — самое то.
Re[8]: активные паттрены: перезагрузка :)
От: Воронков Василий Россия  
Дата: 21.10.10 14:41
Оценка:
Здравствуйте, VladD2, Вы писали:

ВВ>>Вопрос — что конкретно в актив паттернах на самом деле не является сахаром? Какие случаи вариант Влада покрывать не будет? У меня есть большое подозрение, что такие случаев нет.

VD>Понятно какие! Случае когда эктив-паттерн будет сложной функцией производящей кучу вычислений.

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

Я бы сказал тут определенно видится этакий макрос, который позволит некрасивые императивные when превратить в красивые декларативный "как бы паттерн".
Re[8]: активные паттрены: перезагрузка :)
От: VladD2 Российская Империя www.nemerle.org
Дата: 21.10.10 14:43
Оценка:
Здравствуйте, Jack128, Вы писали:

J>Ну и как реюзать конкретный паттерн — не очень понятно.


J>match (someExpr)

J>{
J> | Bin(ExpressionType.And, Const(1), Call(null, method, args)) =>
J> // что-то делаем с method и args
J> | _ => ...
J>}

А в чем тут проблема? И method, и args имеют некоторый тип. Если это объекты, то их опять же можно описать в виде паттернов.

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


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

Если речь об одной сборке, то объявление будет видно во всей сборке.


J>в F# можно было бы так написать:


J>let (|ExpressionOneAndStaticMethodCall|_|) = function

J> | Bin(ExpressionType.And, Const(1), Call(null, method, args)) -> Some (method, args)
J> | None

J>И потом юзать где нуно:

J>match exp
J>| ExpressionOneAndStaticMethodCall (method, args) ->
J>| ... -> ...

Ой ли? И в другой сборке? Если это так, то на лицо нарушение сокрытия объектов, так как мы не указывали public для данной конструкции.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[8]: активные паттрены: перезагрузка :)
От: VladD2 Российская Империя www.nemerle.org
Дата: 21.10.10 14:45
Оценка:
Здравствуйте, WolfHound, Вы писали:

ВВ>>Поэтому, извините, но на мой взгляд от них несет сахарной пудрой.

WH>От почти 100% немерла несет сахороной пудрой.
WH>Но если ее не будет немерле будет страшнее С++са.
WH>Если не веришь отключи все стандартные макросы.
WH>И попробуй пописать на базовом немерле.
WH>Взвоешь минут через 10.

+1

ВВ>>Вопрос — что конкретно в актив паттернах на самом деле не является сахаром? Какие случаи вариант Влада покрывать не будет? У меня есть большое подозрение, что такие случаев нет.

WH>В первом сообщении (которое ты так и не прочитал) этих случаев...

И все же мы увидим реализацию предложенного мной примере с использованием предложенного тобой механизма?
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[8]: активные паттрены: перезагрузка :)
От: Воронков Василий Россия  
Дата: 21.10.10 14:52
Оценка:
Здравствуйте, VladD2, Вы писали:

ВВ>>Не совсем. Скажем, обычные паттерны можно представить через when, однако тогда компилятор не будет строить дерево достижимости, проверять, является ли match exhaustive, и все его вхождения станут irrefutable. Т.е. у нас изменится поведение.

VD>Справедливости ради для объектных паттернов достижимость тоже не проверяется.

Не строит, потому что просто нереализовано или есть какие-то принципиальные проблемы, которые делают это нереализуемым?
Re[7]: активные паттрены: перезагрузка :)
От: VladD2 Российская Империя www.nemerle.org
Дата: 21.10.10 16:09
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

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


ВВ>Позволяют. Но все равно это сахар.


Да что ты прицепился к этому сахару?
Считать что-то сахаром/не сахаром — это вопрос философский важно только полезна ли фича и насколько сложно ее реализовать.

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


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

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

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


Любую логику можно реализовать на when. Так что по твоим канонам все есть сахар.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[9]: активные паттрены: перезагрузка :)
От: VladD2 Российская Империя www.nemerle.org
Дата: 21.10.10 16:10
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>А сделать поддержку выражений — не только разбора по свойствам — в твоем варианте нельзя?


А что ты понимаешь под выражениями? В немерле вообще-то ПМ только по данным работает.

ВВ>Я бы сказал тут определенно видится этакий макрос, который позволит некрасивые императивные when превратить в красивые декларативный "как бы паттерн".


Это уже какой-то очень сложный макрос. Такое поведение лучше все же в компилятор засовывать.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[9]: активные паттрены: перезагрузка :)
От: VladD2 Российская Империя www.nemerle.org
Дата: 21.10.10 16:11
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Не строит, потому что просто нереализовано или есть какие-то принципиальные проблемы, которые делают это нереализуемым?


Потому что иерархия классов может быть очень сложной и потенциально расширяемой в рантайме (если классы не запечатаны, то можно загрузить сборку с другими наследниками).
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[8]: активные паттрены: перезагрузка :)
От: Воронков Василий Россия  
Дата: 22.10.10 06:40
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Да что ты прицепился к этому сахару?

VD>Считать что-то сахаром/не сахаром — это вопрос философский важно только полезна ли фича и насколько сложно ее реализовать.

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

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


А, ну да, у when свой собственный лексический скоп. Тогда просто через макрос, видимо, не получится.
Re[10]: активные паттрены: перезагрузка :)
От: Воронков Василий Россия  
Дата: 22.10.10 06:41
Оценка:
Здравствуйте, VladD2, Вы писали:

ВВ>>А сделать поддержку выражений — не только разбора по свойствам — в твоем варианте нельзя?

VD>А что ты понимаешь под выражениями? В немерле вообще-то ПМ только по данным работает.

Я имел в виду генерить сложные expression-ы для when на основе более простой декларативной записи. Но, видимо, так не выйдет.
Re[6]: активные паттрены: перезагрузка :)
От: Воронков Василий Россия  
Дата: 22.10.10 06:47
Оценка:
Здравствуйте, Рысцов Денис, Вы писали:

Float/Integer это все хорошо. Но честно говоря я в вашем примере вижу как то, что *не является* паттерном зачем-то выглядит как паттерн. Поведение при этом — такое же как у when. Например, если бы происходил парсинг и сравнение значение, то мы бы могли успешно "сопоставиться" с паттером Integer, однако сравнение не прошло бы, потом бы мы успешно "сопоставились" с Float и пр. В вашем примере — разбираемое значение одновременно может подходить и под Integer и под Float. Компилятор молчит, анализа достижимости нет. Переставьте местами Float и Integer — будет ворнинг?

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

Т.е. не то, чтобы я считаю, что "чистота концепции" есть главнейший приоритет, но мне кажется актив паттерны "портят" матч. При этом я просто не очень понимаю, зачем они вообще нужны. Какие могут реальные практичные сценарии их использования?
Re[7]: активные паттрены: перезагрузка :)
От: Рысцов Денис  
Дата: 22.10.10 10:15
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Переставьте местами Float и Integer — будет ворнинг?


Нет, конечно, у компилятора нет для этого информации, как и в случае применения when:

match(6)
{
  | x when x%2==0 => $"$x | 2"
  | x when x%3==0 => $"$x | 3"
}


ВВ>В вашем примере — разбираемое значение одновременно может подходить и под Integer и под Float.


Верно, выбирается первое, которое подходит

ВВ>Но честно говоря я в вашем примере вижу как то, что *не является* паттерном зачем-то выглядит как паттерн.


Это как посмотреть, в данном случае (Integer, Float) да, вряд ли это похоже на паттерн, но в большинстве случаев там будет функция, которая будет разбирать что-то, ниже напишу примеры. А что бы не вносить путаницу можно, как предложил catbert выделять match, который содержит активные паттерны, например так

active match(str)
{
  | Integer(i) => $"str : int = $i"
  | Float(f) => $"str : float = $f"
  | _ => $"$str : Not matched"
}

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

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


1. Разбор объектов, которые не являются вариантами. Данная функциональность уже есть в Nemerle, благодаря where выражению в правилах.
2. В случае, когда правила очень большие и их много сложно читать match, хочется сделать декомпозицию, а средств для неё нету. Активные паттерны выполняют так раз такую функцию.
3. Если в коде часто встречаются вложенные match, то скорее всего этот код можно переписать без них, так как активные паттерны разворачиваются как раз в вложенные match, следовательно, если их правильно подобрать, то получим более понятный код.
Re[9]: активные паттрены: перезагрузка :)
От: VladD2 Российская Империя www.nemerle.org
Дата: 22.10.10 13:49
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

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


ВВ>А, ну да, у when свой собственный лексический скоп. Тогда просто через макрос, видимо, не получится.


+1
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[3]: Как сделать активные паттрены.
От: catbert  
Дата: 08.11.10 19:42
Оценка:
Здравствуйте, catbert, Вы писали:

C>Здравствуйте, Рысцов Денис, Вы писали:


РД>>Несколько примеров доступны по ссылке — http://code.google.com/p/nemerleactivepatterns/source/browse/Test/Main.n, собственно как и исходники проекта. Может быть кому-нибудь будет интересно


Только вот с паттерном Sum я чего-то не понимаю. Почему называется "Sum" а там вычитание?
Re[4]: Как сделать активные паттрены.
От: Рысцов Денис  
Дата: 08.11.10 20:08
Оценка:
Здравствуйте, catbert, Вы писали:

C>Только вот с паттерном Sum я чего-то не понимаю. Почему называется "Sum" а там вычитание?


Так pattern matching это действие обратное конструктору, в данном случае "| Sum(2,x) => ..." нужно читать как "| 2+x => ...". Если разбирается 5, то логично, что x привязывается к 3, поэтому внутри Sum вычитание. Sum нельзя рассматривать как конструктор, это разбирающее правило.
Re[3]: Как сделать активные паттрены.
От: Рысцов Денис  
Дата: 09.11.10 11:53
Оценка:
Здравствуйте, _nn_, Вы писали:

__>А может лучше в Nemerle/snippets, так можно будет потом и в инсталлятор добавить


Я только за. Можно добавить код, а я затем убью отдельный проект, или можно добавить меня в коммитеры и я сам добавлю, мой google аккаунт — rystsov.denis.
Re[4]: Как сделать активные паттрены.
От: hardcase Пират http://nemerle.org
Дата: 09.11.10 12:09
Оценка:
Здравствуйте, Рысцов Денис, Вы писали:

РД>Здравствуйте, _nn_, Вы писали:


__>>А может лучше в Nemerle/snippets, так можно будет потом и в инсталлятор добавить


РД>Я только за. Можно добавить код, а я затем убью отдельный проект, или можно добавить меня в коммитеры и я сам добавлю, мой google аккаунт — rystsov.denis.


Напиши Владу



Я бы такой мощной штуке имя дал, чтоли:
deactivated : list[PExpr.Ref*PExpr*PExpr*list[PExpr]]
/* иЗвиНите зА неРовнЫй поЧерК */
Re[4]: Как сделать активные паттрены.
От: VladD2 Российская Империя www.nemerle.org
Дата: 09.11.10 15:36
Оценка:
Здравствуйте, Рысцов Денис, Вы писали:

РД>Я только за. Можно добавить код, а я затем убью отдельный проект, или можно добавить меня в коммитеры и я сам добавлю, мой google аккаунт — rystsov.denis.


Присылай гуглевое мыло, добавим.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[5]: Как сделать активные паттрены.
От: Рысцов Денис  
Дата: 09.11.10 16:42
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Присылай гуглевое мыло, добавим.


rystsov.denis ПЁС gmail.com
Re[6]: Как сделать активные паттрены.
От: VladD2 Российская Империя www.nemerle.org
Дата: 09.11.10 17:00
Оценка:
Здравствуйте, Рысцов Денис, Вы писали:

VD>>Присылай гуглевое мыло, добавим.


РД>rystsov.denis ПЁС ...


Готово.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.