Функциональное программирование в Nemerle - замечания по статье
От: FDSC Россия consp11.github.io блог
Дата: 20.05.07 13:56
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Здравствуйте, FDSC, Вы писали:


FDS>>Честно скажу: старался читать внимательно и прочитал даже чуть больше половины После чего у меня перегорел последний защитный предохранитель и я понял: "Влад опять рассказывает фичи Немерле по отдельности...".


VD>Здесь был бы очень полезен анализ того, что напрягло и в каком конкретно месте перегорел предохранитель. Глядишь можно было бы дополнить статью или при написании новой учесть ошибки старой.



Собственно, системы пожаротушения у меня сработали на C#-коде, только я не заметил, что он C#
В любом случае, там слишком мало пояснений, т.е. как код работает понятно, но его не мешало бы детально разобрать.

А предохранитель задымился на разделе "Реальный пример декомпозиции функций", вот там я так и не понял, понял я что-то или нет (ну, т.е. понятно, что одно из условий выносится в отдельную функцию как заранее не определённый предикат-параметр функции, но что именно и как там делается... убейте меня об стену ). Да и скобки там перед && не мешало бы поставить во избежание побочных эффектов от неправильного порядка вычисления выражений (или они там не нужны?)


VD>Это действительно сложный вопрос. Я тоже не знаю на него ответа. Вот если передо мной стоит конкретна задача, то наверно я смогу объяснить как бы я ее решил и поучему. А вот как сформулировать общие принцыпы я незнаю.


VD>Наверно общим принципом является дизайнерский выбор того как решать задачу. Если выбирается подход с эмуляцией проблемы с помощью объектов и изменения их состояний, то надо использовать ОО-фичи языка которые почти 1 в 1 как в C#. Другой подход который можно предпочесть — это описание модели как набора вариантов, а их обработку как набор преобразований (конвертаций) этих данных в другие представления.



Собственно, вот здесь и было бы неплохо расшифровать применение "конвертаций" совместо с ООП. Т.е. ясно, что Nemerle не Sceme и "конвертации" будут выглядеть по другому. Соотв., хотелось бы увидеть как

Т.е. увидеть ФП не так, как его SICP показывает, а на архитектурном уровне в сочетании с ООП. Как и где ФП-решения сочетаются с ООП.Возможно, на реальных примерах даже лучше было бы, если есть нужное их количество
Опять же, Nemerle легко позволяет отход от строй константности переменных, что то же может дать изменение в стиле программирования по сравнению с традиционными ФП — опять же, было бы неплохо продемонстрировать как это делается. А то сейчас я мыслю как реле — или ФП, или ООП. В итоге в Немерле для меня полезны одни только замыкания


VD>По сути это и есть выбор междц ООП и ФП. Во втором случае и используются фунциональные фичи вроде вариантов, паттерн-матчинга и функций высшиго порядка.


Вот хотелось бы тот же паттерн-матчинг и проч. описать не на уровне кода. Дело в том, что, я так понимаю, не только мне, непонятны некоторые приводимые примеры сопоставлений с образцом. Совершенно не понятна логика программиста, когда он думая об общей реализации программы вдруг пришёл к необходимости сопоставления с образцом.
Проще говоря, хотелось бы на примере высокоуровневой структуры программы и размышлений программиста посмотреть, как и где он приходит к выводу об использовании сопосотавлений с образцом вместо каких-либо других методов.

Т.е., фактически, нужен пример логики программиста, когда он думает о том, какой код напишет, но самого кода ещё нет

VD>Вот приведенный пример калькулятора как раз хорошо подпадает под фунициональное решение. На входе мы имеем модель одного вида (AST), а на выходе другого (вычесленное выражение и строковое предсавление). Приведенный здесь
Автор: VladD2
Дата: 16.05.07
пример оптимизации тоже подподает под понятие "конвертации".


Замечательный пример, НО только тот, который длинный, с Convert: от этого он почему-то намного понятнее становится. А просто с Eval уж больно просто Честное слово, с Convert до меня дошло почти сразу (правда не совсем точно, но дошло), как увидел, а с Eval я не понял что деется... почему, не знаю. Видать два почти одинаковых кода есть, которые делают разные вещи и поэтому их можно сравнить.

Кстати, вот ещё было бы интересно посмотреть на этот калькулятор с функциями, вынесенными в отдельный текстовый файл, который бы компилировался динамически, будет ли тогда возможно применить сопоставление с образцом?


VD>Ну, SDK не требуется. В прочем SDK по сравнению с самой студией — это просто ничто (студия гигабайты, а SDK сто с копейками мег.).


Эээээ.... только не пугайте меня... студию-то зачем по инету скачивать? Её я скачаю разве что через пару лет (у меня Dial-Up)
Кароче говоря, как использовать интеграцию лично я не понял, и возможно ли это вообще делать с Dial-Up

Вообще, не мешало бы собрать воедино, что как делать и какие типичные ошибки бывают при использовании Nemerle, а то я помню, у меня по началу постоянно вылетали приложения и т.п., потом разобрался в чём дело, а сейчас вот после долгого перерыва боюсь, вдруг опять перестанет работать

