Re[32]: «Собаку съел»
От: vdimas Россия  
Дата: 15.02.17 23:40
Оценка:
Здравствуйте, samius, Вы писали:

S>Мне кажется что я не могу за тебя подобрать определение, которым ты пользуешься, из источника, которому ты доверяешь.


Я никому не доверяю, только лишь своему пролетарскому чутью. ))

И ты никому не доверяй, особенно вот таким маленьким статьям по конкретным языкам, навроде Хаскеля, чьё сообщество на сегодня является наиболее консервативным из всех других "живых" сообществ.

Ну и тем более не доверяй Вики. ))

Я вот всё жду, когда вот эту опенсорсную книгу докончат:
https://hott.github.io/book/nightly/hott-online-1075-g3c53219.pdf
а потом переведут на русский.
Этой книге можно верить.
По всей этой теме она пишется наиболее тщательно во всей Истории IT как таковой.
Книгу пишет большая группа авторов.
Книга пишется на гитхабе.
Идет постоянный фидбэк.
Идут "ночные сборки", ревью, баги — всё как положено. ))

Кста, инициатор проекта и его ведущий — наш русский математик.

Согласно неё имеем:
— обычные типы (домен значений);
— "вселенные" типов (набор доменов);
— иерархию вселенных (по признаку включения/пересечения их элементов-доменов);
— функциональные типы (мап входного домена на выходной: A->B);
— зависимые функциональные типы (мап семейства функций + входного домена из некоторой вселенной на конкретную ф-ию; параметрически полиморфные ф-ии — это разновидность зависимых функциональных типов);
— производные типы (типы параметризуются типами);
— зависимые типы (типы параметризуются значениями);

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

В общем, я не думаю, что уже пора собирать и давать ссылки на различные классификации параметрического полиморфизма (я имел ввиду именно их). Я вообще не думаю, что это когда-либо стоить делать кроме как для удовлетворения некоторого любопытства и при обязательном умении посмотреть на всё малость "со стороны".

Конкретно у нас я увидел, что мы пока не можем отделить даже сам параметрический полиморфизм от других разновидностей полиморфизма. И конкретно ты тут не при чем. Я заглянул в Вики, почитал чуть "вглубь" — волосы встают дыбом. Тут на форуме встают еще чаще. ))

И да. Некоторые авторы в запале "прозрения" называют параметрический полиморфизм "истинным полиморфизмом".
В общем случае это не так. В общем случае речь идёт о "зависимом функциональном типе" (упомянут выше).
Усё. Остальное зависит от техник, частностей и т.д.

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

Итак, начинаем с упомянутой тобой не к ночи Вики:

В языках программирования и теории типов полиморфизмом называется способность функции обрабатывать данные разных типов.

Существует несколько разновидностей полиморфизма. Две наиболее различных из них: это ad hoc полиморфизм и параметрический полиморфизм.

Параметрический полиморфизм подразумевает исполнение одного и того же кода для всех допустимых типов аргументов, тогда как ad hoc полиморфизм подразумевает исполнение потенциально разного кода для каждого типа или подтипа аргумента.

Запомним это определение. Оно верное до тех пор, пока "исполнение" будет означать "исполнение по исходнику", а не по машинным кодам. Где-то я даже встречал "физическое исполнение" и тоже ужасался. )) В книге по ссылке говорится:

A polymorphic function is one which takes a type as one of its arguments, and then acts on elements of that type.

Заметь, и параметрический и ad hoc-полиморфизмы прекрасно подходят под определение.

В первом случае мы напишем единственное тело ф-ии, которое сможет обслуживать, допустим, все типы из данной вселенной.
Во втором случае мы для одной и той же ф-ии напишем несколько версий тел — под разные типы из данной вселенной (или их семейства — подвселенных).

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

Вот тебе совместная работа параметрического полиморфизма и ad hoc.
Но и это не единственный сценарий их взаимодействия.
Идем далее.

А далее вики безбожно противоречит самой себе:

Определение полиморфизма как «один интерфейс — много реализаций», популяризованное Бьерном Страуструпом, относится к ad hoc полиморфизму.
...
Параметрический полиморфизм и динамическая типизация намного существеннее, чем ad hoc полиморфизм, повышают коэффициент повторного использования кода, поскольку определенная единственный раз функция реализует без дублирования заданное поведение для бесконечного множества вновь определяемых типов, удовлетворяющих требуемым в функции условиям.
...
Подтипизация (subtyping), или полиморфизм подтипов (subtype polymorphism), означает, что поведение параметрически полиморфной функции ограничивается множеством типов, ограниченных в иерархию «супертип — подтип».

