Здравствуйте, hi_octane, Вы писали:
R>>Чего не было (как сейчас не знаю), так это ref locals/ref return values, expression bodied methods, throw expressions _>throw expressions вроде были
R>Expression<Func<int,int>> f = i => i * 0 + 0 + i + 10 * (i * 0 + 2);
R>var f1 = f.TransformEx(ex => ex switch
R>{
R> Multiply(Constant(0) e, _) => e, // 0 * e => 0
R> Multiply(_, Constant(0) e) => e, // e * 0 => 0
R> Multiply(Constant(1), var e) => e, // 1 * e => e
R> Multiply(var e, Constant(1)) => e, // e * 1 => e
R> Divide (Constant(0) e, _) => e, // 0 / e => 0
R> Divide (var e, Constant(1)) => e, // e / 1 => e
R> Add (Constant(0), var e) => e, // 0 + e => e
R> Add (var e, Constant(0)) => e, // e + 0 => e
R> Subtract(Constant(0), var e) => Negate(e), // 0 - e => -e
R> Subtract(var e, Constant(0)) => e, // e - 0 => e
R> Multiply(Constant(int x), Constant(int y)) => Constant(x * y), // x * y => e
R> Divide (Constant(int x), Constant(int y)) => Constant(x / y), // x / y => e
R> Add (Constant(int x), Constant(int y)) => Constant(x + y), // x + y => e
R> Subtract(Constant(int x), Constant(int y)) => Constant(x - y), // x - y => e
R> _ => ex
R>});
R>Console.WriteLine(f);
R>Console.WriteLine(f1);
R>Assert.IsTrue(f1.EqualsTo(i => i + 20));
R>
О, а как это работает? Мне такое нужно, а то код арифметического упрощения похож на какие-то спагетти. Тут же ex какого-то особенного типа, не System.Linq.Expressions.Expression?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
S>>То, что появилось и нет в Nemerle больше нужно. Один async awaite чего стоит.
R>async/await есть в немерле. Я говорил об async streams, которые только вот появились в шарпе
Я про то, что изначально в Немерле не было async/await, Linq итд. И появились они не сразу.
Я к тому, что языки постоянно развиваются и берут друг у друга фичи.
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Sinclair, Вы писали:
S>О, а как это работает? Мне такое нужно, а то код арифметического упрощения похож на какие-то спагетти. Тут же ex какого-то особенного типа, не System.Linq.Expressions.Expression?
Да, перед матчингом выражение конвертируется в Expr, так как в Expression бинарные операции выражены просто через единый BinaryExpression, унарные — через UnaryExpression и т.п., что при матчинге наглядности не добавят, поэтому такой вот дополнительный шаг. Для полноты были написаны соответствующие методы расширения для деконструкции колекции параметров и инициализаторов. А для еще большей читаемости добавляем в начале файла:
using static Linq.Expressions.Deconstruct.Expr;
using static System.Linq.Expressions.Expression;
А дальше шарп уже сам включит всю магию паттерн-матчинга.
А да, также у Expr есть implicit оператор обратно в Expression
Здравствуйте, Serginio1, Вы писали:
S>Я про то, что изначально в Немерле не было async/await, Linq итд. И появились они не сразу.
Не сразу, это грубо говоря, недели две после
Здравствуйте, Serginio1, Вы писали:
S> Шарп развивается сейчас быстро и много фич из разных языков взято.
Это не может не радовать, только вот
S>Сейчас язык будет развиваться без оглядки на старый фреймворк и будут вводиться новые фичи в том числе и для Source Generators .
Хотелось бы, чтобы смелее смотрели на то, что вокруг сделано и как.
Здравствуйте, rameel, Вы писали:
R>Здравствуйте, Serginio1, Вы писали:
S>>Я про то, что изначально в Немерле не было async/await, Linq итд. И появились они не сразу. R>Не сразу, это грубо говоря, недели две после
Угу http://rsdn.org/forum/nemerle/7731140.flat
Здравствуйте, rameel, Вы писали:
R>Здравствуйте, Serginio1, Вы писали:
S>> Шарп развивается сейчас быстро и много фич из разных языков взято.
R>Это не может не радовать, только вот
S>>Сейчас язык будет развиваться без оглядки на старый фреймворк и будут вводиться новые фичи в том числе и для Source Generators .
R>Хотелось бы, чтобы смелее смотрели на то, что вокруг сделано и как.
Я к тому, что необходимость паттернматчинга и генерация кода в дизайн тайме очевидна. Почему так долго непонятно.
Но как только начал развиваться .Net Core количество изменений языка сразу выросло. Может это связано в том числе и с опен соурсом.
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, rameel, Вы писали:
Отлично. Попробовал. Есть ощущение, что возвёрнутые значения дальше не трансформируются. Т.е. трансформация работает только снизу вверх.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Я все же настоятельно рекомендую посмотреть документацию, не подумай, я не агитирую тебя писать на немерле, просто для саморазвития, тогда и вопросов будет меньше, а что не так. Немерле это как пример весьма удачной концепции compiler as plugin, реализация — это другой вопрос. Не нравятся слово немерле, посмотри на макросы раста. В немерле тоже не все есть. Мне например нравятся идея зависимых типов, хотел бы видеть, на худой конец возможность задавать контрактное поведение, чтобы зависимости и инварианты проверялись на этапе компиляции и полностью устранялись из машинного кода. Посмотри на идрис, агду или dafny, у которого синтаксис приятный/привычный. Вот кстати nullable reference, добавленный в шарп, можно сказать часть контракта, всего лишь часть от целого. Смотрели бы шире, добавили бы обобщение, а не только nullable, тогда можно было бы писать:
public static T Get<T>(T[] array, int index)
requires array != null
requires index >= 0 && index < array.Length
{
return array[index];
}
И все это проверялось бы еще на этапе компиляции. Гляди там и JIT научат смотреть на аннотации, тогда и null и bounds check'и устранятся. Для array != null можно и ? добавить как сейчас в шарпе.
Та же возможность вмешиваться в этап компиляции позволит прозрачно для пользователя переписывать linq в набор for и foreach, устранить косвенность, в точности и при вызове делегатов, устранить аллокации и даже слохпнуть это в константное выражение, когда можно. Бонусом, в большинстве случаев выражать Enumerator через структуры будет уже не надо.
А сейчас имеем, что имеем. Хочешь избежать мусора в памяти пиши for или енумератор на структурах, нужен индекс пиши for, нужен свитч по регулярке пиши if, хочешь lock над ReaderWriterLockSlim потрудись расписывать все через try-finally, нужна реализация для IEquatable — пиши сам, нужен dispose внутренних объектов — пиши и внимательно, никого не забудь, и таких вот мелочей куча. По отдельности некоторые вещи это мелочи вроде, но попробуй сейчас пересесть на шарп от второго фреймворка.
Вот сейчас полноценно в строй введут source-генераторы, то даже с тем, что есть (добавлять, не изменять), сколько всего будет сделано, что будет казаться и как раньше без этого жили то
Здравствуйте, Sinclair, Вы писали:
S>Отлично. Попробовал. Есть ощущение, что возвёрнутые значения дальше не трансформируются. Т.е. трансформация работает только снизу вверх.
Ну, то есть как это работает: допустим, у меня есть таблица для некоторых ParameterExpression, которая задаёт их пределы.
Типа {minA} <= {a} <= {maxA}.
Теперь у меня есть выражение типа (a + 1 > 0).
Я пытаюсь его свернуть. Как это делается?
При помощи правила, которое сопоставляет выражениям вида {a} > e вот такую кракозяблу (({a} > e) || (minA > e)) && (maxA > e)). (1)
Перед этим надо превратить (a + 1 > 0) в (a > -1). (2)
Но вот у меня правило, которое вызвалось на выражении LessThan(Add(var e, Constant(int x))), Constant(int y)), вернуло оно (a > -1) и всё, поезд ушёл. Трансформатор поехал выше.
Допустим, я запихал правило 2 в первую фазу, а правило 1 — во вторую фазу трансформации.
Теперь, скажем, когда у нас в качестве minA указан {0}, а maxA — {h}, мы получаем (({a} > {-1}) || ({0} > {-1})) && ({h} > {-1}))
Тут надо заново начинать трансформацию, т.к. {0} > {-1} => {true}, ({a} > {-1}) || {true})=>{true}, {true} && ({h} > {-1}) => ({h} > {-1}). Ок, это у нас была фаза трансформации №3 — свёртка AndAlso и OrElse с конст-аргументами.
Но теперь, получается, надо заново применять вторую фазу, т.к. из той же таблицы фактов мы знаем, что {h} >= {0}, и мы должны свернуть выражение в {true}.
Итого — либо мы гоняем цикл
Здравствуйте, rameel, Вы писали:
R>Здравствуйте, Serginio1, Вы писали:
>>>>При компиляции выдает что на list[t] не может найти linq Max, Min.
R>Просто баг, а не отсутствие фичи
Вот и проблема немерля в том, что не хватает сил на компилятор итд.
Например для оптимизации неплохо оптимизировать перед компиляцией roslyn-linq-rewrite
и солнце б утром не вставало, когда бы не было меня
Здесь проблема как в сообществе, так и разработчиках.
Если сообщество будет давить сильнее, то разработчики прогнутся. Акиньшин рассказывал, как чувак кестрел помогал разрабатывать.
И здесь нужно определенное давление сообщества. То, что мы с тобой поговорим, от этого новых фич не появится.
А вот разработать систему давления и хотя бы отзывы почему это не делается и как помочь, идеи для реализации это даже важнее чем сами фичи
Ну или там голосование, какая фича самая востребованная. Можешь выбрать только одну
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Sinclair, Вы писали:
S>Отлично. Попробовал. Есть ощущение, что возвёрнутые значения дальше не трансформируются. Т.е. трансформация работает только снизу вверх.
Да, получается снизу вверх.
S>Но теперь, получается, надо заново применять вторую фазу, т.к. из той же таблицы фактов мы знаем, что {h} >= {0}, и мы должны свернуть выражение в {true}. S>Итого — либо мы гоняем цикл S>
Здравствуйте, rameel, Вы писали: R>Тут подумать надо как лучше, но насколько мне известно, clang именно так и делает — гоняет правила трасформации по кругу
Тут меня смущает потенциальная непроизводительность — эти трансформации работают в основном на уровне листьев, поэтому перетрансформация отдельной веточки интуитивно дешевле, чем полный проход по дереву.
С другой стороны, может тут экономия на спичках. Надо сначала добиться корректности.
А она в первую очередь зависит от компактности изложения правил.
Игоревский трансформатор уже очень, очень хорошо ужимает код. И даже с ним там простейшие трансформации превращаются в простыни:
Add(Constant(int x), Add(var e, Constant(int y))) => Add(e, Constant(x + y)), // x + (e + y) => e + (x + y)
Add(Constant(int x), Add(Constant(int y), var e)) => Add(e, Constant(x + y)), // x + (y + e) => e + (x + y)
Add(Add(var e, Constant(int x)), Constant(int y)) => Add(e, Constant(x + y)), // (e + x) + y => e + (x + y)
Add(Add(Constant(int x), var e), Constant(int y)) => Add(e, Constant(x + y)), // (x + e) + y => e + (x + y)
Add(Constant(int x), Subtract(var e, Constant(int y))) => Add(e, Constant(x - y)), // x + (e - y) => e + (x - y)
Add(Constant(int x), Subtract(Constant(int y), var e)) => Subtract(Constant(x + y), e), // x + (y - e) => (x + y) - y
Add(Subtract(var e, Constant(int x)), Constant(int y)) => Add(e, Constant(y - x)), // (e - x) + y => e + (y - x)
Add(Subtract(Constant(int x), var e), Constant(int y)) => Subtract(Constant(x + y), e), // (x - e) + y => (x + y) - e
Subtract(Constant(int x), Add(var e, Constant(int y))) => Subtract(Constant(x - y), e),
Subtract(Constant(int x), Add(Constant(int y), var e)) => Subtract(Constant(x - y), e),
Subtract(Add(var e, Constant(int x)), Constant(int y)) => Add(e, Constant(x - y)),
Subtract(Add(Constant(int x), var e), Constant(int y)) => Add(e, Constant(x - y)),
Есть искушение, к примеру, задавить на первом проходе все Subtract в Add(a, Negate(b)), чтобы сократить объём правил.
И так же LessThan в Not(GreaterThanOrEqual).
Кстати, чего я не понял — зачем такой огромный switch в TransformInternal.
Там же можно просто по типам свитчится, а не по NodeType.
case BinaryExpression be
expr = be.Update(
TransformInternal(be.Left, func),
(LambdaExpression?)TransformInternal(be.Conversion, func),
TransformInternal(be.Right, func));
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, rameel, Вы писали:
R>Хотелось бы, чтобы смелее смотрели на то, что вокруг сделано и как.
А с чего ты взял что они не смотрят? Language design process у шарпа сейчас более менее открытый. А делать из него экспериментальный никто не будет, не то назначение у языка.
Здравствуйте, rameel, Вы писали: R>Тут подумать надо как лучше, но насколько мне известно, clang именно так и делает — гоняет правила трасформации по кругу
Прикрутил. Вроде работает. Теперь надо научиться сворачивать выражения типа ((i+1)-(i+2)+1).
Уйдемте отсюда, Румата! У вас слишком богатые погреба.