LINUX.ORG.RU

5-й номер журнала «Практика функционального программирования»

 , , , , , ,


0

0

Вышел новый, пятый номер журнала «Практика функционального программирования». В новом номере опубликованы следующие статьи:

  • Инструменты интроспекции в Erlang/OTP. Максим Трескин
  • Экономия ошибок. С. Зефиров, А. Сафронов, В. Шабанов, Е. Мельников
  • Введение в F#. Евгений Лазин, Максим Моисеев, Давид Сорокин
  • Лисп — философия разработки. Всеволод Дёмкин, Александр Манзюк
  • Оптимизирующие парсер-комбинаторы. Дмитрий Попов
  • Модель типизации Хиндли — Милнера и пример её реализации на языке Haskell. Роман Душкин

Также в этом номере опубликованы результаты конкурса, который был объявлен в 3-м номере журнала.

>>> Подробности

★★★★★

Проверено: maxcom ()
Ответ на: комментарий от ed

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

Что бы генерировать гарантировано type-безопасный кода надо иметь систему верификации либо кода, либо генератора. и вот тут выкопана яма. Поскольку изкаробочного или признаноого верификатора, системы алгебры (именно алгебры кода, а не вобще математики) нету то и этот самый код/генератор проверяется по use-case-ам, а не доказывается его корректность для входных условий. Поэтому как правило генерируют очевидный код, но не гарантировано типобезапасный. Другой вопрос что частично функцию верификатора выполняет сам sbcl и это сильно спасает.

Т.е впомнив код на лиспе из ПФП можно сказать можем написать быстрый и рабочий код, но его верификация вопрос уже другой и мутный. И совсем интересно как такой eDSL будет выглядеть на фоне остально кода. То есть понятно что можно обернуть часть кода декларацией входных параметров, а остальное внутри заоптимизирует компилятор или следуя его ругательным советам начнем декларировать узкие места. Но все же интересно как такой eDSL выглядит.

P.S. Использующие лисп (CL по крайней мере) практически никогда не поминают DSL, согласно моему скромному конечно.

antares0 ★★★★
()
Ответ на: комментарий от antares0

Качественные теоритизации несомненно дело хорошое и повышают настроение, однако Я ничего не говорил про доказанность и формальную верификацию. Так как был интересен код, поясню свои формулировки на примере знакомого, но не сильно полезного pascal-like e(притянем DS)L:

(define-pascal-procedure ppp ((a b :integer) (dd (:ptr :real)))
  :var
    (sss :string)
  :begin
     (:= sss (lisp-call (lisp-implementation-version) :string))
     (another-pascal-ppp a b dd)
     ; …
  :end)

процедуры/функции нашего псевдоязыка можно вызывать друг из друга, связь с лиспом через pascal-call и lisp-call (с явным указанием типа результата)

реализовать можно разными способами, самый простой - отобразить на лисп без каких либо проверок (выходные декларации типов тут пусть будут не принципиальны, ведь не одним sbcl-ем ..), в случае валидной псевдопрограммы все будет хорошо, иначе в зависимости от ошибки — компилтайм error, рунтайм type error или вообще undefined behavior. Что в этом способе хорошо - это простота, однако цена ошибки … Так как даже отдельную фазу валидации псевдопрограммы делать лень, просто дополним наш «отображатель» простым в нашем случае type-tracker-ом, остальное есть в самом лиспе. Получается эдакая верификация (в общем смысле) type-совместимости деятельности «отображателя», для данной подпрограммы. Под гарантированной type-безопасностью подразумевается то что мы можем вызвать функцию pascal->pascal без рунтайм проверок типов аргументов, в отличии от lisp->pascal. Работоспособность этого всего естественно зависит только от прямых рук разработчика «отображателя», подход далеко не общий, но весьма практический.

кстати, в той-же задаче :private/:protected/:public в лиспе тоже есть забавный кусок — сама интеграция «в язык», естественно там есть не один вариант, однако какое направление выберете вы ?

P.S. Использующие лисп (CL по крайней мере) практически никогда не поминают DSL, согласно моему скромному конечно.

По моему скромному, мнение нужно аргументировать — моя позиция по DSL-ам тут Вышел новый релиз реализации языка Common Lisp - Clozure CL 1.5 (комментарий) и далее, жду конструктив.