(Например, если имеются типы Number, Rational и Integer, ограниченные отношениями Number :> Rational и Number :> Integer, то функция, определённая на типе Number, также сможет принять на вход аргументы типов Integer или Rational, и её поведение будет идентичным.)

Кошмар, не правда ли? ))
Ладно бы это были выдержки из разных страниц, но эти противоречивые утверждения я собрал с одной страницы.

Вот почему я не очень люблю давать ссылки и практически никогда их не прошу. Я обычно просто благодарен за новую инфу и сам стараюсь подкидывать просто "чистую инфу". Кому интересно — тот осилит. Потому что Интернет не "не может ошибаться", а ровно наоборот — Интернет почти всегда врёт. Каждый раз брать на себя ответственность за это...

ОК. Берем один из моих примеров выше, заворачиваем в объявление ф-ии:
static class Extensions {
    void Draw(this IEnumerable<Widget> widgets, Context context) {
        foreach(var w in widgets)
            w.Draw(context);
    } 
}

Получаем параметрически полиморфный метод Extensions.Draw, который принимает на вход список полиморфных объектов.

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

Идём далее.
В современном программировании принято такие ф-ии объединять в некую сугубо прикладную группу — в классы/интерфейсы/концепты.

Исходно же, исторически, "параметрический полиморфизм" означал программирование в т.н. "черных ящиках". Как пример можно привести любой динамически-типизированный функциональный язык (раньше были модные).