VD>Проблема в том, что структура завист от выбираемых решений. Я демонстрирую средства и примеры решений. И тлько от конкретного программиста зависит то как он решит проблему. Уверен, что первые решения все как одно будут в ОО-стиле и на сквозь императивными. Но если стремиться улучшать свой код, то довольно быстро обучаешся исползовать функциональные возможности.


Дело в том, что не демонстрируется способ, которым вы пришли к решению

VD>По сути учиться писать фунционально можно и на C# 2.0. Только результат не всего удет выглядеть хорошо. Но это не главное. Главное научиться думать о прорамме как о серии преобразований исходных данных в конечные. Тогада все непонятные фичи вдруг сразу станут очень понятными и удобными.


Да я о ней так всегда думаю


VD>К сожалению, без личного опыта видимо это понять нельзя. По этому я пытаюсь показать результат. Причем на на детских примерах вроде фибоначи, а на более менее серьезной порграмме.


VD>Надо пробовать. Как показала практика все программисты которые хотели освоить новый язык и принимали участие в том или ином проекте через некоторое время отлично его осваивали.


Я без нормально описания языка программировать не очень-то могу: слишком неприятно. Проблема, в т.ч., и в том, что никогда не уверен в том, что сделает компилятор из твоего кода. Тут надо долго мучаться и всё время ходить на форум искать или спрашивать
А я очень уж не люблю чувствовать себя с компьютером неуверенно.




22.05.07 00:49: Ветка выделена из темы Функциональное программирование в Nemerle
Автор: Чистяков Влад (VladD2)
Дата: 03.03.07
— VladD2
Re: Пояснение
От: FDSC Россия consp11.github.io блог
Дата: 20.05.07 14:01
Оценка:
Здравствуйте, FDSC, Вы писали:

FDS>Собственно, системы пожаротушения у меня сработали на C#-коде, только я не заметил, что он C#

FDS>В любом случае, там слишком мало пояснений, т.е. как код работает понятно, но его не мешало бы детально разобрать.

Я имею ввиду, например, строку

| Plus(e1, e2) | Minus(_, e2) with e1 = null


Честно говоря, не дошло...
Желательно было бы вообще рассказать, что делает компилятор, когда вообще такую конструкцию встречает. Что бы можно было повторить путь компилятора и точно понять, что делается
Re: Функциональное программирование в Nemerle - замечания по статье
От: konsoletyper Россия https://github.com/konsoletyper
Дата: 20.05.07 14:18
Оценка:
Здравствуйте, FDSC, Вы писали:

VD>>По сути это и есть выбор междц ООП и ФП. Во втором случае и используются фунциональные фичи вроде вариантов, паттерн-матчинга и функций высшиго порядка.


FDS>Вот хотелось бы тот же паттерн-матчинг и проч. описать не на уровне кода. Дело в том, что, я так понимаю, не только мне, непонятны некоторые приводимые примеры сопоставлений с образцом. Совершенно не понятна логика программиста, когда он думая об общей реализации программы вдруг пришёл к необходимости сопоставления с образцом.

FDS>Проще говоря, хотелось бы на примере высокоуровневой структуры программы и размышлений программиста посмотреть, как и где он приходит к выводу об использовании сопосотавлений с образцом вместо каких-либо других методов.

FDS>Т.е., фактически, нужен пример логики программиста, когда он думает о том, какой код напишет, но самого кода ещё нет


Нужно просто попрактиковаться немного, вот и всё. Уже немного устал зханиматься пропагандистской работой, но всё же оно того требует. Вот здесь
Автор: konsoletyper
Дата: 31.03.07
есть кое-какая инфа о проекте, в котором мне не помешала бы помощь извне. Разобраться в нём проще, чем в компиляторе или в Интеграции. Предлагаю присоединиться.

FDS>Кстати, вот ещё было бы интересно посмотреть на этот калькулятор с функциями, вынесенными в отдельный текстовый файл, который бы компилировался динамически, будет ли тогда возможно применить сопоставление с образцом?


А написание парсера, который генерит подходящий AST для компилятора — это уже совсем другая задача. Кстати, в моём проекте есть пример парсера математических выражений с простейшей функцией извлечения производной.
... << RSDN@Home 1.2.0 alpha rev. 672>>
Re[2]: Функциональное программирование в Nemerle - замечания по статье
От: FDSC Россия consp11.github.io блог
Дата: 20.05.07 16:24
Оценка:
Здравствуйте, konsoletyper, Вы писали:

K> Предлагаю присоединиться.


Спасибо, но у меня есть свои задачи, которые требуют решений.

FDS>>Кстати, вот ещё было бы интересно посмотреть на этот калькулятор с функциями, вынесенными в отдельный текстовый файл, который бы компилировался динамически, будет ли тогда возможно применить сопоставление с образцом?


K>А написание парсера, который генерит подходящий AST для компилятора — это уже совсем другая задача. Кстати, в моём проекте есть пример парсера математических выражений с простейшей функцией извлечения производной.


