Здравствуйте, Димчанский, Вы писали:
Д>Скажите, насколько сложен такой финт ушами? Планируете ли?
Какая генерация имеется ввиду? Текстовая? Если текстовая — можно попробовать сделать преобразование AST в строку в виде C#. Не все можно преобразовать, но если ограничивать конструкции — вполне можно генерить. Но текст это плохое решение.
Но nemerle умеет компилировать C#, при этом будут работать макросы уровня сборки и атрибутные. Эти макросы могут генерить что угодно на этапе компиляции.
Здравствуйте, Ziaw, Вы писали:
Z>Какая генерация имеется ввиду? Текстовая? Если текстовая — можно попробовать сделать преобразование AST в строку в виде C#. Не все можно преобразовать, но если ограничивать конструкции — вполне можно генерить. Но текст это плохое решение.
Да, имеется ввиду генереация текста на C# из AST Nemerle. Насколько это сложно (по времени)?
Z>Но nemerle умеет компилировать C#, при этом будут работать макросы уровня сборки и атрибутные. Эти макросы могут генерить что угодно на этапе компиляции.
Я просто подумал, что если вы можете в одну сторону C# -> Nemerle сконвертировать, то может быть можно и в обратную сторону?
Возможно я ошибаюсь, но мне кажется, что при наличии такой фичи людям было бы значительно проще общаться с работодателем, т.к. они бы могли уже сейчас начать спокойно играться с алгебраическими типами Nemerle, его макросами, например computation expressions, т.к. могли бы в любой момент свои наработки на Nemerle перевести в C# , что-то допилить и включить в C# проекты (понимаю, что кода там будет побольше и может быть не все будет выглядеть красиво). Т.е. у людей всегда был бы выбор или убедить своих, как все круто на Nemerle или, если упрутся, загенерить C# код и допиливать уже только его. Чисто стратегически это могло бы вывести часть теоретиков в разряд практиков, т.е. большее число людей могло бы спокойней играться с Nemerle и подтягивать других, т.к. мнение работодателя бы здесь играло значительно меньшую роль.
Здравствуйте, hardcase, Вы писали:
H>В общем случае это очень хреново реализуемо — ибо match. А вообще лучше плагин к ILSpy наваяать, который бы понимал немерловые лямбды и match.
А разве тот же match не разворачивается в итоге в дерево if/else в понимании C#?
Здравствуйте, Димчанский, Вы писали:
H>>В общем случае это очень хреново реализуемо — ибо match. А вообще лучше плагин к ILSpy наваяать, который бы понимал немерловые лямбды и match.
Д>А разве тот же match не разворачивается в итоге в дерево if/else в понимании C#?
Разворачивать-то придется тебе. Вполне можешь в if/else. Поскольку AST будешь строить тоже ты, особых проблем с разворачиванием я не вижу.
Здравствуйте, hardcase, Вы писали:
H>Не всегда. Он может и в switch развернуться. Но ты посмотри декомпилированные match-и Такой код человеки не пишут и уж тем более не поддерживают.
Ну я только вчера поставил Nemrle, накидал по-быстрому рекурсивную функцию фибоначи с аккумуляторами, посмотрел в ILSpy как выглядит — вполне нормальный while цикл получился.
Вот когда алгебраические типи матчить или что еще посложнее, то конечно там должно получаться что-то страшное. А с другой стороны, если бы на C# кто-то бы пытался те же самые алгебраические типы данных изобразить и работать с ними, неужели бы у него код получился бы сильно красивее?
Здравствуйте, Ziaw, Вы писали:
Z>Разворачивать-то придется тебе. Вполне можешь в if/else. Поскольку AST будешь строить тоже ты, особых проблем с разворачиванием я не вижу.
Ты выше писал: "Не все можно преобразовать, но если ограничивать конструкции — вполне можно генерить."
Я просто пытаюсь понять, что именно не получится преобразовать в код на C#?
Здравствуйте, Димчанский, Вы писали:
Д>Скажите, насколько сложен такой финт ушами? Планируете ли?
Мне кажется, это не слишком сложно, но из-за некоторых особенностей языка (матч и возможно хвостовая рекурсия) сгенерированный код будет не таким эффективным, как в Немерле.
Здравствуйте, catbert, Вы писали:
C>Мне кажется, это не слишком сложно, но из-за некоторых особенностей языка (матч и возможно хвостовая рекурсия) сгенерированный код будет не таким эффективным, как в Немерле.
По словам Влада, хвостовые рекурсии в Nemerle разворачиваются в циклы, т.е. не используется IL tail call иснтрукция, т.к. он медленнее. Поэтому с рекурсией видимо не должно быть больших проблем.
C>Влад говорил в видео
Здравствуйте, Димчанский, Вы писали:
Z>>Разворачивать-то придется тебе. Вполне можешь в if/else. Поскольку AST будешь строить тоже ты, особых проблем с разворачиванием я не вижу.
Д>Ты выше писал: "Не все можно преобразовать, но если ограничивать конструкции — вполне можно генерить." Д>Я просто пытаюсь понять, что именно не получится преобразовать в код на C#?
А чем тебе не нравится идея компайл-тайм генерации? Nemerle под нее прекрасно заточен, а вот текстовую придется пилить самостоятельно. Изобретать разные пребилд скрипты. Форматировать этот текст. При этом никакого анализа окружения. Хотя, можно распарсить, конечно.
Здравствуйте, Димчанский, Вы писали:
Д>По словам Влада, хвостовые рекурсии в Nemerle разворачиваются в циклы, т.е. не используется IL tail call иснтрукция, т.к. он медленнее. Поэтому с рекурсией видимо не должно быть больших проблем.
Кстати, ктонибудь тестил ее в .Net4? Они ее оптимизировали вроде. Кто на ты с IL, потестите плиз.
Спасиб за пример, на досуге посмотрю.
Z>А чем тебе не нравится идея компайл-тайм генерации? Nemerle под нее прекрасно заточен, а вот текстовую придется пилить самостоятельно. Изобретать разные пребилд скрипты. Форматировать этот текст. При этом никакого анализа окружения. Хотя, можно распарсить, конечно.
Видишь, я еще не совсем в теме, поэтому не очень понимаю, что значит компайл-тайм генерация. Как это выглядит? Может пример есть?
Здравствуйте, Ziaw, Вы писали:
Z>Кстати, ктонибудь тестил ее в .Net4? Они ее оптимизировали вроде. Кто на ты с IL, потестите плиз.
Я тут попробовал изобразить на F# тест хвостовой рекурсии (можно скачать проект с откомпиленным exe: TailRecursionTest.zip):
open System
open System.Diagnostics
let rec loop_rec n =
if n > 0L
then help_tail_call (n-1L)
else ()
and help_tail_call n =
if n > 0L
then loop_rec (n-1L)
else ()
let loop_for n =
let mutable i = n
while i > 0L do
i <- i - 1L
()
let time s f =
printfn "Starting '%s'..." s
let sw = Stopwatch.StartNew()
f()
sw.Stop()
printfn "Done in %f ms..." sw.Elapsed.TotalMilliseconds
sw.Elapsed.TotalMilliseconds
let time_rec n = (fun () -> loop_rec n) |> time "rec"
let time_for n = (fun () -> loop_for n) |> time "for"
[<EntryPoint>]
let main (args : string[]) =
if args.Length <> 1
then failwith "Error: expected argument <loop count>"
let n = Int64.Parse(args.[0])
printfn "Ratio: %f" ((time_rec n) / (time_for n))
printfn "Ratio: %f" ((time_rec n) / (time_for n))
0
Рекурсию сделал через две рекурсивных функции, которые через tail call вызывают друг друга. Если делаешь в виде одной функции, то компилятор делает такой же цикл, как в loop_for.
Не знаю на сколько корректно. Но запустив программу (release build, any cpu) у себя на 64-битной системе получил:
> TailRecursionTest.exe 1000000000
Starting 'rec'...
Done in 1243.135100 ms...
Starting 'for'...
Done in 710.358100 ms...
Ratio: 1.750012
Starting 'rec'...
Done in 1242.459000 ms...
Starting 'for'...
Done in 711.537000 ms...
Ratio: 1.746162
Т.е. хвостовой вызов в 1.75 раза медленнее цикла. Для чистоты эксперимента нужно было бы наверное поправить IL код, чтобы loop_rec вызывала себя же.
Здравствуйте, Димчанский, Вы писали:
Д>Здравствуйте, Ziaw, Вы писали:
Д>Спасиб за пример, на досуге посмотрю.
Z>>А чем тебе не нравится идея компайл-тайм генерации? Nemerle под нее прекрасно заточен, а вот текстовую придется пилить самостоятельно. Изобретать разные пребилд скрипты. Форматировать этот текст. При этом никакого анализа окружения. Хотя, можно распарсить, конечно.
Д>Видишь, я еще не совсем в теме, поэтому не очень понимаю, что значит компайл-тайм генерация. Как это выглядит? Может пример есть?
Например так
В файле проекта заменяем:
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
На
<Import Project="$(Nemerle)\Nemerle.MSBuild.targets" />
Пишем некий код:
[GenId]
class Test
{
public static void Main()
{
var id = new Test().Id;
Console.WriteLine("Compile time id = {0}", id);
}
}
Создаем макрос в отдельной сборке:
[Nemerle.MacroUsage(Nemerle.MacroPhase.BeforeTypedMembers, Nemerle.MacroTargets.Class)]
macro GenId(tb : TypeBuilder)
{
tb.Define(<[decl: public Id : Guid = Guid.NewGuid() ]>)
}
Здравствуйте, catbert, Вы писали:
C>Мне кажется, это не слишком сложно, но из-за некоторых особенностей языка (матч и возможно хвостовая рекурсия) сгенерированный код будет не таким эффективным, как в Немерле.
Эффективный код сгенерировать не проблема. Вот, легко читаемый сильно сложнее.
C>Влад говорил в видео
Здравствуйте, Димчанский, Вы писали:
Д>Скажите, насколько сложен такой финт ушами? Планируете ли?
Я планировал реализовать это в Н2. Ну, или в каком-то из промежуточных релизов.
Задача там не очень сложная, так что ее мог бы решить кто-то из комьюнити. На ней можно и язык подучить.
Кроме того эта же задача решается с другой стороны, со стороны декомпиляторов сборок. JetBrains dotPeek и ILSpy уже очень близки к тому чтобы полностью декомпилировать сборки немерла в C#. А это мало отличается от генерации кода по немерловым кишкам. Результат будет тот же — C#-код который можно скомпилировать компиляторами C#. Так что возможно, имеет смысл помочь разработчикам ILSpy-я и dotPeek-а. Первым можно просто присылать патчи исправляющие их ошибки. А вторым слать багрепорсты и просить их сделать поддержку немерла более качественной.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, Димчанский, Вы писали:
Д>Да, имеется ввиду генереация текста на C# из AST Nemerle. Насколько это сложно (по времени)?
Зависит от качества генерируемого кода которое хочется получить.
В принципе, если не заморачиваться на качество, то по типизированному AST можно довольно просто сгенерировать C#-код. Вот только качество этого код будет крайне низким. Там будет куча goto, вместо лямбд будут объекты, вместо ПМ будут страшные if-ы и т.п.
Если такой результат устроит, то могу рассказать как это дело добавить в компилятор.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.