Далее — у нас есть две основные разновидности такого "ящика":

  • "Типизированный ящик" или т.н. "концепт" — список операций над ящиком задан "заранее".

  • "Нетипизированный ящик" — список операций получается "по факту".

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

    Если же в последнем случае типизация происходит в компайлтайм (т.е. статическая типизация), тогда все "черные ящики" должны быть "выведены" компилятором до монотипов или до других "типизированных концептов". Так работает компилятор С++.

    Именно поэтому мы имеем в С++ статическую типизацию на "нетипизированных черных ящиках" и динамическую типизацию на "типизированных концептах" — т.е. абстрактных/виртуальных методах.
    (тут надо остановиться и попытаться переварить, ы-ы-ы)

    Далее. Т.н. "структурный полиморфизм".
    Доступен частично в стандартном Хаскеле — в языке доступна лишь "открытая" структура типов, этой структурой можно оперировать даже тогда, когда элементами структуры является неизвестный тип (вселенная всех типов или некая подвселенная).

    И совсем хорошо "структурный полиморфизм" доступен в диалекте GHC. Они там ввели "семейства типов" (крайне неудачное наименование, сбивающее с толку, но в терминах Хаскеля теперь придётся юзать).

    И точно так же, как в случае классов типов, можно задавать как ad hoc специализации хаскелевских "семейств типов", так и "ограничения" на структуру полиморфных типов (такое ограничение образует собсно "семейство" в терминах Хаскеля, как ограничение на список ф-ий образовывало "класс").

    Любая специализация некоего "семейства" переопределяет "структуру" типа (т.е. конструкцию данных).
    И опять твой викиучебник по Хаскелю пишет:

    Indexed type families, or type families for short, are a Haskell extension supporting ad-hoc overloading of data types.

    Предлагаю здесь опять сделать паузу и напрячь внимание.

    Потому что чаще всего "семейства типов" определяют в виде "ограничений" не для того, чтобы рядом нарисовать конкурирующее определение для ad hoc, а с целью дать "известную структуру" неизвестному типу. Т.е., представь, что помимо "интерфейсов-ограничений" в дотнете можно было бы указывать "структуры-ограничения" и обращаться к публичным полям типа в теле генерик-методов.

    Возвращаясь к нашим баранам — в С++ структурный полиморфизм доступен: в шаблонах можно обращаться к полям типов. Но этот полиморфизм в C++ тоже идёт не типизированный "изкаробки". (Хотя, есть сразу несколько техник приведения его к типизированному. Например, через т.н. "селекторы" можно сводить структурный полиморфизм к полиморфизму над "концептом", а как последний сделать типизированным в реалиях С++ — уже описывал ранее.)

    ============
    Далее будет совсем смешно (из той же статьи):

    Наследование в С++ реализуется набором ad hoc-механизмов, однако, его использование называется в сообществе языка «полиморфизмом», а сокрытие полей — «абстракцией».

    Каких еще в опу "наборов ad hoc-механизмов"??? Что за потёки сознания? ))
    ad hoc механизм — он один, нет никаких его "наборов".

    И откуда взялось про "в сообществе языка"? У кого там так подгорает-то? ))
    И почему "абстракцией" было названо только лишь сокрытие полей, да еще в обвинительном тоне?
    Прикол, да?
    Принципы абстрагирования родились в IT за пол века до первой версии языка С, не то, что даже С++.

    И уж инкапсуляцию тоже не в С++ придумали как средство абстрагирования.

    Однако, автор на голубом глазу путает "абстрагирование" как способ проектирования публичных интерфейсов (сокрытие частностей), от абстрагирования на уровне системы типов, когда нам такое абстрагирование нужно сугубо для повторного использования кода (чаще всего абстрагирование от конкретного типа за этим и нужно).

    В IT оба этих понятия вокруг одного слова "абстракция" довольно четко отделены уже давно, более 70-ти лет (конец 50-х, начало 60-х 20-го века), но поди ж ты!

    К тому же, любой современный студент знает, что сокрытие полей называется чаще "инкапсуляцией". А когда говорят об "абстракции", то чаще имеют ввиду полиморфизм.


    S>С другой стороны, я не ковырял по узкоспециализированнымм инженерным источникам.


    Ну а я ковырял одно время, пытаясь почерпнуть "знания", угу.
    Был весьма обескуражен вначале, а потом разозлён из-за потраченного времени.

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


    S>Вот я копнул, ты копнул — у нас разногласия.


    Ну, у нас возникли совсем уж серьезные разногласия — что есть ad hoc.
    И потребовалось несколько итераций, чтобы ты начал приводить свои источники и я попытался понять, почему ты эти источники понял именно так.

    В общем, тут рассуждения простые. "Поли-" — это много, "морфизм" — приспособляемость (формы — "морфы").

    В случае ad hoc полиморфизма у нас должно быть много подходящих под разные типы (или их групп) определений, а в случае параметрического полиморфизма у нас должно быть такое определение, которое умеет работать на множестве типов.


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


    Что значит "указанно избыточно"?
    В смысле, не используется явно в коде ф-ии?
    Но иногда и не надо, ведь есть много "трюков" — например, для конкретного ограничения можно применить некую специфическую логику.
    Суть трюка состоит в том, что мы переносим константы (т.е. некие данные, которые неизменны в течении работы программы) в систему типов, избавляясь от if в теле ф-ий, эксплуатируя имеющуюся систему типов используемого языка, чтобы диспетчеризация происходила "сама".


    S>Хрен с ним с рангом. Давай сначала с ad-hoc-ом разберемся.


    Еще не разобрались? ))


    V>>Отвечу: ad hoc — это наличие конкурирующих специализаций. Это ВЕСЬ мой ответ.

    S>Поверхности у всех разные. На моей поверхности elem и lookup ad-hoc полиморфны. На твоей — я так и не понял из ВСЕГО твоего ответа.

    ОК.
    Оба elem и lookup параметрически полиморфны прямо по определению параметрического полиморфизма. На обе эти ф-ии можно подать аргументы несчетного кол-ва типов. Главное, чтобы такой тип принадлежал вселенной Eq ("классу типов" в терминах Хаскеля).

    Если ты напишешь более одной перегрузки каждой из этих ф-ий, то мн-во этих перегрузок по каждой ф-ии будут составлять ad hoc полиморфизм.


    S>Я тут копчу лишь за то, что компараторы, использующие "натуральные" сравнения ad-hoc полиморфны.


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


    S>как и все, что их прямо или косвенно использует. Исключая ФВП, которые используют ad-hoc постольку-поскольку им их явно передали.


    Э, нет. Это параметрический полиморфизм распространяется "вверх", т.е. тип, производный от полиморфного, тоже будет полиморфным (например, список полиморфных переменных). В противоположность ему, ad hoc применяется только в конкретном месте, и не распространяется ни вверх, ни вниз. Это просто выбор "по-месту" некоей перегрузки (специализации) из множества их.
  •  
    Подождите ...
    Wait...
    Пока на собственное сообщение не было ответов, его можно удалить.