ed ★★
()
Ответ на: комментарий от ed

> я говорил о компилтайм верифицируемом eDSL-е, генерирующем гарантировано type-безопасный код

однако Я ничего не говорил про доказанность и формальную верификацию.

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

просто дополним наш <<отображатель>> простым в нашем случае type-tracker-ом, остальное есть в самом лиспе. Получается эдакая верификация (в общем смысле) type-совместимости деятельности <<отображателя>>, для данной подпрограммы.

Чем дальше в лес тем непонятнее. Давайте с вашей помощью попробуем раскрыть type-tracker и посмотреть что он делает. Что забавно, гугл на запрос '«type-tracker» lisp' выдает перврой ссылкой именно этот пост.

Под гарантированной type-безопасностью подразумевается то что мы можем вызвать функцию pascal->pascal без рунтайм проверок типов аргументов, в отличии от lisp->pascal.

Два раза прочитал все равно не понял.

antares0 ★★★★
()
Ответ на: комментарий от antares0

Я обозвал именно гарантией так, как подразумевал что мы не зависим от компилтайм type проверок и их полноты в конкретной реализации CL, но не суть важно. А type-tracker-ом, я это только в этом топике обозвал, возможно есть более научная формулировка. Можно его показать на примере перехода от простого «отображения», к отображению с отслеживанием:

простой вариант:

(define-pascal->lisp-transformation (:= var expr)
  `(setf ,var ,(pascal->lisp-transform expr))

(define-pascal->lisp-transformation (:+ a b)
  `(+ ,(pascal->lisp-transform a) ,(pascal->lisp-transform a)))

немного сложнее с «отслеживанием типов»:

(define-pascal->lisp-transformation (:= var expr)
  (bind (((:values expr-code expr-type) (pascal->lisp-transform expr)))
    (ensure-pascal-subtypep  expr-type (pascal-variable-type var))
    (values `(setf ,var ,expr-code) nil)))

(define-pascal->lisp-transformation (:+ a b)
  (bind (((:values a-code a-type) (pascal->lisp-transform a))
             ((:values b-code b-type) (pascal->lisp-transform b))
	 (result-type (match-type-rules +base-math-type-rules+ a-type b-type)))
    (values `(+ ,a-code ,b-code) result-type)))

подход не универсален как я и говорил, а в зависимости от усложнения системы типов eDSL — разница между этими вариантами будет расти, однако на мой взгляд на «практических» eDSL, более декларативных, конструкций будет меньше, а проверки хитрее, в зависимости от предметной области конечно.

Под гарантированной type-безопасностью подразумевается то что мы можем вызвать функцию pascal->pascal без рунтайм проверок типов аргументов, в отличии от lisp->pascal.

Я имел ввиду, что наша процедура ppp преобразуется в упрощенном варианте в что-то типа:

(defun ppp-internal (a b dd)
  ; транслированный код полагающийся на корректность типов аргументов  ...
  )

(defun ppp-external (a b dd)
  (check-type a fixnum)
  (check-type b fixnum)
  (check-pascal-pointer-type dd float)
  (ppp-internal a b dd))

pascal->pascal → call internal - за счет компилтайм отслеживания, lisp->pascal → call external

ed ★★
()
Ответ на: комментарий от ed

местный colorer/formatter немного не справился :(

ed ★★
()
Ответ на: комментарий от archimag

> Завязывал бы с этой наркотой, вредно для здоровья.
может не стоит опускаться до уровня некоторых анонимусов ?, хотя задетое ЧСВ долго заживает ...

ed ★★
()
Ответ на: комментарий от ed

> может не стоит опускаться до уровня некоторых анонимусов ?

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

хотя задетое ЧСВ долго заживает


Не беспокойся, моей самооценке ничего не угрожает лет этак с шести ;)

archimag ★★★
()
Ответ на: комментарий от archimag

> Ну, подобные обороты вот и Линус использует, а он вроде не анонимус ;)
только с Ханса Райзера пример не бери а ...

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

раз уж тебе не все понятно, то так отвечать на адресованный не тебе пост - как минимум странно

Не беспокойся, моей самооценке ничего не угрожает лет этак с шести ;)

ага, тогда зачем косить под финских дядек ?)