Мне просто было бы интересно посмотреть, можно ли применять динамическое сравнение с образцом, т.е. когда заранее неизвестны ни варианты сравнения, ни варианты действий. Это было бы интересно, хотя, думаю, кроме как через дин. компиляцию это сделать нельзя
Re: Функциональное программирование в Nemerle - замечания по статье
От: VladD2 Российская Империя www.nemerle.org
Дата: 21.05.07 01:31
Оценка:
Здравствуйте, FDSC, Вы писали:

FDS>А предохранитель задымился на разделе "Реальный пример декомпозиции функций", вот там я так и не понял, понял я что-то или нет (ну, т.е. понятно, что одно из условий выносится в отдельную функцию как заранее не определённый предикат-параметр функции, но что именно и как там делается... убейте меня об стену ).


ОК. Будет время попробую дописать разняснения. Хорошо бы получить список мест требующих таких разяснений. Ведь это наверно не одно?

FDS>Да и скобки там перед && не мешало бы поставить во избежание побочных эффектов от неправильного порядка вычисления выражений (или они там не нужны?)


А вот это личшее. Лучше одучить приоритеты оператов. Они аналогичны C#-ным. Лишние скобки ухудшат читаемость.


FDS>Собственно, вот здесь и было бы неплохо расшифровать применение "конвертаций" совместо с ООП. Т.е. ясно, что Nemerle не Sceme и "конвертации" будут выглядеть по другому. Соотв., хотелось бы увидеть как


Да на самом деле в Схеме все будет очень похоже если не учитывать синтаксис. Просто на задачу нужно смотреть как на преобразование чего-то в нечто обладающее новыми качествами. Собственно это и есть самая частая задача в компиляторе.

Ну, вот простой пример. Берем тот же комплятор. Предположим, что в нем есть стадии до типизации когда АСТ — это всего лишь дерево хранящее информцию о синтаксических конструкциях и стадии после типизации (когда известны типы параметров и возвращаемых значнеий). Так вот если использовать классический ООП-подход, то мы может добавить у классов описывающих АСТ свойсва которые содержат null в первой стадии (до типизации) и ссылки на описание типов после стадии типизации. Само дерево можно сделать изменяемым и если нам нужно его менять, то мы и будем его менять. При этом старое дерево уйдет в небытие (изменится). Второй подход, фунциональный, предложит разделить деревья на типизированное и нетипизированное. При этом процедуру типизации можно оформить в виде фукнции принимающей на вход нетпизированное АСТ и возвращающее типизированное. Получается, что мы сделали фукнцию преобразования (конвертации). Вот в Linq ребята из МС раши красивую форму для этой конвертации — запрос. Они по сути ввели в язык функциональные конструкции, но офрмили их как SQL. Причем не смотря на то, то что SQL более громоздок, нежели функциональная запись они добиваются главного — упрощения восприятия новых идей пользователями. Ведь пользователь уже изучил SQL и видя похожую на него вещь (ведь Linq-овские запросы отнюдь не SQL-закросы) он не страдает синдромом ломки, ведь все это ему уже знакомо и он умеет думать в терминах запросов.

Запрсоы в SQL они в принципе декларативны. Так что это хорошая анлогия. Можно смотреть на функциональный код как на код состоящий из запросов, а когда пыташся создать фунциональную программу думать о ней как о создание череды запросов преобразующих данные в некоторый конечный вид. Кстати, когда я в свое время стал так же думтаь о самом SQL-е, то сильно приуспел в написании сложных запросов, ведь вложенные запросы стали очевидными для меня.

FDS>Т.е. увидеть ФП не так, как его SICP показывает, а на архитектурном уровне в сочетании с ООП.


Дык сочетание только в том, что одно сдержит другое. Ну, еще фнкции вроде Map и Fold могут быть методами, что немного красивее выглядит, на мой взгляд.

FDS>Как и где ФП-решения сочетаются с ООП.Возможно, на реальных примерах даже лучше было бы, если есть нужное их количество


Опять берем компилятор. Сам компилятор логично оформить в виде класса. А вот АСТ в виде вариантов.

FDS>Опять же, Nemerle легко позволяет отход от строй константности переменных, что то же может дать изменение в стиле программирования по сравнению с традиционными ФП — опять же, было бы неплохо продемонстрировать как это делается. А то сейчас я мыслю как реле — или ФП, или ООП. В итоге в Немерле для меня полезны одни только замыкания


С переменными надо поступать очень просто. Надо взять за правило использовать исключительно неизменяемые перменные. Если надо переписывать код так, чтобы он не нуждался в изменяемых переменынх. И вот уже если ты понимаешь, что обойтись без изменяемой перменной невозможно, или это приводит к существенному усложненияю кода, тогда можно использовать изменяемую. Причем еще раза два-три подумать прежде чем принять такое решение. Сам не замешь, как через некоторое время у тебя 99% переменных убедт неизменяемые, код более функциональный.

По сути, технически фукнциональный код отличается от не функционального только наличием изменяемых перменных. Сюда првда входяти лкассы с оными (или свойствами доступными на запись), так что использование Hashtable уже приводитк не фунциональному коду. Но раз хэш-таблица нужна, значит нужна и фунционльный код не выгоден в данных условиях.

