Entry tags:
NEMERLE и поток сознания
Сначала я хотел просто написать, что майский конкурс по ФП закончился, и желающие могут посмотреть, что мы там устроили. А если что-то из увиденного понравится, то и проголосовать.
Но потом я подумал, что это хороший повод рассказать о языке программирования Nemerle, с которым я игрался в последнее время. Опыт у меня с ним пока не большой, потому структурировано написать не выйдет. Под катом некторый набор сведений о Nemerle в перемешку с моим потоком сознания относительно функционального программирования и программирования вообще.
Мне нравится программировать. Я испытываю удовольствие, когда получается красивый и лаконичный код, а так же удовлетворение, когда результаты моих трудов приносят реальную пользу другим людям. Я не могу сказать, насколько программирование творческая профессия, но верю, что первычны мысль и знания, а не нажимание кнопочек. Язык - это средство выражения мысли, при этом неважно, про естественный язык мы говорим или нет. Идеально выразить мысль нельзя, но надо к этому стремится. И уж точно, нельзя запирать мысль в рамки конкретного языка. Ведь из того, что в языке нет какого-то слова совершенно не следует, что объект, который мы хотим описать не существует.
Спасибо мне! Сыграл в КО! Однако с языками программирования часто не прокатывает. Осилил %langname% и все, хватит, отвалите. Мне труп страуса нашептал, что у меня в руках ИНСТРУМЕНТ ВЫСОКОГО УРОВНЯ, а потом, прищурившись, добавил: "Полный по Тьюрингу, даааа". Ну теперь вообще ахуеть. Я даже слушать вас не хочу: жаба тормозит, сишка хуже ассемблера, додиез не знаю, зачем придумали, когда у них жаба есть, objc - это просто яблочная илитка, на лиспе искуственный интелект так и не зделали, лямбда-исчисление? исчисление что? Шли бы вы отсюда со своими историями. А потом человеку изменяет сознание и он начинает находить свои любимые костыли даже там, где их никогда и не было. Паттерн ПРИСПОСОБЛЕНЕЦ во все поля.
Я вспоминаю, как начав программировать на C#, испытывал физическую необходимость ОСВОБОДИТЬ ПАМЯТЬ и руками устроить связанный список. Потом-то оно уже проще идет. Знакомые вещи определяются сразу, а новые расширяют кругозор. Интересно узнавать новый язык, задаваясь вопросом: "А как я вообще раньше без этого жил?" Как будто собирается некий пазл, образуя целостную картину, а не "Вот тебе походный ножик. Теперь иди - строй дом".
Казалось бы, причем здесь Nemerle? Просто это язык программирования, который, на мой взгляд, заслуживает внимания.
Nemerle - ЯП общего назначения. Я не знаю, что такое общее назначение. Я так мало знаю о программировании микроконтроллеров и о программировании для суперкомьютеров и еще куче областей , что у меня с парнями, работающими в тех сферах, разная специальность. Я понимаю, что хороший программист должен найти себя в любой области, но у нас _настолько_ разные приоритеты, что придется сильно ломать себя. Я пишу средней толстоты эторпрайз (базворды прилагаются), потому для меня важны:
- Надежность. Ведь ничего падать не должно, а если упадет - перезапуститься. Конечно же, все логировать-логировать и алертить. И желательно все это задублировать.
- Прозрачность. Ведь вон та функция "ОТПРАВИТЬ ДЕНЬГИ НА ПЕЧАТЬ", должна отправлять деньги на печать всегда, а не только в состоянии суперпозиции ста тысяч "Если".
- Читаемость. Ну мы же все знаем, что самодокументируемый код - это миф, не так ли? Правда, мы так же знаем, что документирование всего и вся с последующей актуализацией - тот еще кошмар. Потому лучше писать кратко и информативно.
- Тестируемость. Необходимо проверить исправность каждой детальки еще до момента, когда конструктор будет собран. Мы же не хотим ОТПРАВИТЬ ЯЧЕЙКУ НА БОЕВОЕ ДЕЖУРСТВО, ЧТОБЫ ОНА ТАМ ПРОСТО СИГНАЛ РИСОВАЛА ТАБУРЕТОЧКОЙ, так?
- Совместимость. Хаскель исключительно хорош для новых проектов? А если не новых? Вместо библиотек даете возможность их написать? ВЕРНИТЕ НА МЕСТО МОИ ЛЮБИМЫЕ ВЕЛИКИ! БЫЫЫСТРААА!
Nemerle - статически типизуеммый язык программирования под .NET (есть реализация для Mono, но она вроде сломана) со всеми вытекающими. Язык поддерживает ООП в самом распространенном варианте ее реализации с одиночным наследованием, знакомый по Java и C#. Есть:
- Шаблоны (generics)
- Интерфесы
- Методы расширения
- Частичные (partial) классы
- Модификаторы доступа (internal, protected и тд)
- Весь набор, привычный C# программисту. )
Я не вижу смысла, останавливаться на ООП, потому как все достаточно стандартно. Идем далее. Nemerle реализует концепции функционального программирования:
- Нормальные кортежи
- Алгебраические типы данных
- Иммутабельность из коробки
- Паттерн матчинг
- Функции высшего порядка
- Частичное применение
- Вывод типов
- Замыкания
- Перегрузка и определение операторов с возможностью задания приоритета и ассоциативности
- Итераторы
- List comprehensions (не знаю, как переводится)
- Монады (нет, ввод-вывод не в монаде)
- Computation expressions (опять не знаю устоявшегося перевода)
- Опционально двухмерный синтаксис (синтаксис на отступах) через #pragma indent
- Опционально может в ленивость
- Оптимизация хвостовых вызовов
- События и делегаты (я думаю, эти вещи в этом блоке смотрятся лучше)
Вообщем-то весь джентльменский набор, необходимый, чтобы назвать язык функциональным. Стоит отметить, что Nemerle разрешает перегрузку функций (в отличии, например, от F#) и вывод типов спокойно разруливает, какую именно следует вызвать. Мне нравится, но наверное хаскелисты негодуют. Правда, Nemerle требует, чтобы на высшем уровне, то есть в классах и модулях (модуль является обычными статическим классом, для методов которого по умолчанию выставлен модификатор public) необходимо явно аннотировать типы. Я не думаю, что кому-то станет плохо от подобного требования, поскольку даже в Haskell, где система типов способна сама все выводить, аннотации типов все равно приводятся, поскольку по типам можно судить о природе процесса, выполняемого функцией. Еще одной особенностью является возможность "открыть" статических класс, импортировав его содержимое в текущее пространство имен. Может мелочь, но меня всегда раздражали все эти Console.WriteLine.
То есть, на первый взгляд, Nemele ничего особенно не представляет. К тому же разработчики старались не сломать мозг своей потенциальной аудитории, потому сделали синтаксис языка по возможности идентичным C#. Разработчики Scala, как я понимаю, пошли тем же путем. А вот ML-подобный синтаксис с непривычки может очень сильно напугать. Проверено. Язык задумывался, как замена C#, то есть каким C# должен был бы быть. И вы знаете, я согласен. Этих возможностей вполне хватает, чтобы комфортно программировать. F# как раз на этой позиции и находится, то есть со вкусом и без изъебств.
Теперь переходим к Nemerle непосредственно, к тому, что делает язык в большой степени уникальным, - макросам. У меня с макросами всегда были проблемы, сначало звучало страшно, потом было непонятно, где и как и применять. Похоже, это не только моя проблема. Иногда, я думаю, что после изобретения LISP'а, значительная часть развития языков программирования является размышлением на тему "Нужны ли макросы? Какими они должны быть тогда?" LISP'еры хоть и не изобрели искустевеный интелект, но очень многое дали миру: gc, графические интерфейсы и конечно макросы. Мне кажется, Ритчи с Томпсоном догадывались, что всего не предусмотришь, потому запили макры. Сишка используется до сих пор, многие даже испытывают к ней теплые чувства. А более другие люди решили, что макры не нужны, а теперь гордятся тьюринг-полным ТЕМПЛЕЙТО-ДОБРОМ. В Скалочку вот добавляют макросы, а я не видел, чтобы кто-то писал, мол Мартин Одерский не особо рубит в языках программирования.
Так с макросами какие проблемы? Во-первых, сразу начинается нытье, мол развалите весь синтаксис со всей семантикой, превратив язык в непонятную ёбу. Я так же ныл (может еще заною, кто его знает). Но это возврат к разговору о возможности прострелить себе ногу. Меня подзаебали эти разговоры, я решил для себя, что прострелить ногу можно везде и всегда. Мутабельность - прострелил. Энергичность - прострелил. Ленивость - иди чини ноги. Иммутабельность - не прочитал книгу по иммутабельным структурам данных? пиздуй в больницу чинить ноги. И так всегда, не бывает серебрянной пули, как не бывает языков общего назначения, как нет искуственого интеллекта. Именно поэтому, программисты существуют, существуют как профессия, как специалисты, а не просто прослойка между креслом и монитором. Хотя надо отдавать себе отчет в собственных возможностях. Это вам не придти и перевести все критические бизнес-процессы на Хаскель из-за того, что кто-то научился Фибоначи считать. И я не один такой, создатель Лифта такой же точки зрения придерживается. То есть в любом случае некоторый опыт необходим.
Во-вторых, макросы сложные. В Nemerle не сложные, то есть при написании макросов используется тот же самый Nemerle и его возможности, никакого специального DSL не требуется. Держим в уме знание, что макрос - функция с типом List[PExpr] -> PExpr, выполняемая во время компиляции, и все будет хорошо. Макросы гигиеничны, то есть при совпадении имен переменной из макроса и контекста, в котором макрос разворачивается, имя из макроса будет автоматически переименовано, хотя это поведение можно отключать, тогда значение будет связано с ближайшим именем в контексте. Таким образом, кстати, работает макра regex match, которую я использовал в своем решении.
Макросы бывают разными
- Макросы выражения: можно сделать printf("%d%f", x, y), который будет на этапе компиляции проверять соответствие количества параметров и их типов строке форматирования; многие компоненты языка такие как if else, while, for и другие реализованы через такие макросы
- Макросы-операторы: собственно через них реализует переопределение и создание новых операторов. Можно задавать приоритет и ассоциативность. Например, с их помощь в Nemerle сделаны pipe-операторы |> и <|
- Мета-атрибуты - видимо, так называются из-за сходства в записили с атрибутами C#. Позволяют изменить класс, метод, свойство и так далее. Для меня самый впечатляющим примером использования является макрос PegGrammar, который по заданной PEG грамматике создает класс-парсер ее разбирающий. Мой игрушечный пример можно увидеть тут. Если игрушки вам не по душе, то можно глянуть на серьезное использование для разбора грамматики C#.
- Лексические макросы: к сожалению, я еще не успел с этим разобраться, но похоже, макра конструирования XML, напоминающая синтаксис для работы с XML в Scala, относится именно к этой категории.
Мне очень хочется, рассказать о макросах Nemerle, кратко и содержательно, чтобы вы могли испытать то же ВАУ, которое испытываю я. Но, по всей видимости, пока в моем мозгу все по полочкам не разложится, я не смогу внятно излагать. Главное, что я хочу донести, что макросы в Nemerle - это очень гибкое средство, которое красиво и лаконично ложится на язык. Синтаксис языка во много сделан на макросах, кодогенерация требующая в C# сторонных тулзовин отлично реализуется, многие хорошие фичи, которые приходят в C#, как новые элементы языка, делаются на макросах. Я думаю, так ожидаемые Type Providers из F# 3.0 делаются на макросах на ура. То есть я пока не вижу, где заканчиваются возможности, но четко представляю, как применять эти вещи в работе: будь-то автоматическая имплементация всяких IDataErrorInfo с INotifyChanged или как присахарить и обезопасить работу с каким-нибудь SqlCommand. При этом я без проблем, могу использовать существующий C# код, могу использовать в C# проектах код на Nemerle (пока не тестировал). Я считаю, что Nemerle - более удобный и качественный инструмент для решения мох задач.
Надесь, было хоть чуть-чуть интересно. Но если вы внезапно дочитали до сюда и считаете все вышенаписаное бредом идиота , хотя бы начинайте псить. Мне приятно будет)
Update: Как-то получилось, что обсуждение велось параллельно в двух местах: тут и еще одна ветка обсуждения.
Но потом я подумал, что это хороший повод рассказать о языке программирования Nemerle, с которым я игрался в последнее время. Опыт у меня с ним пока не большой, потому структурировано написать не выйдет. Под катом некторый набор сведений о Nemerle в перемешку с моим потоком сознания относительно функционального программирования и программирования вообще.
Мне нравится программировать. Я испытываю удовольствие, когда получается красивый и лаконичный код, а так же удовлетворение, когда результаты моих трудов приносят реальную пользу другим людям. Я не могу сказать, насколько программирование творческая профессия, но верю, что первычны мысль и знания, а не нажимание кнопочек. Язык - это средство выражения мысли, при этом неважно, про естественный язык мы говорим или нет. Идеально выразить мысль нельзя, но надо к этому стремится. И уж точно, нельзя запирать мысль в рамки конкретного языка. Ведь из того, что в языке нет какого-то слова совершенно не следует, что объект, который мы хотим описать не существует.
Спасибо мне! Сыграл в КО! Однако с языками программирования часто не прокатывает. Осилил %langname% и все, хватит, отвалите. Мне труп страуса нашептал, что у меня в руках ИНСТРУМЕНТ ВЫСОКОГО УРОВНЯ, а потом, прищурившись, добавил: "Полный по Тьюрингу, даааа". Ну теперь вообще ахуеть. Я даже слушать вас не хочу: жаба тормозит, сишка хуже ассемблера, додиез не знаю, зачем придумали, когда у них жаба есть, objc - это просто яблочная илитка, на лиспе искуственный интелект так и не зделали, лямбда-исчисление? исчисление что? Шли бы вы отсюда со своими историями. А потом человеку изменяет сознание и он начинает находить свои любимые костыли даже там, где их никогда и не было. Паттерн ПРИСПОСОБЛЕНЕЦ во все поля.
Я вспоминаю, как начав программировать на C#, испытывал физическую необходимость ОСВОБОДИТЬ ПАМЯТЬ и руками устроить связанный список. Потом-то оно уже проще идет. Знакомые вещи определяются сразу, а новые расширяют кругозор. Интересно узнавать новый язык, задаваясь вопросом: "А как я вообще раньше без этого жил?" Как будто собирается некий пазл, образуя целостную картину, а не "Вот тебе походный ножик. Теперь иди - строй дом".
Казалось бы, причем здесь Nemerle? Просто это язык программирования, который, на мой взгляд, заслуживает внимания.
- Надежность. Ведь ничего падать не должно, а если упадет - перезапуститься. Конечно же, все логировать-логировать и алертить. И желательно все это задублировать.
- Прозрачность. Ведь вон та функция "ОТПРАВИТЬ ДЕНЬГИ НА ПЕЧАТЬ", должна отправлять деньги на печать всегда, а не только в состоянии суперпозиции ста тысяч "Если".
- Читаемость. Ну мы же все знаем, что самодокументируемый код - это миф, не так ли? Правда, мы так же знаем, что документирование всего и вся с последующей актуализацией - тот еще кошмар. Потому лучше писать кратко и информативно.
- Тестируемость. Необходимо проверить исправность каждой детальки еще до момента, когда конструктор будет собран. Мы же не хотим ОТПРАВИТЬ ЯЧЕЙКУ НА БОЕВОЕ ДЕЖУРСТВО, ЧТОБЫ ОНА ТАМ ПРОСТО СИГНАЛ РИСОВАЛА ТАБУРЕТОЧКОЙ, так?
- Совместимость. Хаскель исключительно хорош для новых проектов? А если не новых? Вместо библиотек даете возможность их написать? ВЕРНИТЕ НА МЕСТО МОИ ЛЮБИМЫЕ ВЕЛИКИ! БЫЫЫСТРААА!
Nemerle - статически типизуеммый язык программирования под .NET (есть реализация для Mono, но она вроде сломана) со всеми вытекающими. Язык поддерживает ООП в самом распространенном варианте ее реализации с одиночным наследованием, знакомый по Java и C#. Есть:
- Шаблоны (generics)
- Интерфесы
- Методы расширения
- Частичные (partial) классы
- Модификаторы доступа (internal, protected и тд)
- Весь набор, привычный C# программисту. )
Я не вижу смысла, останавливаться на ООП, потому как все достаточно стандартно. Идем далее. Nemerle реализует концепции функционального программирования:
- Нормальные кортежи
- Алгебраические типы данных
- Иммутабельность из коробки
- Паттерн матчинг
- Функции высшего порядка
- Частичное применение
- Вывод типов
- Замыкания
- Перегрузка и определение операторов с возможностью задания приоритета и ассоциативности
- Итераторы
- List comprehensions (не знаю, как переводится)
- Монады (нет, ввод-вывод не в монаде)
- Computation expressions (опять не знаю устоявшегося перевода)
- Опционально двухмерный синтаксис (синтаксис на отступах) через #pragma indent
- Опционально может в ленивость
- Оптимизация хвостовых вызовов
- События и делегаты (я думаю, эти вещи в этом блоке смотрятся лучше)
Вообщем-то весь джентльменский набор, необходимый, чтобы назвать язык функциональным. Стоит отметить, что Nemerle разрешает перегрузку функций (в отличии, например, от F#) и вывод типов спокойно разруливает, какую именно следует вызвать. Мне нравится, но наверное хаскелисты негодуют. Правда, Nemerle требует, чтобы на высшем уровне, то есть в классах и модулях (модуль является обычными статическим классом, для методов которого по умолчанию выставлен модификатор public) необходимо явно аннотировать типы. Я не думаю, что кому-то станет плохо от подобного требования, поскольку даже в Haskell, где система типов способна сама все выводить, аннотации типов все равно приводятся, поскольку по типам можно судить о природе процесса, выполняемого функцией. Еще одной особенностью является возможность "открыть" статических класс, импортировав его содержимое в текущее пространство имен. Может мелочь, но меня всегда раздражали все эти Console.WriteLine.
То есть, на первый взгляд, Nemele ничего особенно не представляет. К тому же разработчики старались не сломать мозг своей потенциальной аудитории, потому сделали синтаксис языка по возможности идентичным C#. Разработчики Scala, как я понимаю, пошли тем же путем. А вот ML-подобный синтаксис с непривычки может очень сильно напугать. Проверено. Язык задумывался, как замена C#, то есть каким C# должен был бы быть. И вы знаете, я согласен. Этих возможностей вполне хватает, чтобы комфортно программировать. F# как раз на этой позиции и находится, то есть со вкусом и без изъебств.
Теперь переходим к Nemerle непосредственно, к тому, что делает язык в большой степени уникальным, - макросам. У меня с макросами всегда были проблемы, сначало звучало страшно, потом было непонятно, где и как и применять. Похоже, это не только моя проблема. Иногда, я думаю, что после изобретения LISP'а, значительная часть развития языков программирования является размышлением на тему "Нужны ли макросы? Какими они должны быть тогда?" LISP'еры хоть и не изобрели искустевеный интелект, но очень многое дали миру: gc, графические интерфейсы и конечно макросы. Мне кажется, Ритчи с Томпсоном догадывались, что всего не предусмотришь, потому запили макры. Сишка используется до сих пор, многие даже испытывают к ней теплые чувства. А более другие люди решили, что макры не нужны, а теперь гордятся тьюринг-полным ТЕМПЛЕЙТО-ДОБРОМ. В Скалочку вот добавляют макросы, а я не видел, чтобы кто-то писал, мол Мартин Одерский не особо рубит в языках программирования.
Так с макросами какие проблемы? Во-первых, сразу начинается нытье, мол развалите весь синтаксис со всей семантикой, превратив язык в непонятную ёбу. Я так же ныл (может еще заною, кто его знает). Но это возврат к разговору о возможности прострелить себе ногу. Меня подзаебали эти разговоры, я решил для себя, что прострелить ногу можно везде и всегда. Мутабельность - прострелил. Энергичность - прострелил. Ленивость - иди чини ноги. Иммутабельность - не прочитал книгу по иммутабельным структурам данных? пиздуй в больницу чинить ноги. И так всегда, не бывает серебрянной пули, как не бывает языков общего назначения, как нет искуственого интеллекта. Именно поэтому, программисты существуют, существуют как профессия, как специалисты, а не просто прослойка между креслом и монитором. Хотя надо отдавать себе отчет в собственных возможностях. Это вам не придти и перевести все критические бизнес-процессы на Хаскель из-за того, что кто-то научился Фибоначи считать. И я не один такой, создатель Лифта такой же точки зрения придерживается. То есть в любом случае некоторый опыт необходим.
Во-вторых, макросы сложные. В Nemerle не сложные, то есть при написании макросов используется тот же самый Nemerle и его возможности, никакого специального DSL не требуется. Держим в уме знание, что макрос - функция с типом List[PExpr] -> PExpr, выполняемая во время компиляции, и все будет хорошо. Макросы гигиеничны, то есть при совпадении имен переменной из макроса и контекста, в котором макрос разворачивается, имя из макроса будет автоматически переименовано, хотя это поведение можно отключать, тогда значение будет связано с ближайшим именем в контексте. Таким образом, кстати, работает макра regex match, которую я использовал в своем решении.
Макросы бывают разными
- Макросы выражения: можно сделать printf("%d%f", x, y), который будет на этапе компиляции проверять соответствие количества параметров и их типов строке форматирования; многие компоненты языка такие как if else, while, for и другие реализованы через такие макросы
- Макросы-операторы: собственно через них реализует переопределение и создание новых операторов. Можно задавать приоритет и ассоциативность. Например, с их помощь в Nemerle сделаны pipe-операторы |> и <|
- Мета-атрибуты - видимо, так называются из-за сходства в записили с атрибутами C#. Позволяют изменить класс, метод, свойство и так далее. Для меня самый впечатляющим примером использования является макрос PegGrammar, который по заданной PEG грамматике создает класс-парсер ее разбирающий. Мой игрушечный пример можно увидеть тут. Если игрушки вам не по душе, то можно глянуть на серьезное использование для разбора грамматики C#.
- Лексические макросы: к сожалению, я еще не успел с этим разобраться, но похоже, макра конструирования XML, напоминающая синтаксис для работы с XML в Scala, относится именно к этой категории.
Мне очень хочется, рассказать о макросах Nemerle, кратко и содержательно, чтобы вы могли испытать то же ВАУ, которое испытываю я. Но, по всей видимости, пока в моем мозгу все по полочкам не разложится, я не смогу внятно излагать. Главное, что я хочу донести, что макросы в Nemerle - это очень гибкое средство, которое красиво и лаконично ложится на язык. Синтаксис языка во много сделан на макросах, кодогенерация требующая в C# сторонных тулзовин отлично реализуется, многие хорошие фичи, которые приходят в C#, как новые элементы языка, делаются на макросах. Я думаю, так ожидаемые Type Providers из F# 3.0 делаются на макросах на ура. То есть я пока не вижу, где заканчиваются возможности, но четко представляю, как применять эти вещи в работе: будь-то автоматическая имплементация всяких IDataErrorInfo с INotifyChanged или как присахарить и обезопасить работу с каким-нибудь SqlCommand. При этом я без проблем, могу использовать существующий C# код, могу использовать в C# проектах код на Nemerle (пока не тестировал). Я считаю, что Nemerle - более удобный и качественный инструмент для решения мох задач.
Надесь, было хоть чуть-чуть интересно. Но если вы внезапно дочитали до сюда и считаете все вышенаписаное бредом идиота , хотя бы начинайте псить. Мне приятно будет)
Update: Как-то получилось, что обсуждение велось параллельно в двух местах: тут и еще одна ветка обсуждения.
no subject
when' = flip when
f = do
do_something `when'` condition
Вы всё напираете на синтаксис, как и большинство других разработчиков. Синтаксис всего ли часть языка программирования, далеко не самая важная и сложная. Смысл конструкций гораздо важнее.
В чём смысл XML-литералов? В "наглядности", это раз (в кавычках из-за плохой читаемости XML), и в "скорости", это два (ибо всё равно строки соединять). Так вот может важнее правильность этого XML, чтобы вам компилятор быстрее сказал об ошибке в проверке по схеме, чем эти два сомнительных преимущества?
Ознакомьтесь с реализацией Agda2 и семейств типов Хаскеля. Обе реализации ленивые. Это касательно манипуляции с типами функций.
no subject
Правильность XML тоже важна, и ее макрос тоже может проверить, это не преимущество ленивости.
no subject
Нормальный порядок вычислений именно таков: уменьшает количество труда по всему фронту работ.
Типы данных тоже.
И макросы тоже, если рассудить.
Я перечислил инструменты в порядке понимаемой мной важности.
90% применений макросов может быть убрано нормальным порядком вычислений. См. Алана Кея: http://kazimirmajorinc.blogspot.com/2010/02/alan-kay-on-fexprs.html
Ещё 90% оставшихся 10% - типами (правильность XML).
И вот где уж совсем никак, надо применять макросы. 1% применений макросов действительно оправдан, а не вызван недостатками семантики или системы типов языка.
no subject
no subject
(Anonymous) 2012-05-15 03:17 pm (UTC)(link)А вы знаете, ни у кого нету точных данных. Просто апологеты хаскеля любят бросаться бездоказательными утверждениями.
no subject
(Anonymous) 2012-05-15 03:15 pm (UTC)(link)> Ещё 90% оставшихся 10% - типами (правильность XML).
С другой стороны, 100% применений ленивости может быть убрано макросами. !00% применений типов тоже может быть убрано макросами.
То есть случаев, в которых применение типов и лени оправдано не остается. Зачем же множить сущности?
no subject
Возражений два: этого так никто и не сделал и у самописных макросов не будет строгой логической основы (зависимых) типов данных.
Посему здесь сила практических результатов (наличие развитых систем типов и языков с ленивым порядков вычислений) против слабости теоретических (надо делать самому, а не пользоваться чужим).
Это мой последний комментарий анониму в этой ветке. Залогиньтесь.
no subject
Да нет, я апеллирую к тому, что вы сделали кучу ничем неподтвержденных и, более того, заведомо ошибочных утверждений (причем вы эти утверждения из раза в раз повторяете как заведенный), и я просто ответил вам в вашем же собственном стиле.
Давайте по порядку разберемся. Вы вот говорите, что лень покрывает большую часть юзкейсов макросов. В подтверждение вместо макросов приводите, почему-то, _спецформу_ if, а никакие не макросы. К спецформе if еще вернемся позже, а вот сам аргумент рассмотрим, но на примере приведенном ниже с with-open-file. Ну, мол, вот в хаскеле это все делается функциями, а вот в общелиспе - макросами. Так, видите ли, это просто особенности дизайна конкретно общелиспа. Возьмем racket - там и макросистема намного мощнее, чем в общелиспе, и макросы обычно сложнее (то есть в общелиспе они были бы сложнее средних общелисповских, а в racket их писать проще), и применяются они намного шире. И (внезапно!) все указанные формы там делаются функциями. call-wtih-input-file - функция, dynamic-wind (аналог unwind-protect, но работающая с продолжениями) - функция. Вообще, все то, что вы назвали "90% юзкейсов макросов" в racket делается простыми функциями, а когда нам надо задержать вычисление аргумента (то есть то, для чего, по-вашему, нужны макросы) - то он просто оборачивается явно в лямбду и дальше руками форсится. Вот вы не находите странным, что язык программирования, в котором мощная макросистема позиционируется как одна из killer-feature, который стимулирует использовать макросы как можно больше, в "90% юзкейсов" заменяет макросы обычными функциями? Вам не кажется, что тут что-то не так? Как же это так выходит, что остаются 10% юзйкесов а макросы там на каждом шагу? Иначе как чудом и не назовешь такую ситуацию, не правда ли?
Теперь if и преимущества лени. Начнем с того, что вообще неясно стремление помериться спецформами, а потом еще и утверждать что-де "лень лучше, потому что там if - функция". Но ладно, допустим, чем минимальнее ядро языка - тем лучше, тем проще анализировать свойства этого языка, в конце концов. Но в вашем-то хаскеле у вас if в ядре (ну да, там case а не if но это не так важно, сами понимаете), и никак этот if оттуда не убрать. Да, можно сделать свой самопальный if, но он никогда не будет работать со стандартными True/False - но так аналог этого if можно сделать и в энергичном языке, достаточно обернуть ветки исполнения в лямбду и зафорсить руками.
На счет "мощности" лени в общем я уже писал выше. Единственно, что можно утверждать - так это, что в лямбда-исчислении с нормальным порядком зависающих программ меньше, чем в лямбда-исчислении с энергичным. Ну и? Можно сделать язык, в котором вообще не будет зависающих программ, он правда не будет тьюринг-полным. Значит ли это, что такоц язык мощнее тьюринг-полного языка? Нет. Даже наоборот. По-этому, на мой взгляд, более мощным является именно энергичный порядок - т.к. он позволяет более точно специфицировать поведение программы.
> Возражений два: этого так никто и не сделал
typed/racket есть, lazy/racket есть, все сделали. Какие проблемы?
> Посему здесь сила практических результатов (наличие развитых систем типов и языков с ленивым порядков вычислений) против слабости теоретических (надо делать самому, а не пользоваться чужим).
Я здесь рассуждаю несколько иначе. Специфическое решение (специализированный дсл в виде макрообвязки) всегда лучше, чем общее (одна единственная система типов). То есть иметь возможность сделать заточенный под задачу инструмент самому лучше, чем не иметь такой возможности и вынужденно обходиться одним единственным заранее сделанным инструментом. Тем более, что никто не запрещает вам использовать библиотеки уже готовых инструментов :)
В этом смысле библиотека с реализацией в виде макросов какой-то системы типов ничем не отличается от этой же реализации, но в рамках встроенного тайпчекера какого-то ЯП.
no subject
Изначально разговор был шире макросов Лиспа. Туда включали Nemerle. Однако вы поддерживаете мою точку зрения - большую часть макросов можно заменить ФВП и (!) если нет ленивого порядка вычислений с каррингом, то приходится делать руками. При этом умные люди (создатели Схемы умны) предпочитают функции, нежели макросы.
Оптимизации же - типа склеивания и устранение леса, а также уменьшение сложности на степени N, которые вы тоже можете попытаться записать на счёт макросов, - лучше делать суперкомпиляцией, к чему лучше приспособлены, опять же, ленивые языки.
>Но в вашем-то хаскеле у вас if в ядре (ну да, там case а не if но это не так важно, сами понимаете), и никак этот if оттуда не убрать.
Тут рядом я рассказал, как это убирается. Это было сделано в 1936 году, если что. Ещё до появления машины Тьюринга. Исходный вариант STG использовал кодирование Чёрча.
>По-этому, на мой взгляд, более мощным является именно энергичный порядок - т.к. он позволяет более точно специфицировать поведение программы.
Ваш взгляд противоречит принятому в CS. Также не-Тьюринг полные языки входят в моду, ибо именно для них можно наиболее точно специфицировать поведение программы.
no subject
Вы, видимо, меня не слушали. Я говорю, что эта часть юзкейса - это не бОльшая часть макросов. Даже не значимая часть. И если ее убрать - то ничего не меняется.
> Оптимизации же - типа склеивания и устранение леса, а также уменьшение сложности на степени N, которые вы тоже можете попытаться записать на счёт макросов, - лучше делать суперкомпиляцией, к чему лучше приспособлены, опять же, ленивые языки.
Непонятно, при чем тут макросы. Еще раз - оптимизация и задерживание аргументов это совершенно не значимая часть макросов. То есть из тысячи макросов этим занимается... ну может один или два.
> Тут рядом я рассказал, как это убирается.
Нет, не рассказали. Никакой реализации if без использования вшитого кейза причем так, чтобы if использовал стандартные True и False вы не предложили.
> Ваш взгляд противоречит принятому в CS.
Вы выдаете собственное мнение за принятый в CS взгляд.
no subject
Есть ли у вас исследования, как применяются макросы? Вы же наверняка интересовались этим вопросом больше, чем я. Проводили исследования, владеете цифрами, всё такое.
Здесь я охотно соглашусь с моим неведением, если увижу настоящее исследование. В противном случае я бы предпочёл, чтобы вы больше не говорили о большей и меньшей частях, если вы... не запрещаете, конечно, но говорите о моей неправомочности делать выводы.
>Еще раз - оптимизация и задерживание аргументов это совершенно не значимая часть макросов. То есть из тысячи макросов этим занимается... ну может один или два.
Есть ли у вас исследования, как применяются макросы?
Да даже если и нет, то это ваше высказывание означает, что макросы используются лдя расширения синтаксиса. См. выше про синтаксический подход.
>Никакой реализации if без использования вшитого кейза причем так, чтобы if использовал стандартные True и False вы не предложили.
Я и не должен был. Это за меня сделали в 1936 году. Я всего лишь показал, что это возможно и указал более авторитетный источник.
Прочитайте же наконец литературу. Хотя бы Википедию про кодирование Чёрча. В "Programming in Martin-Loef Type Theory" рассказывается, как сделать всё то же самое, только со строгой типизацией и без парадоксов. "Всё то же самое" - определение типов, рекурсивных в том числе.
>Вы выдаете собственное мнение за принятый в CS взгляд.
О, моё мнение основывается на принятом в CS. В CS наиболее мощным считается нормальный порядок упрощения, он позволяет выразить наибольшее количество программ, не прибегая к ссылкам и внешним константам.
no subject
Стоп-стоп-стоп, зачем мне проводить исследования? Это же _вы_ ворвались, размахивая яки знаменем своими "90% случаев" (и не первый раз ворвались, надо заметить). Никаких исследований ни я, ни кто-либо еще, естественно, не проводил - просто потому что такие исследования принципиально невозможно провести так, чтобы получить хоть сколько-нибудь корректный результат. И что, этот факт позволяет врываться и нести ересь о 90%? Вы тогда так и говорите: не "90%", а "на мой взгляд человека, с макросами никогда не работавшего и об их применении ничего не знающего - 90%". Это ваше личное мнение, основанное на вашей личной практике. И это будет верно, и никто вам не сможет ничего возразить. А дальше можете ссылаться на Алана Кея и других альтернативно мыслящих, оставшихся в прошлом 50-летней давности с фекспрами, от которых все сообщество (за исключением тех самых альтернативных единиц) отказалось ввиду того, что эти самые фекспры на практике доказали свою говенность.
> В противном случае я бы предпочёл, чтобы вы больше не говорили о большей и меньшей частях
Конечно, не буду. Если вы не будете. Все честно, так? Ну а если вы сами бросаетесь бездоказательными высказываниями - до даете мне полное моральное право поступить аналогичным образом. Сим я заявляю, например, что статическая типизация может исправить не более сотой доли процента от общей совокупности ошибок - и, тем самым, совершенно не нужна. Дико же звучит? Дико. Вот ваши сентенции звучат столь же дико. Будем и дальше бросаться бредовыми бездоказательными заявлениями или переведем беседу в конструктивное русло? Мне без разницы, если честно. Мне и друг друга потроллить будет весело и серьезно те или иные аспекты ЯП обсудить. Оставляю выбор вам.
> Да даже если и нет, то это ваше высказывание означает, что макросы используются лдя расширения синтаксиса. См. выше про синтаксический подход.
А вот здесь я вам могу точно заявить - нет, это не так. Если мы, конечно, говорим о макросах в лиспе или немерле. Подобные макросы могут, естественно, изменять синтаксис - но их назначение в изменении семантики. Если вы на прошлый вопрос ответите, что готовы вести конструктивное обсуждение - я вам готов показать на конкретных примерах отличия. Ясно и четко.
И еще два вопроса - замена аппликативного порядка вычислений на нормальный или замена системы типов являются изменением семантики? Или это изменения синтаксиса?
> Я всего лишь показал
Что вы показали? Что в какой-то реализации хаскеля это можно? Конечно, можно - лямбда-исчисление является тьюринг-полной системой, по-этому любую программу можно свести к вычислительно эквивалентному лямбда-терму. Причем и в ленивом, и в энергичном случае. Это не отменяет того факта, что если у вас примитивные True/False, то case всегда будет спецформой.
> Хотя бы Википедию про кодирование Чёрча.
Да все знают про кодирование Черча, чего вы повторяете как попугай? Вам еще несколько постов назад сказали, как сделать if со _встроенными_ True/False. Если у вас вместо булевых значений лямбды - тут любой дурак справится. Причем порядок вычислений не важен - это одинаково просто и в нормальном и в аппликативном случае.
> О, моё мнение основывается на принятом в CS.
Правда? И где же можно узнать о теоремах где доказано, что нормальный порядок более мощен? Именно мощен.
> В CS наиболее мощным считается нормальный порядок упрощения, он позволяет выразить наибольшее количество программ, не прибегая к ссылкам и внешним константам.
Что значит "выразить большее количество программ"? Любая программа в нормальном порядке тривиальным синтаксическим преобразованием (описываемым в две строчки) приводится к вычислительно эквивалентной программе в аппликативном порядке. Обратное, кстати, тоже верно, правда преобразование не настолько тривиально. Как вы умудряетесь сравнивать "мощность" совершенно эквивалентных с вычислительной точки зрения систем - мне совершенно неясно. Может, все дело в понятии "мощность"? Что вы под ним подразумеваете?
no subject
no subject
Да. Мой анекдотический опыт говорит вот это. Я просто-напросто один раз посчитал макросы в доступных мне программах на языках высокого уровня, натурально. В основном, это был Си, но и тикль встречался. На ассемблере и Форте (в последнем макросы весьма условны) всё по-другому, но там и семантика такая, что не изменив её, далеко не уедешь.
Это было давно, 1999-2001 год.
Попробуйте провести такой опыт.
>>>Еще раз - оптимизация и задерживание аргументов это совершенно не значимая часть макросов. То есть из тысячи макросов этим занимается... ну может один или два.
>> Да даже если и нет, то это ваше высказывание означает, что макросы используются лдя расширения синтаксиса. См. выше про синтаксический подход.
>А вот здесь я вам могу точно заявить - нет, это не так. Если мы, конечно, говорим о макросах в лиспе или немерле. Подобные макросы могут, естественно, изменять синтаксис - но их назначение в изменении семантики.
Приведите, пожалуйста, все макросы из какой-либо не очень большой программы на Лиспе.
(ибо я тут уже приводил кусочки кода, имею право потребовать)
>Что вы показали? Что в какой-то реализации хаскеля это можно? Конечно, можно - лямбда-исчисление является тьюринг-полной системой, по-этому любую программу можно свести к вычислительно эквивалентному лямбда-терму. Причем и в ленивом, и в энергичном случае. Это не отменяет того факта, что если у вас примитивные True/False, то case всегда будет спецформой.
Да и наплевать. В случае расширение RebindableSyntax оператор if...then...else... заменяется на ifThenElse a b c, натурально. Я могу последовательно убирать case, например. В моём HHDL так и сделано, кстати. В язык описания аппаратуры введены алгебраические типы и сравнение с образцом.
>Правда? И где же можно узнать о теоремах где доказано, что нормальный порядок более мощен? Именно мощен.
http://en.wikipedia.org/wiki/Lambda_calculus
Applicative order is not a normalising strategy. The usual counterexample is as follows: define Ω = ωω where ω = λx.xx. This entire expression contains only one redex, namely the whole expression; its reduct is again Ω. Since this is the only available reduction, Ω has no normal form (under any evaluation strategy). Using applicative order, the expression KIΩ = (λx.λy.x) (λx.x)Ω is reduced by first reducing Ω to normal form (since it is the rightmost redex), but since Ω has no normal form, applicative order fails to find a normal form for KIΩ.
In contrast, normal order is so called because it always finds a normalising reduction, if one exists. In the above example, KIΩ reduces under normal order to I, a normal form. A drawback is that redexes in the arguments may be copied, resulting in duplicated computation (for example, (λx.xx) ((λx.x)y) reduces to ((λx.x)y) ((λx.x)y) using this strategy; now there are two redexes, so full evaluation needs two more steps, but if the argument had been reduced first, there would now be none).
Засим позвольте с вами распрощаться. Вы даже Википедию не освоили.
Натурально, отвечать не будут нигде.
no subject
То есть смотрите, что вы фактически сделали - посчитали, как часто в джаве используются анонимные классы, выяснили, что редко, и отсюда сделали вывод, что лямбды (реализацией которых являются анонимные классы) не нужны. Я уж не говорю про сравнение макросов немерле/лиспа с макросми си.
> Приведите, пожалуйста, все макросы из какой-либо не очень большой программы на Лиспе.
Нет, не имеете. Я вам в прошлом посте задал конкретный вопрос исключительно после ответа на который вы и сможете что-то там "требовать". Вы на него так и не ответили.
> Да и наплевать. В случае расширение RebindableSyntax оператор if...then...else... заменяется на ifThenElse a b c, натурально.
Вы что, совсем слепой? Еще раз - любой идиот может убрать кейз. Задача - убрать кейз, сохранив оригинальные True/False. Вот эта задача не решается.
> Applicative order is not a normalising strategy. The usual counterexample is as follows: define Ω = ωω where ω = λx.xx. This entire expression contains only one redex, namely the whole expression; its reduct is again Ω. Since this is the only available reduction, Ω has no normal form (under any evaluation strategy). Using applicative order, the expression KIΩ = (λx.λy.x) (λx.x)Ω is reduced by first reducing Ω to normal form (since it is the rightmost redex), but since Ω has no normal form, applicative order fails to find a normal form for KIΩ.
>In contrast, normal order is so called because it always finds a normalising reduction, if one exists. In the above example, KIΩ reduces under normal order to I, a normal form. A drawback is that redexes in the arguments may be copied, resulting in duplicated computation (for example, (λx.xx) ((λx.x)y) reduces to ((λx.x)y) ((λx.x)y) using this strategy; now there are two redexes, so full evaluation needs two more steps, but if the argument had been reduced first, there would now be none).
Как видно, я был прав - принятое в CS мнение состоит исключительно в том, что энергичные и ленивые программы отличаются исключительно формально - тем фактом, что некоторые программы, эквивалентные при нормальном порядке могут быть неэквивалентными при аппликативном, что никак не сказывается на выразительной мощности. За сим вы признаетесь треплом обыкновенным, не способным ответить за слова.
no subject
Хотя ладно, пойду вам навстречу (хотя вы результат все равно проигнорируете и кукарекнете что-нибудь на тему "кококо плохая семантика кококо поэтому без макросов никак кококо"). Программа, вычисляющая факториал:
[code]
#lang racket
(define (fact n)
(define (rec n acc)
(if (= n 0)
acc
(rec (sub1 n) (* acc n))))
(rec n 1))
[/code]
Во время экспанда 8 макровызовов. Самих макросов 2: define и printing-module-begin, но define весьма нетривиальный (считайте, что эквивалентен целой библиотеке, вообще, это весьма характерно для макросов, когда один единственный макрос заменяет целую библиотеку функций. Именно по-этому нету никакого корректного способа сравнения).
no subject
no subject
> И вот те абстракции, которые будут в реализации макроса, и их свойства - это более существенно, чем сама макроабстракция, которая всего-лишь предоставляет возможность завернуть это в скобочный edsl.
Странно. Я всегда думал, что важен именно интерфейс, а реализация - совсем нет. Ну, у вас свое, альтернативное мнение.
Только вот ответьте мне на один вопрос - как разница, транслируется ваш прекрасный и расчудесный код в императивную лапшу во время стадии макроэкспанда или во время стадии компиляции? Почему тайпчекер, реализованный в виде библиотеки, которая вызывается во время нажатия кнопочки "compile" хуже тайпчекера, реализованног ов виде _той же самой_ библиотеки, но, но вызываемой при нажатии кнопочки "expand"?
no subject
Это зависит от уровней абстракций. Вот смотри, если ты тырпрайз-программист, пишущий erp-систему, то для тебя реализация важна, потому что ты её и пишешь. А бухгалтеру на реализацию пофиг - ему важен интерфейс, потому что он с ним работает.
Так и здесь. Предметно-ориентированные декларативные языки - это инструменты не для программистов, а для экспертов соответствующих предметных областей. А задача программистов в данном контексте - реализация этих языков.
> транслируется ваш прекрасный и расчудесный код в императивную лапшу во время стадии макроэкспанда или во время стадии компиляции
В хороших компиляторах трансляция в императивную лапшу полностью автоматизирована, а пишут их обычно на самом компилируемом языке. А в макросах императивная лапша пишется ручками нерадивого лиспера, которому кажется, что он решает задачу при помощи макроса, а не при помощи этой лапши.
no subject
Что-то вы куда-то не туда ушли. Давайте проще - вот есть у нас несколько монад, у этих монад есть реализация и интерфейс (bind и join). Для использования этого интерфейса есть вдобавок DSL (do-нотация). Есть ли для вас, как пользователя этих монада, разница - каким именно способом реализованы конкретные join и return, а так же каким именно способом выполняется раскрытие do-нотации? Предположу, что нет. по крайней мере, я не могу придумать себе хотя бы одну задачу, в которой это станет важным. А вы?
> В хороших компиляторах трансляция в императивную лапшу полностью автоматизирована, а пишут их обычно на самом компилируемом языке.
Вы только что описали макросы.
> А в макросах императивная лапша пишется ручками нерадивого лиспера, которому кажется, что он решает задачу при помощи макроса, а не при помощи этой лапши.
Вообще, кстати, не совсем ясно, о какой императивной лапше идет речь. К счастью, макространсформер имеет тип (AST,Context) -> (AST, Context), то есть он чисто функционален. Причем никаких костылей в виде уникальных типов или монад не нужно.
no subject
В чём же недостаток?
no subject