ed ★★
()
Ответ на: комментарий от ed
(define-pascal->lisp-transformation (:= var expr)
  (bind (((:values expr-code expr-type) (pascal->lisp-transform expr)))
    (ensure-pascal-subtypep  expr-type (pascal-variable-type var))
     (values `(setf ,var ,expr-code) nil)))

(define-pascal->lisp-transformation (:+ a b)
  (bind (((:values a-code a-type) (pascal->lisp-transform a))
             ((:values b-code b-type) (pascal->lisp-transform b))
    (result-type (match-type-rules +base-math-type-rules+ a-type b-type)))
    (values `(+ ,a-code ,b-code) result-type)))

В этом коде работу type-tracker-а не видно. Видимо он прчется ensure--pascal-subtype и match-type-rules на них тоже стоит посмотреть.

Про задачу и и аргументы помню, но попозже.

antares0 ★★★★
()
Ответ на: комментарий от antares0

в двух словах:
ensure-pascal-subtypep - аналог subtypep, но кидает error если нет
match-type-rules - ищет по своим аргументам в списке с элементами вида (type1 ... typen . result-type), если не нашел - error

ed ★★
()
Ответ на: комментарий от lester

я очень хочу посмотреть на более-менее реальный пример с вводом-выводом и обработкой данных (а не пример функции, вычисляющей числа фабиначи) на «чистом» ФЯП. кто-нибудь, сварганьте, плиз, ищущие дзена быдлокодеры (как я) были бы очень благодарны.

можно в исходную задачу добавить какие-нибудь нюансы, которые бы могли показать выгодность ФЯП, но без фанатизма (чтобы задача оставалась реалистичной).

либо дайте ссылку на такой готовый пример, только не слишком объёмный :).

boo32
()
Ответ на: комментарий от boo32

Несколько странно спрашивать об организации ввода-вывода в сферически-чистых ЯП в уже почти угасшем лиспосраче. Я конечно к ФЯП кроме лиспа имею отдаленоое отношение. Вспоминаются введение к фуджетам. Читать по порядку для понимания. Есть еще глава про IO в Real World Haskell. Но код работы с файлами в первой половине там реально почти туп и haskell позорит. Не знаю уж, то ли для прстоты изложения, то ли просто все так грустно. Вобще в ФП по-моему принято выделять вход и выход процесса IO и кобинацию действий между ними. Ну и разделение действий и чистых функций для чистого ФП.

antares0 ★★★★
()
Ответ на: комментарий от antares0

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

boo32
()

Тогда я вобще не понимаю что такое «конкретная реализация IO». Сходить посмотреь исходники в hackage?

antares0 ★★★★
()
Ответ на: комментарий от boo32

> пусть будет не чистый ФЯП в тех местах, где функции имеют побочные эффекты. главный интерес примера - в практичности.
очень подозреваю что на самом деле хотелось увидеть что то подобное:
http://www.erlang.org/examples/examples-2.0.html

ed ★★
()
Ответ на: комментарий от antares0

> Тогда я вобще не понимаю что такое «конкретная реализация IO»

нет, меня НЕ интересовала конкретно реализация IO

boo32
()
Ответ на: комментарий от antares0

>> невозможность после этого в рантайме поменять класс объекта так, что методы исчезнут

а методы не исчезнут они определяюся НА классах а не в них, за исключение методов определяемых при инициализации класоов (accessor-ы например).

еще раз озвучу задачу:

надо создать коллекцию (вовсе не обязательно массив), в которую клались бы только объекты, на классе которых определена функция f

при этом не должно быть возможности поменять класс элемента коллекции так, что в результате f стала на этом элементе не определена

www_linux_org_ru ★★★★★
()
Ответ на: комментарий от antares0

> Если же двинутся дальше в MOP то можно контролировать изменения класса, например для db-классов можно контролировать соответсвие схеме БД и в случае разногласий запросить помощи у програмиста предоставив возможные варианты решения в виде рестартов.

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

ты где обычно тусуешься, чтобы пофлеймить на тему MOP? в ЖЖ там или где?

www_linux_org_ru ★★★★★
()
Ответ на: комментарий от www_linux_org_ru

> надо создать коллекцию (вовсе не обязательно массив), в которую клались бы только объекты, на классе которых определена функция f