FDS>Вот хотелось бы тот же паттерн-матчинг и проч. описать не на уровне кода. Дело в том, что, я так понимаю, не только мне, непонятны некоторые приводимые примеры сопоставлений с образцом.


Дык тыкай пальцеам. Будем объяснть. А потом статью подпрвлю, чтобы таких мест не было.

FDS> Совершенно не понятна логика программиста, когда он думая об общей реализации программы вдруг пришёл к необходимости сопоставления с образцом.


Дык думал о данных как о наборе значний которые нужно преобрзовать в другой. Только и всего.
Тут только практика поможет. Я не видел чтобы люди пописали на языке и у них возникали такие вопросы.

FDS>Проще говоря, хотелось бы на примере высокоуровневой структуры программы и размышлений программиста посмотреть, как и где он приходит к выводу об использовании сопосотавлений с образцом вместо каких-либо других методов.


Ну, не знаю. Если только взять и переписать, например, мой редактор кода с C# на Nemerle заменяя где можно классы на варианты и т.п.

FDS>Т.е., фактически, нужен пример логики программиста, когда он думает о том, какой код напишет, но самого кода ещё нет


Ох не просто это. Процесс мышления описывать — это все равно как дышание контролировать усилием воли. Ты просто дышишь или думашь, а начинашь думать как ты думашь и шарики за ролик изаходят.

FDS>Замечательный пример, НО только тот, который длинный, с Convert: от этого он почему-то намного понятнее становится. А просто с Eval уж больно просто Честное слово, с Convert до меня дошло почти сразу (правда не совсем точно, но дошло), как увидел, а с Eval я не понял что деется... почему, не знаю. Видать два почти одинаковых кода есть, которые делают разные вещи и поэтому их можно сравнить.


Ну, если бы я был такой умный вчера, как сейчас, то меня звали бы Бил Гейтс .
Раз этот пример доходчив, значит нужно расширить статью им. Так что можно сказать, что даже от самого упертого спорщика бывает польза, причем не смотря на то смог ты ему доказать что-то (точнее объяснить) или нет.

FDS>Кстати, вот ещё было бы интересно посмотреть на этот калькулятор с функциями, вынесенными в отдельный текстовый файл, который бы компилировался динамически, будет ли тогда возможно применить сопоставление с образцом?


Э... не понял. Сделать лексический и синтаксический разбор? Это можно, но по крайней мере лексер будет мало отличаться от C#-ного, а парсер окажется бональным рекурсивным спуском который хотя и отлично пишется в функциональном стиле, но тем не менее неплохо реализуется и на классических процедурных языка (на С не говоря уже о C#).

Боюсь это займет много места в статье и отвлечет от ее темы. У меня же не было задачи создать именно калькулятор. Это был пример элюстрирующий теорию. Просто калькулятор мне близок так как сейчас я заниаюсь интеграцией со студией и много копаюсь в компляторе.

FDS>Эээээ.... только не пугайте меня... студию-то зачем по инету скачивать? Её я скачаю разве что через пару лет (у меня Dial-Up)

FDS>Кароче говоря, как использовать интеграцию лично я не понял, и возможно ли это вообще делать с Dial-Up

Если у тебя студия есть, то скачай модуль интеграции
Автор: Блудов Павел
Дата: 08.05.07
(два мега) и поставь его (это инсталлятор). Более ничего делать не надо. В студии появится новый язык и шаблоны проектов.

FDS>Вообще, не мешало бы собрать воедино, что как делать и какие типичные ошибки бывают при использовании Nemerle, а то я помню, у меня по началу постоянно вылетали приложения и т.п., потом разобрался в чём дело, а сейчас вот после долгого перерыва боюсь, вдруг опять перестанет работать


Дык вот и поделился бы, что у тебя была за проблема. Я знаю только одну проблему которая почти исчезла с опытом и появлением интеграции — это когда ты запутался в трех соснах, а компилятор выдает невнятные ошибки (их тоже, кстати улучшели за последнее время). Тут решение очень просто. Нужно добавлять явные аннотации типов (благо это омжно делать прямо в середине кода, а не только у переменных ипараметров) и разносить код на отдельные строки внсоя промежуточные перменные.

