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
>Как нормальный порядок вычислений снижает потребность в макросах?
Нормально так снижает, на порядки. Даже можно сказать, замечательно снижает, ибо на порядки.
Простой пример. if в лиспе - специальная форма. В обычных языках программирования он встроен потому, что иначе нельзя. В Хаскеле этот оператор встроен потому, что чуть удобней.
Вот аналог if на Хаскеле:
ifThenElse :: Bool -> a -> a -> a
ifThenElse True th el = th
ifThenElse False th el = el
Теперь вместо "if c then aaa x else bbb y" вы можете писать ifThenElse c (aaa x) (bbb y) и никто не отличит вашу программу от использующую встроенные if. Это будет работать даже с вводом-выводом, ибо этот ввод-вывод не будет выполняться до тех пор, пока от него не потребуют результата.
И далее там всякое интересное. Tying the knot, и тп.
Это не даёт преимуществ оптимизирующих макросов, но и так неплохо, ибо производительность программиста растёт. Вместе с прагмой RULES может дать ещё и выигрыш по скорости.
Насчёт printf. Хаскель не умеет анализировать значения. Но может анализировать типы.
Пусть за меня говорит Олег: http://okmij.org/ftp/typed-formatting/index.html
no subject
no subject
no subject
зато здесь
switch...casepattern matching является специальной формойno subject
http://en.wikipedia.org/wiki/Church_encoding
Сравнение с образцом введено потому, что... удобней! Для алгебраического типа данных можно ввести кодирование функциями, которое будет выполнять "сравнение с образцом". В этом случае case превращается в простое применение функций.
type Bool' a = a -> a -> a -- решил дать параметр, поскольку со скрытием возникают проблемы.
true, false :: Bool' a
true th el = th
false th el = el
a &&. b = a b false
a ||. b = a true b
ifThenElse :: Bool' a -> a -> a
ifThenElse c th el = c th el
no subject
вот покажите реализацию функции, которая, например, вернёт true этого Bool', если x < 5, а в противном случае - false, тогда отстану. А то пока не очевидно, что можно совсем-совсем обойтись.
no subject
Попробуйте прочитать про кодирование Чёрча и написать сами. Это не сложно.
Числа:
data Nat = Zero | Succ Nat
Предикат:
less :: Nat -> Nat -> Bool
less Zero (Succ n) = True
less Zero Zero = False
less (Succ a) (Succ b) = less a b
less (Succ n) Zero = False
five = Succ (Succ (Succ (Succ (Succ Zero))))
less5 a = less a five
Я, с вашего позволения, займусь практическим применением Хаскеля. Это более полезно "для одного из обоих нас".
no subject
no subject
Сравниваю, чтобы показать выразительность ленивых вычислений. Там, где в Хаскеле обходятся одними функциями высших порядков (функция when :: Monad m => Bool -> m a -> m (), bracket :: Monad m => m h -> (h -> m a) -> (h -> m r) -> m r, использовать bracket openFile hClose thingsToWrite), в Лиспе требуются дополнительные выразительные средства.
no subject
(no subject)
(no subject)
no subject
Ваш тезис был, что "if...else" вообще не нужно в Хаскеле, что является примером, почему в Хаскеле не нужны макросы в отличие от Лиспа. Вот я хочу в этом тезисе разобраться.
Так вот, я замечаю, что ваш первый пример использует другую встроенную форму "if..else".
Второй ваш пример вводит функции true и false, которым можно передать два continuation. Но а. почему это не возможно в лиспе (ибо изначально разговор за if...else начался из-за контрипримера макросам) б. пример с возможной реализацией < через Succ понятен, но неужели так и реализовано?
Я ж вопросы задаю не для того, чтобы над идеей поиздеваться, а хочу понять вашу мысль о макросах. Может, тогда пример другой нужен?
(no subject)
(no subject)
(no subject)
(Anonymous) - 2012-05-15 15:09 (UTC) - Expand(no subject)
(Anonymous) - 2012-05-15 15:12 (UTC) - Expandno subject
do_something(x) if condition
Такое насколько легко запилить на ленивых функциях?
Пример с if хрестоматийный, но сильно далеко в этом направлении не уедешь. Макросы же дают свободу в синтаксисе, а ленивость - не очень-то. Вот если бы в хаскеле не было do-нотации, можно ли ее добавить чисто ленивостью? Макросами можно. XML-литералы насколько легко добавить в хаскель одной ленивостью? В язык с макросами легко. Манипуляции с типами функций можно сделать одной ленивостью? Макросами можно. И т.д.
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)
(no subject)
(no subject)
(no subject)
(no subject)
(no subject)
(no subject)
(no subject)
no subject
(no subject)
(no subject)
(no subject)
no subject
В чём же недостаток?
no subject
no subject
(Anonymous) 2012-05-15 03:07 pm (UTC)(link)no subject
Лиспомакросы:
Типизированные ленивые частично-применяемые функции:
bracket = unwind-protect