а практическое значение есть у этой задачи?

boo32
()
Ответ на: комментарий от boo32

> да, похоже. ещё, ещё :).
это не так просто, остальное либо на самом деле мультипарадигменное (common lisp, ocaml, F#), либо скорее с академическим уклоном

ed ★★
()
Ответ на: комментарий от boo32

> а практическое значение есть у этой задачи?

ну ты задал вопрос...

есть — ООП «вышло в люди» именно из-за того, что ООП эту задачу решает

www_linux_org_ru ★★★★★
()
Ответ на: комментарий от boo32

> а практическое значение есть у этой задачи?

ну ты задал вопрос...

есть — ООП «вышло в люди» именно из-за того, что ООП эту задачу решает

www_linux_org_ru ★★★★★
()
Ответ на: комментарий от www_linux_org_ru

> > надо создать коллекцию (вовсе не обязательно массив), в которую клались бы только объекты, на классе которых определена функция f

есть — ООП «вышло в люди» именно из-за того, что ООП эту задачу решает

Ого, а поподробнее?

paranonymous
()
Ответ на: комментарий от www_linux_org_ru

эту задачу решает интроспекция + дактайпинг, а не ООП как таковой. ООП решает только задачу декомпозиции исходной задачи (не смог решить тавтологию) на объекты.

boo32
()
Ответ на: комментарий от boo32

> эту задачу решает интроспекция + дактайпинг

Без статической типизации эту задачу сделать крайне сложно, ибо в большинстве динамических языков есть возможность в рантайме поменять все и вся, и никаких гарантий получить нельзя. Ну и каким боком эта задача к ООП, мне тоже крайне инетересно было бы узнать.

paranonymous
()
Ответ на: комментарий от paranonymous

> Без статической типизации эту задачу сделать крайне сложно, ибо в большинстве динамических языков есть возможность в рантайме поменять все и вся, и никаких гарантий получить нельзя. Ну и каким боком эта задача к ООП, мне тоже крайне инетересно было бы узнать.

формально ты прав — это статика, а не ООП, но фактически ООП применяется именно для того, чтобы идти по массиву из абстрактного класса и дергать конкретные реализации метода; возможность неожиданно получить тут исключение «нет метода» или получить метод с тем же названием, но совсем другим предназначением нам не к чему

www_linux_org_ru ★★★★★
()
Ответ на: комментарий от www_linux_org_ru

> фактически ООП применяется именно для того, чтобы идти по массиву из абстрактного класса и дергать конкретные реализации метода; возможность неожиданно получить тут исключение «нет метода» или получить метод с тем же названием, но совсем другим предназначением нам не к чему

Пусть и так, но в динамических языках, как показывает практика, ошибки method not implemented встречаются так же редко, как и, например, попытки сложить апельсины с коровами, т.е. есть подозрение, что ты пытаешься решить те проблемы, которых при правильном подходе вообще нет (с).

paranonymous
()
Ответ на: комментарий от paranonymous

> Пусть и так, но в динамических языках, как показывает практика, ошибки method not implemented встречаются так же редко, как и, например, попытки сложить апельсины с коровами, т.е. есть подозрение, что ты пытаешься решить те проблемы, которых при правильном подходе вообще нет (с).

Их, «попыток сложить апельсины с коровами», вообще нет там, где это не дает компилятор (т.е. при правильном подходе). И это факт.

А то, что «ошибки method not implemented встречаются так же редко» — это домыслы. Или у тебя есть ссылка на исследование, где считали эту частоту? Включая отладку?

Ну и ты упустил случай 2 — method хотя и implemented, но предназначался *совсем* для другого, например (классика) метод draw() у всех фигур их рисует, а у ковбоя заставляет вытащить пистолет из кобуры.

www_linux_org_ru ★★★★★
()
Ответ на: комментарий от paranonymous

а есть еще случай 3

у кольцевого списка и разокнутого списка имеется метод next(), так вот, у одного из них он должен использоваться в виде

item=start_item; 
while(1) {
   /// do somethig
   item=item.next()
   if(item == start_item ) break;
}

а у другого в виде

item=start_item
while(1) {
   /// do somethig
   item=item.next();
   if( item != NULL ) break;
}

разница есть?

что будет, если мы в одну коллекцию положим как замкнутые, так и разомкнутые списки, и начнем колбасить их одним (параметрически полиморфным) кодом, который понимает только наличие у списка next()?

www_linux_org_ru ★★★★★
()
Ответ на: комментарий от www_linux_org_ru

поторопился; вот код

item=start_item;  
while(1) { 
   /// do somethig 
   item=item->next(); 
   if(item == start_item ) break; 
}

а у другого в виде

item=start_item;
while(1) { 
   /// do somethig 
   item=item->next(); 
   if( item == NULL ) break; 
}
www_linux_org_ru ★★★★★
()
Ответ на: комментарий от www_linux_org_ru

В правильных библиотеках

item=start_item;
while(1) {
    /// do somethig
    item=item->next();
    if( item == end() ) break;
}
:)

