Здравствуйте, VladD2, Вы писали:
VD>Кстати, всем кто улыбнулся прочтя твои строки, очень советую не пробовать немерл. Буквально месяц реального использования и от C# начинается натуральная ломка. Причем это даже если не написать ни одного собственного макроса. А на работе, ведь, могут не дать применять то что хочется.
Да я серьёзно, вот фрагмент одной штуки из одного секретного продукта, над которым я работаю:
private static IForeachStatement IsYieldForeachPattern(IYieldStatement yieldReturn, IType ienumerableType)
{
// detect "yield return $0;" where $0 - reference expressionvar yieldExpression = yieldReturn.Expression as IReferenceExpression;
if (yieldExpression == null) return null;
// detect if "yield return $0;" is right inside foreach statementvar foreachStatement = yieldReturn.Parent as IForeachStatement;
if (foreachStatement == null)
{
// ok, we may be inside single statement blockvar block = yieldReturn.Parent as IBlock;
if (block == null || block.Statements.Count != 1) return null;
foreachStatement = block.Parent as IForeachStatement;
if (foreachStatement == null) return null;
}
// detect if $0 resolves into foreach statement iteration variableif (foreachStatement.IteratorDeclaration == null) return null;
var target = foreachStatement.IteratorDeclaration.DeclaredElement;
var resolved = yieldExpression.Reference.Resolve().DeclaredElement;
if (!DeclaredElementEqualityComparer.ElementComparer.Equals(target, resolved)) return null;
// detect the type of foreach statement collection expressionif (foreachStatement.Collection == null) return null;
var collectionType = foreachStatement.Collection.Type();
if (collectionType.IsUnknown) return null;
// detect if foreach statement collection is convertible into IEnumerable<T>var conversionRule = foreachStatement.GetTypeConversionRule();
if (!conversionRule.IsImplicitlyConvertibleTo(collectionType, ienumerableType)) return null;
return foreachStatement;
}
Представляешь как этот треш мог бы выглядеть лишь благодаря паттерн-матчингу? Меня уже трясёт от:
var someNode = node as SomeNode;
if (someNode != null) {
...
}
и визиторов всяких.
VD>Я, вообще-то, тоже с юмором. Я ж тебя не первый год знаю.
А мне всегда кажется, что ты меня забываешь. Я к тебе на альтнетике даже знакомиться подходил, а ты сказал, что не знаешь такого
p.s. [немного оффтопа] кстати, а можно-ли на макросах "забабахать" automatic casts, как в Kotlin? Типа:
object x = 0;
if (x is int) {
int y = x + 1;
Console.WriteLine(y);
}
или типа:
void Foo(int? x) {
if (x != null) {
int y = x + 1; // никаких x.Value
...
}
}
То есть макросом поменять тип некоторой локальной переменной внутри некоторого скоупа. Если такое выражается макросом, то круто вообще!
Здравствуйте, Пельмешко, Вы писали:
П>Да я серьёзно, вот фрагмент одной штуки из одного секретного продукта, над которым я работаю:...
Ну, тогда еще раз извини. Просто народ язык не использовавший твои слова, скорее всего, воспримет как легкий стеб.
П>...Представляешь как этот треш мог бы выглядеть лишь благодаря паттерн-матчингу? Меня уже трясёт от: П>
Ну, да. Тут или говногод вглуб, или Посетители и куча болерплэйта в ширь.
Только вот ты даже понимая преимущества язык на практике не используешь, а люди с этого форума зачастую даже не понимаю, что все может быть по другому. Но судят, все равно, со своей колокольни.
Потому когда видишь вблизи Nemerle и , то невольно в голове возникает опять эти...
Сори.
VD>>Я, вообще-то, тоже с юмором. Я ж тебя не первый год знаю.
П>А мне всегда кажется, что ты меня забываешь. Я к тебе на альтнетике даже знакомиться подходил, а ты сказал, что не знаешь такого
Тут еще проблема, что я с трудом сомещаю IRL и ники на форумах. Плюс я тогда еще соображал в одну сторону. Когда "вещаешь" несколько часов мозг тупеет.
Так что еще раз приношу свои извинения.
Для лучшего знакомства нужно где-то собраться и тупо выпить.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, Пельмешко, Вы писали:
П>[немного оффтопа] кстати, а можно-ли на макросах "забабахать" automatic casts, как в Kotlin? Типа: П>
П>object x = 0;
П>if (x is int) {
П> int y = x + 1;
П> Console.WriteLine(y);
П>}
П>
или типа: П>
П>void Foo(int? x) {
П> if (x != null) {
П> int y = x + 1; // никаких x.Value
П> ...
П> }
П>}
П>
П>То есть макросом поменять тип некоторой локальной переменной внутри некоторого скоупа. Если такое выражается макросом, то круто вообще!
Можно.
Чтобы сделать это нужно или доработать стандартные макросы if/when, или ввести свой аналог (например null_guard). Но того же самого можно добиться воспользовавшись оператором match.
В Котлине же сделано нечто большее. Его авторы пытаются сделать язык null-защиденным. Тебе просто не дадут воспользоваться nulable-значением без проверки. Вот это в макросах сделать сложно (хотя и можно, если очень постараться).
На практике, лично мне хватает следующих фишек:
1. Возможности использовать паттерн-матчинг:
match (x)
{
| Some(x) => // "x" переопределен. Теперь это просто intdef y = x + 1; // никаких x.Value
...
| None => сообщаем об ошибке
}
2. Оператора ?? позволяющего задать нужное значение по умолчанию.
3. Оператор .? позаимствованный нами из Груви. Он позволяет делать так:
def a = x.?y.?z + 1;
Если переменная x или хотя бы одно из полей будет null, то в результате выражение x.?y.?z вернет 0, и в "a" окажется 1.
Как показала практика — это очень удобно и используется чаще всего.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, VladD2, Вы писали:
VD>3. Оператор .? позаимствованный нами из Груви. Он позволяет делать так: VD>
VD>def a = x.?y.?z + 1;
VD>
VD>Если переменная x или хотя бы одно из полей будет null, то в результате выражение x.?y.?z вернет 0, и в "a" окажется 1. VD>Как показала практика — это очень удобно и используется чаще всего.
Здравствуйте, Jack128, Вы писали:
П>>Представляешь как этот треш мог бы выглядеть лишь благодаря паттерн-матчингу?
J>А как он мог бы выглядеть? Вот как "?." здесь поможет упростить код я вижу, а чем пм поможет??
Так и поможет. Вместо этой каши будет что-то вроде:
match (yieldReturn.Parent)
{
| x is IForeachStatement => ...
| x is IBlock => ...
...
}
Но, если пресмотреться, то это разбор AST. В таких случаях AST описывается на основе вариантов и тогда можно будет распознавать сложные сочетания веток.
Следующий шаг — лфитинг и введение DSL-я для представления языка. Тогда работа будет вестись уже на совершенно другом уровне.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, VladD2, Вы писали:
VD>Но, если пресмотреться, то это разбор AST. В таких случаях AST описывается на основе вариантов и тогда можно будет распознавать сложные сочетания веток. VD>Следующий шаг — лфитинг и введение DSL-я для представления языка. Тогда работа будет вестись уже на совершенно другом уровне.
Здравствуйте, VladD2, Вы писали:
VD>Здравствуйте, Jack128, Вы писали:
П>>>Представляешь как этот треш мог бы выглядеть лишь благодаря паттерн-матчингу?
J>>А как он мог бы выглядеть? Вот как "?." здесь поможет упростить код я вижу, а чем пм поможет??
VD>Так и поможет. Вместо этой каши будет что-то вроде:
VD>
VD>match (yieldReturn.Parent)
VD>{
VD> | x is IForeachStatement => ...
VD> | x is IBlock => ...
VD> ...
VD>}
VD>
ну ты полный код опиши ? На Nemerle.
Если апи полностью на вариантах/АТД будет — тогда возможно проще будет, но в текущем варианте — линейный код будет заменен цепочной вложенных match'ей. Понятности это не прибавит.
Здравствуйте, YF, Вы писали:
VD>>Следующий шаг — лфитинг и введение DSL-я для представления языка. Тогда работа будет вестись уже на совершенно другом уровне.
YF>А что такое лифтинг?
Превращение структуры данных в код, котрый порождает эту структуру данных.
Здравствуйте, hardcase, Вы писали:
H>Здравствуйте, YF, Вы писали:
YF>>я правильно понимаю, что речь идет о макросе, который генерирует эту структуру данных?
H>Нет. Речь идет о квазицитатах. Квазицитаты превращаются в код, который порождает AST, записанное в цитате.
Квазицитаты во вхождениях PM поднимаются (lift) в обычные шаблоны для вариант (алгебраических типов).
Здравствуйте, YF, Вы писали:
YF>А что такое лифтинг?
С LINQ-ом знаком? Представляешь как выглядит дерево выражений? Вот в шарпе захардкожен лифтинг для подъема кода в деревья выражений. Но тоже самое можно делать с любым языком. А лифтинг — это, грубо говор, поднятие кода в его АСТ.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, Jack128, Вы писали:
J>Здравствуйте, Пельмешко, Вы писали:
П>>Представляешь как этот треш мог бы выглядеть лишь благодаря паттерн-матчингу?
J>А как он мог бы выглядеть? Вот как "?." здесь поможет упростить код я вижу, а чем пм поможет??
Поможет, если API задизайнено под него будет + куча active patterns (не помню как оно в немерлях называется).
Даже одинх automatic casts хватило бы чтобы заметно облегчить эту C#-лапшу...
Здравствуйте, Jack128, Вы писали:
J>ну ты полный код опиши ? На Nemerle.
А смысл? Если решать эту задачу на Немерле, то код буде совсем другой. Всех этих интерфейсов не будет в помине.
Если очень нужно легаси упростить, то тоже есть множество решений.
Например, лобовое:
def isYieldForeachPattern(stmt : IStatment)
{
| IStatment where(Parent=foreachStatement is IForeachStatement)
| IStatment where(Parent=IBlock where(Statements=st, Parent=foreachStatement is IForeachStatement)) when st.Count == 1 =>
def target = foreachStatement.IteratorDeclaration.DeclaredElement;
def resolved = yieldExpression.Reference.Resolve().DeclaredElement;
unless (DeclaredElementEqualityComparer.ElementComparer.Equals(target, resolved))
return null;
unless (foreachStatement?.Collection.Type().IsValid)
return null;
// detect if foreach statement collection is convertible into IEnumerable<T>def conversionRule = foreachStatement.GetTypeConversionRule();
if (conversionRule.IsImplicitlyConvertibleTo(collectionType, ienumerableType)) foreachStatement else null
| _ => null
}
При этом можно создать ExtensionPattern-Ы, которые будут выглядеть как паттерн-матчинг по вариантным типам, но на самом деле будет раскрываться в приведенные выше паттерны. Это позволит упростить код лобового решения и сделать его читабельным.
Естественно, можно написать макрос, который превращает три строки в одну.
Далее можно воспользоваться ComputationExpressions и создать билдер для монды Maby. В этом случае код будет выглядеть так:
Здравствуйте, Пельмешко, Вы писали:
П>...куча active patterns (не помню как оно в немерлях называется).
Есть и аналог active patterns из F#. Но они тормоза (в F#-е тоже) по своей природе. Но есть еще ExtensionPattern. Вот это то что доктор прописал! Они отлично подходят для сокрытия пушистости МП по ОО-типам.
Погляди пример МП по LINQ-овским деревьям выражений.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, Jack128, Вы писали:
J>но в текущем варианте — линейный код будет заменен цепочной вложенных match'ей. Понятности это не прибавит.
Ты просто не понимаешь всей мощи ПМ. Весь кайф ПМ в его рекурсивности. К примеру, вот такую кучу строк:
var yieldExpression = yieldReturn.Expression as IReferenceExpression;
if (yieldExpression == null) return null;
// detect if "yield return $0;" is right inside foreach statementvar foreachStatement = yieldReturn.Parent as IForeachStatement;
if (foreachStatement == null)
{
// ok, we may be inside single statement blockvar block = yieldReturn.Parent as IBlock;
if (block == null || block.Statements.Count != 1) return null;
foreachStatement = block.Parent as IForeachStatement;
if (foreachStatement == null) return null;
}
...
можно заменить одним составным паттерном:
| IStatment where(Parent=foreachStatement is IForeachStatement)
| IStatment where(Parent=IBlock where(Statements=st, Parent=foreachStatement is IForeachStatement)) when st.Count == 1 => ...
При этом проверки на null просто не нужны. Паттерн описывает объект. И если объект не соответствует из-за того, что где-то там в нем null-ы, то это не проблема, так как алгоритм построения дерева решений это учитывает автоматом.
Если паттерны кажутся длинными, то можно воспользоваться ExtensionPattern-ом и описать, например, такие расширения:
[assembly: ExtensionPattern(IStatment,
ParentForeach(foreachStatement)
= IStatment where(Parent=foreachStatement is IForeachStatement))]
[assembly: ExtensionPattern(IStatment,
ParentForeachBlock(foreachStatement, statements)
= IStatment where(Parent=IBlock where(Statements=statements, Parent=foreachStatement is IForeachStatement)))]
Здравствуйте, VladD2, Вы писали:
VD>На практике, лично мне хватает следующих фишек: VD>1. Возможности использовать паттерн-матчинг:
Было бы очень круто, если бы ПМ выражения можно было использовать в виде обычных булевых. При этом образцы сопоставления были бы видны в блоках if и when.
when (x is IDisposable) // некоторые паттерны уже работают как булевы, осталось доработать if/when
x.Dispose()
when (x matches [arg1, arg2]) // для остальных можно ввести оператор
{
f(arg1, arg2)
}
Здравствуйте, Ziaw, Вы писали:
Z>Было бы очень круто, если бы ПМ выражения можно было использовать в виде обычных булевых. При этом образцы сопоставления были бы видны в блоках if и when.
Z>when (x is IDisposable) // некоторые паттерны уже работают как булевы, осталось доработать if/when Z> x.Dispose()
Вот так как раз не работает, так как тип переменной не изменяется. Так что проверку можно сделать, но тип "х" останется прежним. Можно попробовать подправить.
Потенциально можно переделать макрос when и сделать так, чтобы он вводил для подобных случаев локальную неизменяемую переменную. Но это предотвратит возможность использовать исходную переменную внутри when. Меж тем как минимум одно такое применение есть в компиляторе:
mutable retTy = ty1;
when (!args1.IsEmpty && argsTys.Length == args1.Length)
{
NList.Iter2(args1, argsTys, trySetType);
when (retTy is PExpr.Wildcard)
retTy = PExpr.TypedType(ret);
}
Можно сделать поддержку для другого специального случая — использования оператора as. Тогда описанный тобой код будет выглядеть так:
when ((x is IDisposable) as x)
x.Dispose()
или даже:
when (x is IDisposable as x)
x.Dispose()
Ну, или можно отдельный оператор придумать.
Короче — технически это решается легко. Вопрос только в том, что нужно найти красивое синтаксическое решение.
Z>when (x matches [arg1, arg2]) // для остальных можно ввести оператор
Z>{
Z> f(arg1, arg2)
Z>}
А так, как раз можно. Только вместо устаревшего matches, нужно использовать is. В прочем, вариант со списком не захотел работать. Но я доработал макру when напильником, и теперь это работает.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, hardcase, Вы писали:
YF>>я правильно понимаю, что речь идет о макросе, который генерирует эту структуру данных?
H>Нет. Речь идет о квазицитатах.
На самом деле макросы могут квази-цитаты для хитрых языков реализовывать.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.