Возможно, по начлау полезным будет делать так. Если не понимаешь как реализовать что-то через рекуссию, паттерн-матчинг и т.п., то сначал написать все влоб как на Шарпе (эдаком C##), а потом подумать и постепенно переписать кода с использованием расширенных возможностей. Не грех бросить такой код сюда. Народ подскажет.

VD>>По сути учиться писать фунционально можно и на C# 2.0. Только результат не всего удет выглядеть хорошо. Но это не главное. Главное научиться думать о прорамме как о серии преобразований исходных данных в конечные. Тогада все непонятные фичи вдруг сразу станут очень понятными и удобными.


FDS>Да я о ней так всегда думаю


Ну, значит дело за малым. За практикой. Я раньше тоже не понимал фунциональный код. Паттерн-матчинг вообще в ступор вводил. А потом все само встало на свои места.

FDS>Я без нормально описания языка программировать не очень-то могу: слишком неприятно.


Ладно тебе. Есть и неплохое описание на стайте. И несклько статей. Для человека знающего шапр это проблемой быть не должно.

FDS>Проблема, в т.ч., и в том, что никогда не уверен в том, что сделает компилятор из твоего кода.


Дык можно подглядеть рефлектором. К тому же я во водной статье как раз описывал семантику переписыания паттернов в if-ы. Прочитай еще раз эту статью
Автор(ы): Сергей Туленцев, Владислав Чистяков
Дата: 23.05.2006
Производительность труда программиста в основном зависит от самого программиста. Однако даже самый опытный и знающий программист мало что может без подходящего инструмента. Эта статья открывает цикл статей об одном из таких инструментов, еще мало известном среди программистов, но очень многообещающем. Язык Nemerle, о котором пойдет речь в этих статьях, на первый взгляд очень похож на слегка улучшенный C#, но привносит многое из передовых исследовательских языков. Данная статья рассказывает об отличиях Nemerle от C# (как наиболее близкого языка)и является неформальным введением в язык.
.

FDS> Тут надо долго мучаться и всё время ходить на форум искать или спрашивать

FDS>А я очень уж не люблю чувствовать себя с компьютером неуверенно.

Ну, хорошее знание C# и темболее C++ (а Немерле по гибкости его превосходит в разы) без форумов тоже невозможно. Так что это нормально. Описание и статьи дают базу. Они дают начать программирвоать. А далее сталкиваясь с реальными проблемами нужно шлифовать свое мастерство. А это уже можно делать только в коллективе. Форум и есть замена коллектива.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[2]: Пояснение
От: VladD2 Российская Империя www.nemerle.org
Дата: 21.05.07 01:31
Оценка:
Здравствуйте, FDSC, Вы писали:

FDS>Я имею ввиду, например, строку


FDS>
FDS>| Plus(e1, e2) | Minus(_, e2) with e1 = null
FDS>


FDS>Честно говоря, не дошло...

FDS>Желательно было бы вообще рассказать, что делает компилятор, когда вообще такую конструкцию встречает. Что бы можно было повторить путь компилятора и точно понять, что делается

А такой строки не было. Были такие:
| Plus(e1, e2) with op = "+" | Minus(e1, e2) with op = "-" 
| Mul (e1, e2) with op = "*" | Div  (e1, e2) with op = "/" 
                                        => $"$e1 $op $e2"

Они делают очень простую вещь. Находят образцы
| Plus(e1, e2)
| Minus(e1, e2) 
| Mul (e1, e2) 
| Div  (e1, e2)

и для каждого из них в переменную op помещают соответствующую строку. Для Plus(e1, e2) это будет "+", для Minus(e1, e2) — "-" и так далее.
Это называется ad-hok-полиморфизм, или полиморфизм по месту. Мы заставляем компилятор считать перечисленные значения варианта Plus, Minus, Mul, Div одинаковыми (полиморфными) и обрабатываем их одним обработчиком '=> $"$e1 $op $e2"'. Но для нас все же есть разница что за значение пришло в функцию. Можно было написать так:
match (this)
{
    | Literal(value)    => value.ToString()
    | Call(name, parms) => $"$name(..$parms)"
    | Plus(e1, e2) | Minus(e1, e2) 
    | Mul (e1, e2) | Div  (e1, e2) =>
        def op = match (this)
        {
            | Plus  => "+"
            | Minus => "-"
            | Mul   => "*"
            | Div   => "/"
        };
        
        e1.ToString() + op + e2.ToString()
}

но это было бы длинее и медленее (проверка делалась бы два раза).
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[3]: Пояснение
От: FDSC Россия consp11.github.io блог
Дата: 21.05.07 12:31
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Здравствуйте, FDSC, Вы писали:


FDS>>Я имею ввиду, например, строку


FDS>>
FDS>>| Plus(e1, e2) | Minus(_, e2) with e1 = null
FDS>>


FDS>>Честно говоря, не дошло...

FDS>>Желательно было бы вообще рассказать, что делает компилятор, когда вообще такую конструкцию встречает. Что бы можно было повторить путь компилятора и точно понять, что делается

VD>А такой строки не было


Как это не было, когда была В самом листинге не было, а вот в пояснениях была...
Re[2]: Функциональное программирование в Nemerle - замечания по статье
От: FDSC Россия consp11.github.io блог
Дата: 21.05.07 12:31
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Здравствуйте, FDSC, Вы писали:


FDS>>А предохранитель задымился на разделе "Реальный пример декомпозиции функций", вот там я так и не понял, понял я что-то или нет (ну, т.е. понятно, что одно из условий выносится в отдельную функцию как заранее не определённый предикат-параметр функции, но что именно и как там делается... убейте меня об стену ).


VD>ОК. Будет время попробую дописать разняснения. Хорошо бы получить список мест требующих таких разяснений. Ведь это наверно не одно?



Собственно, мест именно непонятных 3:
строка
| Plus(e1, e2) | Minus(_, e2) with e1 = null


далее

    | EndBrace            => check(_ is Token.BeginBrace)  // }
    | EndRound            => check(_ is Token.BeginRound)  // )
    | EndSquare           => check(_ is Token.BeginSquare) // ]
    | EndQuote            => check(_ is Token.BeginQuote)  // ]>
  }
  and check(predicate)
  {
      if (stack.Count > 0 && predicate(stack.Peek()))


Вопрос, как будет работать код типа этого

 | EndBrace            => check(FirstCondition || SecondCondition)
}
  and check(predicate)
  {
      if (stack.Count > 0 && predicate(stack.Peek()))


Это будет (|| по приоритету вроде ниже &&)
((stack.Count > 0) && FirstCondition ) || SecondCondition

или
(stack.Count > 0) && (FirstCondition  || SecondCondition)


Пока писал до меня дошло, что predicate — это функция, а не макрос (по типу C-шных) и, следовательно, исполняться будет правильно без скобок

Т.е. проблема была в том, что

_ is Token.BeginBrace

— не очень-то очевидный приём. Т.е. понятно, что в итоге образуется анонимная функция
SomeLambda(x: boolean): boolean
{
  return x is Token.BeginBrace;
}

но как-то это далеко не сразу доходит. Т.е. лучше было бы это написать в явном виде. Что вот это делается именно так, а не иначе. Я на это очень много времени убил, хотя, вроде, код выше с частичным применением функций понял без проблем (если бы не читал какую-то более раннюю статью, не понял бы нефига, т.е. иллюстрация частичного применения в этой статье не является самодостаточной)


ещё

Тот же эффект проявляется и в более сложных структурах данных, например, в деревьях. Неизменяемость элементов позволяет добиться эффекта версионности. Добавляя новые элементы в дерево, мы вынуждены заменять все ветки от заменяемой до корневой ветки включительно. Казалось бы лишние расходы?! Но глубина сбалансированного двоичного дерева обычно не бывает очень большой. Зато неизменность предыдущих веток позволяет иметь одновременно в памяти множество разных версий дерева. Причем затраты на их создание значительно ниже, чем если копировать все дерево целиком.

Т.е. тут просто так вдруг берётся, да и говорится, что вот мол, деревья сбалансированные... не понятно зачем откуда и куда.
Опять же, понять этот абзац перед пояснениями и листингом трудно... напрягаться приходится, представлять структуру дерева Рисуночек бы что-ли вставил...

Для понимания этого
public Insert[T](tree : Node[T], elem : T, replace : bool) : Node[T]

пришлось лезть в документацию (я не помнил, что [T] — это определение шаблона типа)

Тут вот как раз самое интересное начинается.


public Insert[T](tree : Node[T], elem : T, replace : bool) : Node[T]
  where T : System.IComparable[T]
{
  def insert(tree)
  {
    | Node.Red(key, ltree, rtree) =>
      if (elem.CompareTo(key) > 0)
        Node.Red(key, ltree, insert(rtree))
      else if (elem.CompareTo(key) < 0)
        Node.Red(key, insert(ltree), rtree)
      else if (replace)
        Node.Red(elem, ltree, rtree)
      else
        throw System.ArgumentException("node already in the tree")
        
    | Node.Black(key, ltree, rtree) =>
      if (elem.CompareTo(key) > 0)
        BalanceRight(key, ltree, insert(rtree))
      else if (elem.CompareTo(key) < 0)
        BalanceLeft(key, insert(ltree), rtree)
      else if (replace)
        Node.Black(elem, ltree, rtree)
      else 
        throw System.ArgumentException("node already in the tree")
        
    | Node.Leaf => Node.Red(elem, Node.Leaf(), Node.Leaf())
  }
  
  match (insert(tree))
  {
    | (Node.Black) as tree => tree
    | Node.Red(key, ltree, rtree) => Node.Black(key, ltree, rtree)
    | Node.Leaf => assert(false)
  }
}

Скажем так, здесь можно только догадываться, правильно ли понял то, что написано, или нет.
Я пишу, а вы поправите:

| Node.Red(key, ltree, rtree) =>

Т.е. это условие на то, что tree является именно Red, насколько я понимаю (это тоже бы не мешало пояснить), в определении структуры Node[T] указывается, что узел может быть красный, чёрный или концевой ("лист").
При этом, если узел красный, то мы получаем в локальные переменные (которые автоматически объявляются?) key, ltree и rtree записи из структуры tree

Дальше
  // вставка нового элемента elem в tree
  match (insert(tree))
  {
      // Если корневой элемент дерева был чёрным, то вернуть его, как результирующее дерево
    | (Node.Black) as tree => tree
     // Если корневой элемент красный, то создаётся новый элемент-копия корня, но уже чёрного цвета и он уже возвращается
    | Node.Red(key, ltree, rtree) => Node.Black(key, ltree, rtree)
    | Node.Leaf => assert(false)
  }

Вот и вопрос, правильно я понял или нет? Я ведь при чтении статьи не должен задаваться такими вопросами... наоборот, должен быть уверен, что тут всё именно так, как я понял

Дальше

Не знаю, может плохо смотрел, но, скажем, в SICP я не нашёл, как правильно работать с графом, представленным списками смежности
Т.е. у меня есть структура данных, для определённости, представляющие страницы html и связи между ними.
Соотв., мне нужно работать со структурой, где в вершинах графа будет содержимое страницы, дальше будут список ссылок (с их данными), в каждой из ссылок одно из полей будет указывать на целевую страницу. На вершине целевой страницы есть служебная ссылка, указывающая назад, на ссылающуюся страницу

Представим себе, что мне нужно просто добавить появившуюся страницу. Со списками довольно просто — присоединяем к ним новую страницу и, тем самым, создаём новый список. Но, куда этот новый список девать? Вообще говоря, здесь ведь предполагается, что ВСЕ вершины графа (если, конечно, он связный) будут заменены. Так или нет?
Соотв., для оптимизации такой вещи, не мешало бы вместо замены вершинов графов сделать их изменяемыми и просто сохранить неким образом (списком списков) как старые списки (для сохранения предыдущего состояния), так и новые списки смежности. Получается, что всё-таки решение здесь именно ФП-ООП, а не так, что ООП скрывает ФП.
Можно ли это сделать на чистом ФП? И, опять же, я тут привёл пример того, как ООП и ФП могут сочетаться именно в одном уровне кода. Насколько я понимаю, здесь список списков будет фактически указывать лишь на какие-то элементы дерева, о котором вы говорили в статье


FDS>>Да и скобки там перед && не мешало бы поставить во избежание побочных эффектов от неправильного порядка вычисления выражений (или они там не нужны?)


VD>А вот это личшее. Лучше подучить приоритеты оператов. Они аналогичны C#-ным. Лишние скобки ухудшат читаемость.


См. выше, не про это говорил.

VD>Дык думал о данных как о наборе значний которые нужно преобрзовать в другой. Только и всего.

VD>Тут только практика поможет. Я не видел чтобы люди пописали на языке и у них возникали такие вопросы.

Угу, я в диплом сейчас буду писать немножко на Nemrle (правда, далеко не всё... а то так и завалить можно). Наверное, буду методы численного интегрирования на Nemerle реализовывать

FDS>>Проще говоря, хотелось бы на примере высокоуровневой структуры программы и размышлений программиста посмотреть, как и где он приходит к выводу об использовании сопосотавлений с образцом вместо каких-либо других методов.


VD>Ну, не знаю. Если только взять и переписать, например, мой редактор кода с C# на Nemerle заменяя где можно классы на варианты и т.п.


Ужасти какие....

Да я писать ничего и не предлагаю. Просто взять задачу и так же текстом сказать, что вот, можно решить так, а можно так. Даже без кода. А код для иллюстрации на парочку маленьких примерчиков



VD>Раз этот пример доходчив, значит нужно расширить статью им. Так что можно сказать, что даже от самого упертого спорщика бывает польза, причем не смотря на то смог ты ему доказать что-то (точнее объяснить) или нет.


+

FDS>>Кстати, вот ещё было бы интересно посмотреть на этот калькулятор с функциями, вынесенными в отдельный текстовый файл, который бы компилировался динамически, будет ли тогда возможно применить сопоставление с образцом?


VD>Э... не понял. Сделать лексический и синтаксический разбор? Это можно, но по крайней мере лексер будет мало отличаться от C#-ного, а парсер окажется бональным рекурсивным спуском который хотя и отлично пишется в функциональном стиле, но тем не менее неплохо реализуется и на классических процедурных языка (на С не говоря уже о C#).


Да нет. Это уже не важно, только что сообразил, что в то, что я предлагаю реализуется классом Dictionary. Я предлагал просто сделать настраиваемый калькулятор. Т.е. где определения функций хранятся в отдельном файле. Но тогда это уже не сопоставление с образцом... просто загрузить в словарь имена функций и сами функции и искать то, что надо.



VD>Если у тебя студия есть, то скачай модуль интеграции
Автор: Блудов Павел
Дата: 08.05.07
(два мега) и поставь его (это инсталлятор). Более ничего делать не надо. В студии появится новый язык и шаблоны проектов.


Вчера ещё скачал — вроде правда работает Спасибо


VD>Дык вот и поделился бы, что у тебя была за проблема. Я знаю только одну проблему которая почти исчезла с опытом и появлением интеграции — это когда ты запутался в трех соснах, а компилятор выдает невнятные ошибки (их тоже, кстати улучшели за последнее время). Тут решение очень просто. Нужно добавлять явные аннотации типов (благо это омжно делать прямо в середине кода, а не только у переменных ипараметров) и разносить код на отдельные строки внсоя промежуточные перменные.


Ну, насколько я помню, был ещё прикол с тем, что у кого-то ncc.exe был обработан ngen-ом и работал гораздо быстрее, а у кого-то нет... но я там не помню уже
Потом, честно говоря уже забыл, но когда я запускал программу Nemerle на другом компьютере, эта прога чего-то требовала... опять же, просто лучше написать, какие dll-ки она требует и где они должны быть (в GAC или в рабочей директории)
В общем, там было несколько проблем именно с настройкой. Сейчас как там не знаю, правда

VD>Возможно, по начлау полезным будет делать так. Если не понимаешь как реализовать что-то через рекуссию, паттерн-матчинг и т.п., то сначал написать все влоб как на Шарпе (эдаком C##), а потом подумать и постепенно переписать кода с использованием расширенных возможностей. Не грех бросить такой код сюда. Народ подскажет.


Дело в том, что я не понимаю, где нужно пользоваться сопоставлением с образцом тем же. Т.е. я ваш калькулятор бы не написал так, как вы просто потому что не подумал бы, что там вообще можно использовать сопоставление с образцом.
Т.е. с одной стороны, я мыслю ближе к ФП, но, с другой стороны, многие возможности я не знаю как и где применить. Нужны именно примеры приёмов программирования

А рекурсией я наоборот очень часто мыслю, приходится иногда даже переводить её потом в циклы Так что тут проблемы вряд ли будут


VD>Дык можно подглядеть рефлектором. К тому же я во водной статье как раз описывал семантику переписыания паттернов в if-ы. Прочитай еще раз эту статью
Автор(ы): Сергей Туленцев, Владислав Чистяков
Дата: 23.05.2006
Производительность труда программиста в основном зависит от самого программиста. Однако даже самый опытный и знающий программист мало что может без подходящего инструмента. Эта статья открывает цикл статей об одном из таких инструментов, еще мало известном среди программистов, но очень многообещающем. Язык Nemerle, о котором пойдет речь в этих статьях, на первый взгляд очень похож на слегка улучшенный C#, но привносит многое из передовых исследовательских языков. Данная статья рассказывает об отличиях Nemerle от C# (как наиболее близкого языка)и является неформальным введением в язык.
.


Ага, только там "with" нету. По поводу рефлектора что-то не дошло: действительно ведь можно
Re[4]: Пояснение
От: VladD2 Российская Империя www.nemerle.org
Дата: 21.05.07 15:18
Оценка:
Здравствуйте, FDSC, Вы писали:

VD>>А такой строки не было


FDS>Как это не было, когда была В самом листинге не было, а вот в пояснениях была...


Незнаю, я не нашел. Но все равно смысл тот же. Просто null обычно присваивается как значение по умолчанию. Бывает так, что у одного значения варианта есть некое поле, а у дрегого нет, но хочется их обработать как-будто такое поле есть у боих значений варианта. При этом значение — null устраивает. Вот и задается для того значения варианта где поля нет эдакое ложное значение. Это и есть ad-hok-полиморфизм, или полиморфизм по месту/требованию. Мы как бы забываем о реальном типе и хотим видеть его как некий новый абстрактный тип у которого есть нужные нам поля (а значит характеристики). Это то что делает паттерн-матчинг еще мощьнее.

Кстати, в инициализирующем выражении могут быть вычисления любой сложности. Там может быть и блок кода, и вызов функции. Это позволяет реализовывать довольно хитрые решения.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[5]: Пояснение
От: FDSC Россия consp11.github.io блог
Дата: 21.05.07 15:25
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Здравствуйте, FDSC, Вы писали:


VD>>>А такой строки не было


FDS>>Как это не было, когда была В самом листинге не было, а вот в пояснениях была...


VD>Незнаю, я не нашел.


Поиск в статье по строке "Более того, можно даже в одном из образцов связать переменную с независимым значением. Для этого используется конструкция with:"

VD> Но все равно смысл тот же. Просто null обычно присваивается как значение по умолчанию. Бывает так, что у одного значения варианта есть некое поле, а у дрегого нет, но хочется их обработать как-будто такое поле есть у боих значений варианта. При этом значение — null устраивает. Вот и задается для того значения варианта где поля нет эдакое ложное значение. Это и есть ad-hok-полиморфизм, или полиморфизм по месту/требованию. Мы как бы забываем о реальном типе и хотим видеть его как некий новый абстрактный тип у которого есть нужные нам поля (а значит характеристики). Это то что делает паттерн-матчинг еще мощьнее.


Спасибо, понял

VD>Кстати, в инициализирующем выражении могут быть вычисления любой сложности. Там может быть и блок кода, и вызов функции. Это позволяет реализовывать довольно хитрые решения.


Вот опять, в статье-то не написал. То есть по верхушкам прошёлся, но вроде, и не по всем верхушкам, но и не вглубь
Re: Функциональное программирование в Nemerle - замечания по
От: VladD2 Российская Империя www.nemerle.org
Дата: 21.05.07 21:32
Оценка:
Вынес в отдельную тему, чтобы оно не терялось в этом море флуда.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[6]: Пояснение
От: VladD2 Российская Империя www.nemerle.org
Дата: 21.05.07 21:32
Оценка: +1
Здравствуйте, FDSC, Вы писали:

FDS>Вот опять, в статье-то не написал. То есть по верхушкам прошёлся, но вроде, и не по всем верхушкам, но и не вглубь


Дык я не пытался создать инструкцию по применению паттерн-матчинга, и темболее, документацию по языку. Задача была другая — заинтересовать людей и возможно показать как надо мыслить, чтобы все это применять. Потому как без изменения мышления получаются вот такие "обсуждения" скатывающиеся на демогогию.

В общем, надо бы конечно статью доработать, с тем, чтобы затрагиваемые вопросы были объяснены доходчивее. Но превращать ее в очередной введение в язык, я считаю лишним.

Лучше потом сделать еще статью которую полностью посвятить расширенному изучению сопоставления с образцом.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.