ЗЫ а в ещё более правильных библиотеках и языках должен быть for_each

ЗЗЫ топик оказывается от анонимов закрыт. Зачем?..

legolegs ★★★★★
()
Ответ на: комментарий от www_linux_org_ru

> ты где обычно тусуешься, чтобы пофлеймить на тему MOP? в ЖЖ там или где?

Тусуюсь на LOR-е, lisper.ru, sql.ru, rsdn. ЖЖ читаю от случая к случаю, комментирую и того реже. В жж короче не звать.

Я как правило отвечую на вопросы (даже если они не мне адресованы :)) и правлю ляпы. т.е. на вопрос прозвучавший что дает MOP отвечу, но флейм с+ruby vs |lisp в вакуме| мне скучен и комментировать лень. Опять же надо понимать что я не гуру в четвертом поколении пишущий 5 языков в неделю а DSL вобще как горох без счета, просто третий год с лиспом дает о себе знать. Можно и новую тему завести если уж к делу подходить серьезно. Вобще вопросы небесмысленные и попробую в рабочем порядке ответить.

Все хочу тему про :private :protected раскрыть в статью,н оруки не доходят пока.

Остально откоментирую в ближайшем светлом будущем когда высплюсь. Выходной.

antares0 ★★★★
()
Ответ на: комментарий от legolegs

> if( item == end() ) break;

не понял — как этот end() догадается выдавать start_item, которым может быть любой элемент списка (а именно тот, с которого мы начали обход)?

ЗЫ а в ещё более правильных библиотеках и языках должен быть for_each

вообще да, но может мне надо деструктивный там foreach и вообще примеров можно придумать еще

ЗЗЫ топик оказывается от анонимов закрыт. Зачем?..

макском писал, что начиная с 1000 автоматически закрывается, так что надо скорее не поздравлять с 1000, а некролог по анонимусу постить

www_linux_org_ru ★★★★★
()
Ответ на: комментарий от www_linux_org_ru

>не понял — как этот end() догадается

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

так что надо скорее не поздравлять с 1000, а некролог по анонимусу постить

Кстати, WВИМ.

legolegs ★★★★★
()
Ответ на: комментарий от www_linux_org_ru

> но предназначался *совсем* для другого, например (классика) метод draw() у всех фигур их рисует и ПРОЧИЕ.
слушай, ну прочитай же уже наконец Practical Common Lisp

ed ★★
()
Ответ на: комментарий от antares0

> Все хочу тему про :private :protected раскрыть в статью,н оруки не доходят пока.
статья это конечно хорошо, будем с нетерпением ждать
только вот с суждением о понимании DSL неувязочка, если вы его сделали, то вероятно у вас была уже сформированная на этот счет позиция, и в таком случае раскрыть непонимание собеседника дело 3-5 минут и предложений, и по моему, с тех пор, вы здесь уже не меньше написали

ed ★★
()
Ответ на: комментарий от www_linux_org_ru

> А то, что «ошибки method not implemented встречаются так же редко» — это домыслы. Или у тебя есть ссылка на исследование, где считали эту частоту? Включая отладку?

Я оцениваю по своему опыту использования динамических языков и по реальным проектам - я очень мало видел более или менее серьезных проектов, у которых в багтрекере висела ошибка типа method not implemented или AttributeError. Такие ошибки, как правило, быстро находятся, и также быстро исправляются.

Ну и ты упустил случай 2 — method хотя и implemented, но предназначался *совсем* для другого, например (классика) метод draw() у всех фигур их рисует, а у ковбоя заставляет вытащить пистолет из кобуры.

Приведи реальный код, пожалуйста. Обычно, в языкеах с multiple inheritance, traits, mixins, interfaces и прочее, четко оговорено, какой метод вызывается в случае, если у его предков есть методы с одинаковыми именами.

paranonymous
()
Ответ на: комментарий от www_linux_org_ru

> что будет, если мы в одну коллекцию положим как замкнутые, так и разомкнутые списки, и начнем колбасить их одним (параметрически полиморфным) кодом, который понимает только наличие у списка next()?

Так в чем проблема? Неправильно использовать метод можно всегда. Здесь спокойно делается map_list, специфичный для каждого типа списков, и он используется в коде вместо next().

paranonymous
()
Ответ на: комментарий от www_linux_org_ru

> вообще да, но может мне надо деструктивный там foreach и вообще примеров можно придумать еще

Пишешь для каждого типа списков отдельную полиморфную функцию, по-другому, судя по всему, никак.

paranonymous
()
Ответ на: комментарий от paranonymous

>> ... Включая отладку?

Я оцениваю по своему опыту использования динамических языков и по реальным проектам - я очень мало видел более или менее серьезных проектов, у которых в багтрекере висела ошибка типа method not implemented или AttributeError.

Еще раз: Включая отладку.

Судя по моему опыту — у меня при написании нового кода и серьезной модификации старого компилятор *обязательно* завопит о куче случаев, которые бы в динамическом языке вылились в method not implemented или AttributeError.

Приведи реальный код, пожалуйста. Обычно, в языкеах с multiple inheritance, traits, mixins, interfaces и прочее, четко оговорено, какой метод вызывается в случае, если у его предков есть методы с одинаковыми именами.

Имелось в виду то, что мы в массив с фигурами положили еще и ковбоя; дальше прошлись по массиву, вызывая метод draw(), и удивились. (хотя да, *это* не классика)

www_linux_org_ru ★★★★★
()
Ответ на: комментарий от paranonymous

> Так в чем проблема? Неправильно использовать метод можно всегда.

А вот и нет.

В нормальных языках нет структурной эквивалентности типов или утиной типизации, или по крайней мере ее можно запретить.

Тогда эти два типа данных — замкнутый и разомкнутый списки — будут разными типами, но попытка вызвать функцию для обработки одного из них на другом будет отвергнута компилятором.

www_linux_org_ru ★★★★★
()
Ответ на: комментарий от ed

> статья это конечно хорошо, будем с нетерпением ждать только вот с суждением о понимании DSL неувязочка, если вы его сделали, то вероятно у вас была уже сформированная на этот счет позиция, и в таком случае раскрыть непонимание собеседника дело 3-5 минут и предложений, и по моему, с тех пор, вы здесь уже не меньше написали

ты в своих постах на тему DSL написал кучу кода, но не дал объяснений своей идее — такие вещи трудно понимать

www_linux_org_ru ★★★★★
()
Ответ на: комментарий от legolegs

>> не понял — как этот end() догадается

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

не понял, где у дерева последний узел :-) ну и хрен с ним

я говорил, что структурная эквивалентность и утиная типизация (в т.ч. в шаблонах с++ :-) есть плохо, и end() тут тебя не спасет

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

если бы в сигнатуру next() входил предикат, то уже можно было бы жить; за неимением предиката можно написать так:

class CircularListItem { ... AlwaysNonNullPtr<CircularListItem> next(); ... }

class FlatListItem { ... FlatListItem* next(); ... }

с предикатом (@аннотация, как в яве):

class CircularListItem { ... @always_non_null CircularListItem* next(); ... }

class FlatListItem { ... FlatListItem* next(); ... }

www_linux_org_ru ★★★★★
()
Ответ на: комментарий от www_linux_org_ru

> не надо отвечать на те вопросы, которые я не спрашивал
как не спрашивал ? а «идентификация» методов и их связь с типами в CL - почитай и сам поймешь, что там нет тех проблем которые сейчас тебе кажутся фатальными, у PCL даже перевод уже есть

ты в своих постах на тему DSL написал кучу кода, но не дал объяснений своей идее — такие вещи трудно понимать

я про другое, это было еще до кода

ed ★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.