Здравствуйте, samius, Вы писали:
_>>Параметрический полиморфизм — это механизм, позволяющий обрабатывать значения разных типов с помощью одного и того же программного кода. S>Вот видишь, именно из твоего определения (сам придумал, или все-таки укажешь источник?) как раз и следует что перегрузка функций — параметрический полиморфизм, ибо найдется более одного типа, которые можно обработать одним и тем же кодом (вызывающим перегрузку).
Это каким этом образом перегрузка функций является одним и тем же кодом? При перегрузке у тебя как раз получается несколько версий функции в исходнике. Продемонстрируй пример своего тезиса)
_>>Т.е. я правильно тебя понял, что возможность написать в Хаскеле функцию вида "f a = xrmbrm a" является проявлением ad hoc полиморфизма? ))) S>Это зависит от определения функции xrmbrm. Если она параметрически полиморфна, то тем же свойством будет обладать "алиас". Если она выдвигает требования к аргументу (инстанс класса), то ad hoc. А уж если она определена мономорфо — то соответственно f будет мономорфна.
Хыхы, похоже ты совсем не представляешь, как это всё работает. Но чтобы это явно продемонстрировать потребуется немного другой пример, тем более, что мы уж давно ушли от обсуждения того несчастного компаратора и перешли к принципиальным вопросам о сути шаблонов C++ и полиморфизма Хаскеля.
И так возьмём такую простейшую функцию на Хаскеле:
apply f x = f x
и скомпилируем её в отдельный бинарный модуль (ну чтобы точно не было никаких иллюзий). А затем попробуем выполнить следующий тестовый примерчик (использующий только этот модуль):
f x = x + 1
apply f 1 -- вернёт 2
apply f 1.0 -- вернёт 2.0
apply f "1"-- компилятор пошлёт очень далеко
Ну и соответственно будет очень интересно послушать твои мысли на счёт того, какой полиморфизм реализует функция apply и как это всё работает.
А после этого твоего ответа рассмотрим такой код на C++:
auto apply=[](auto f, auto x) {return f(x);};
//...auto f=[](auto x) {return x+1;};
apply(f, 1); // вернёт 2
apply(f, 1.0); // вернёт 2.0
apply(f, "1"s); // компилятор пошлёт очень далеко
И соответственно будет интересно услышать от тебя какая разница у этого кода с примером на Хаскеле. И на уровне исходных кодов и на уровне машинных.
Да, и уже не совсем по теме. Так же было бы забавно увидеть вариант этого примера на Java/C# — там же у нас тоже вроде как есть подобие полиморфизма, не так ли? )))
S>>>Потому и заявляю, что equals_to — ad hoc, т.к. требует специализации чуть ли не для всех типов. _>>Ну давай, расскажи, зачем может понадобиться специализация equals_to. S>Ну я не думаю что для тебя это будет откровением. Например, для того, что бы использовать алгоритмы, нуждающиеся в binary_function для типов, у которых нет оператора сравнения и нет возможности определить его.
Это каким образом может не быть возможности определить его?
S>Или для того, что бы использовать способ сравнения типов отличный, от штатного оператора ==.
А зачем использовать для этого equals_to? Это же собственно просто "шорткат" к чему-то вроде [](const auto& l, const auto& r) {return l==r;}. Если тебе надо передать в алгоритм какой-то нестандартный предикат, то просто запиши его явно и всё — это будет намного короче и удобнее. А equals_to создан не для этого.
А вот и нет. Компилятор пошлёт о-о-очень далеко только в случае C++. В случае Haskell пошлёт не очень далеко. Makes a difference. Причём, конечно же, в случае C++ компилятор укажет не на ту строку, которая помечена комментарием «// компилятор пошлёт очень далеко». Господи, какой фейл.
Q>А вот и нет. Компилятор пошлёт о-о-очень далеко только в случае C++. В случае Haskell пошлёт не очень далеко. Makes a difference.
Текст ошибки "No instance for (Num [Char])" конечно несколько короче чем "no match for 'operator+' (operand types are 'std::basic_string<char>' and 'int')", но не то чтобы как-то принципиально. Да и сам смысл сообщения от компилятора C++ (gcc) мне кажется несколько более ясным. Q>Причём, конечно же, в случае C++ компилятор укажет не на ту строку, которая помечена комментарием «// компилятор пошлёт очень далеко». Господи, какой фейл.
Вообще то Хаскель тоже на f укажет. ))) И оба компилятора при этом укажут весь стек вызова. Q>
Здравствуйте, alex_public, Вы писали:
_>Не избыточна. Вот смотри пример. Сейчас при разработке на C++ приложения под Андроид приходится пихать в дистрибутив (apk) от 2 (самые распространённые) до 6 (теоретический максимум в данный момент, охватывающий точно всё) версий приложения, под разные процессорные архитектуры. Если бы вместо этого мы компилировали приложение в llvm, а потом при инсталляции приложения на устройство перекомпилировали в машинные коды процессора данного устройства (кстати, в современном Андроиде именно так и происходит с Java кодом), то можно было бы класть только одну версию приложения в дистрибутив, что гораздо удобнее и экономнее. Причём это всё было бы без малейших потерь в производительности.
Это потому что сама идея дурацкая. Нужно сразу из магазина качать под нужную архитектуру, а не на клиенте разгребать, что подходит, а что — нет. Тем более что все равно этим не все пользуются, попробуй firefox на x86 андроид поставить — из магазина не заработает, хотя нужная сборка на сайте мозиллы есть.
Переубедить Вас, к сожалению, мне не удастся, поэтому сразу перейду к оскорблениям.
Здравствуйте, alex_public, Вы писали:
_>Здравствуйте, samius, Вы писали:
S>>Вот видишь, именно из твоего определения (сам придумал, или все-таки укажешь источник?) как раз и следует что перегрузка функций — параметрический полиморфизм, ибо найдется более одного типа, которые можно обработать одним и тем же кодом (вызывающим перегрузку).
_>Это каким этом образом перегрузка функций является одним и тем же кодом? При перегрузке у тебя как раз получается несколько версий функции в исходнике. Продемонстрируй пример своего тезиса)
Я написал совсем не то, что ты передернул. Так что, или у тебя с падежами проблемы, или ты хочешь от меня демонстрацию не моего тезиса.
S>>Это зависит от определения функции xrmbrm. Если она параметрически полиморфна, то тем же свойством будет обладать "алиас". Если она выдвигает требования к аргументу (инстанс класса), то ad hoc. А уж если она определена мономорфо — то соответственно f будет мономорфна.
_>Хыхы, похоже ты совсем не представляешь, как это всё работает. Но чтобы это явно продемонстрировать потребуется немного другой пример, тем более, что мы уж давно ушли от обсуждения того несчастного компаратора и перешли к принципиальным вопросам о сути шаблонов C++ и полиморфизма Хаскеля.
Похоже ты совсем не представляешь, что я не представляю.
Принципиальный вопрос здесь — устаканить определение и источник. Без этого обсуждение сути шаблонов С++ и полиморфизма Хаскеля — просто перевод трафика.
_>И так возьмём такую простейшую функцию на Хаскеле: _>
_>apply f x = f x
_>
_>и скомпилируем её в отдельный бинарный модуль (ну чтобы точно не было никаких иллюзий). А затем попробуем выполнить следующий тестовый примерчик (использующий только этот модуль): _>
_>f x = x + 1
_>apply f 1 -- вернёт 2
_>apply f 1.0 -- вернёт 2.0
_>apply f "1"-- компилятор пошлёт очень далеко
_>
_>Ну и соответственно будет очень интересно послушать твои мысли на счёт того, какой полиморфизм реализует функция apply и как это всё работает.
А мне все еще интересно послушать, не выдумал ли сам ты то определение параметрического полиморфизма, что привел.
Исходя из того определения, что я использую, apply параметрически полиморфна. Она принимает любую функцию из a в b и возвращает такую же. Раз ты подаешь функцию, ограниченную классом, то и получаешь на выходе apply соответствующий результат.
А вот то что ты подаешь строку на вход
apply f :: Num t1 => t1 -> t1
— тут apply с ее параметрическим полиморфизмом уже не виновата.
_>А после этого твоего ответа рассмотрим такой код на C++: _>
_>И соответственно будет интересно услышать от тебя какая разница у этого кода с примером на Хаскеле. И на уровне исходных кодов и на уровне машинных.
Мм, разницу в исходнике посмотри diff-ом, а в машинных кодах — не знаю. Тебя же компилятор послал далеко, значит машинных кодов нет.
_>Да, и уже не совсем по теме. Так же было бы забавно увидеть вариант этого примера на Java/C# — там же у нас тоже вроде как есть подобие полиморфизма, не так ли? )))
Вроде есть. Но там у нас подобие полиморфизма первого ранга. Так что, ради твоей забавы не стану корячиться.
S>>Ну я не думаю что для тебя это будет откровением. Например, для того, что бы использовать алгоритмы, нуждающиеся в binary_function для типов, у которых нет оператора сравнения и нет возможности определить его.
_>Это каким образом может не быть возможности определить его?
таким, что оператор скрыт модификатором доступа, а исходники тебе не доступны.
S>>Или для того, что бы использовать способ сравнения типов отличный, от штатного оператора ==.
_>А зачем использовать для этого equals_to? Это же собственно просто "шорткат" к чему-то вроде [](const auto& l, const auto& r) {return l==r;}. Если тебе надо передать в алгоритм какой-то нестандартный предикат, то просто запиши его явно и всё — это будет намного короче и удобнее. А equals_to создан не для этого.
Уговорил, не для этого. Что не отменяет его ad hoc природы.
Вообще, очень мило что ты проигнорировал сделанные мной цитаты с определением и классификацией полиморфизма. Если тебе нечего к ним добавить, то вопрос о природе equal_to можно закрывать.
Здравствуйте, samius, Вы писали:
S>Здравствуйте, Serginio1, Вы писали:
S>>Здравствуйте, samius, Вы писали:
S>>>Однако, строим ли мы дерево вручную, или компилятор его строит, способ вызова оператора сравнения будет одним и тем же. Если, конечо, деревья выражений транслируются в IL. Т.е. никакого инлайнинга по сравнению с написанным в обычном C# коде выражением "field >= start".
S>> Конечно транслируются Программирование на C# 5.0 S>Это я уточняю вариант. Т.е. пишу что речь не про SQL или еще что-то там. Т.е. когда деревья транслируются в IL, то способ вызова оператора сравнения невозможно отличить от того что получается при обычной компиляции исходника C#. Именно это я хотел сказать.
Я же тебе дал ссылкую Там показано во, что транслуруются Expression<Func<int,bool>> greaterThenZero=value=> value>0;
А вот Iquerable принимает как раз Expression. То есть когда ты видишь Where(value=> value>0) то это не Func<int,bool> а Expression<Func<int,bool>>
которые могут и компилироваться в инлайн. Ты же передаешь не функцию, а дерево
S>> Деревья выражений собираются и компилируются в рантайме. S>> Мы можем собирать SQl выражение из разных кусочков, но на выходе должны получить один Sql запрос. S>Это известно со времен LinqToSQL
Правильно, но работаем мы не с Func, а с Expression.
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Ops, Вы писали:
_>>Не избыточна. Вот смотри пример. Сейчас при разработке на C++ приложения под Андроид приходится пихать в дистрибутив (apk) от 2 (самые распространённые) до 6 (теоретический максимум в данный момент, охватывающий точно всё) версий приложения, под разные процессорные архитектуры. Если бы вместо этого мы компилировали приложение в llvm, а потом при инсталляции приложения на устройство перекомпилировали в машинные коды процессора данного устройства (кстати, в современном Андроиде именно так и происходит с Java кодом), то можно было бы класть только одну версию приложения в дистрибутив, что гораздо удобнее и экономнее. Причём это всё было бы без малейших потерь в производительности. Ops>Это потому что сама идея дурацкая. Нужно сразу из магазина качать под нужную архитектуру, а не на клиенте разгребать, что подходит, а что — нет. Тем более что все равно этим не все пользуются, попробуй firefox на x86 андроид поставить — из магазина не заработает, хотя нужная сборка на сайте мозиллы есть.
Ну это понятно. И можно даже догадаться о причинах (в самых первых версиях предполагался прикладной код исключительно на Java — хаха). Но если уж так сложилось, то llvm был бы хорошим решением проблемы. Тем более, что в последних версиях и у Java кода появилась компиляция при установке.
Здравствуйте, samius, Вы писали:
S>>>Вот видишь, именно из твоего определения (сам придумал, или все-таки укажешь источник?) как раз и следует что перегрузка функций — параметрический полиморфизм, ибо найдется более одного типа, которые можно обработать одним и тем же кодом (вызывающим перегрузку). _>>Это каким этом образом перегрузка функций является одним и тем же кодом? При перегрузке у тебя как раз получается несколько версий функции в исходнике. Продемонстрируй пример своего тезиса) S>Я написал совсем не то, что ты передернул. Так что, или у тебя с падежами проблемы, или ты хочешь от меня демонстрацию не моего тезиса.
Эээ что? Ты написал, что из моего определения "следует что перегрузка функций — параметрический полиморфизм" (это точная цитата). Вот я тебе и предлагаю привести конкретный пример (перегрузку функций, подходящую под моё определение параметрического полиморфизма), который демонстрировал бы правоту этого твоего тезиса.
_>>И так возьмём такую простейшую функцию на Хаскеле: _>>
_>>apply f x = f x
_>>
_>>и скомпилируем её в отдельный бинарный модуль (ну чтобы точно не было никаких иллюзий). А затем попробуем выполнить следующий тестовый примерчик (использующий только этот модуль): _>>
_>>f x = x + 1
_>>apply f 1 -- вернёт 2
_>>apply f 1.0 -- вернёт 2.0
_>>apply f "1"-- компилятор пошлёт очень далеко
_>>
_>>Ну и соответственно будет очень интересно послушать твои мысли на счёт того, какой полиморфизм реализует функция apply и как это всё работает. S>Исходя из того определения, что я использую, apply параметрически полиморфна. Она принимает любую функцию из a в b и возвращает такую же. Раз ты подаешь функцию, ограниченную классом, то и получаешь на выходе apply соответствующий результат. S>А вот то что ты подаешь строку на вход S>
S>apply f :: Num t1 => t1 -> t1
S>
S>- тут apply с ее параметрическим полиморфизмом уже не виновата.
О, прогресс, наконец то зафиксировали некоторое согласие! И так данная функция apply — это параметрическим полиморфизм в чистом виде. И с этим никто не спорит. ОК.
_>>А после этого твоего ответа рассмотрим такой код на C++: _>>
_>>И соответственно будет интересно услышать от тебя какая разница у этого кода с примером на Хаскеле. И на уровне исходных кодов и на уровне машинных. S>Мм, разницу в исходнике посмотри diff-ом,
diff то как раз разницу покажет. А вот любой вменяемый программист скажет что разницы в данных двух примерах кода нет.
Но меня больше интересует другое. С твоей точки зрения apply из C++ примера — это какой полиморфизм? )
S>а в машинных кодах — не знаю.
Тут как раз всё просто. Данный вариант функции apply невозможно засунуть в бинарный модуль (библиотеку), как это сделано в Хаскеле. В то же время конечное приложение, использующий данный (C++) вариант функции apply будет оптимизировано гораздо лучше своего аналога на Хаскеле.
_>>Да, и уже не совсем по теме. Так же было бы забавно увидеть вариант этого примера на Java/C# — там же у нас тоже вроде как есть подобие полиморфизма, не так ли? ))) S>Вроде есть. Но там у нас подобие полиморфизма первого ранга. Так что, ради твоей забавы не стану корячиться.
Угу, именно про это я имел в виду, когда писал в предыдущем сообщение "нет ни удобства, ни быстродействие". )))
S>Вообще, очень мило что ты проигнорировал сделанные мной цитаты с определением и классификацией полиморфизма. Если тебе нечего к ним добавить, то вопрос о природе equal_to можно закрывать.
Цитаты то ты приводил нормальные. Только делаешь из них неадекватные выводы. Причём сам это потом (после долгого и занудного разбора) это признаёшь. Так что в дискуссии с тобой проще рассмотреть конкретный пример кода и из него сразу всё становится ясно.
Здравствуйте, alex_public, Вы писали:
_>Ну это понятно. И можно даже догадаться о причинах (в самых первых версиях предполагался прикладной код исключительно на Java — хаха). Но если уж так сложилось, то llvm был бы хорошим решением проблемы. Тем более, что в последних версиях и у Java кода появилась компиляция при установке.
Так а что сложилось-то? Кто мешает отдавать вместо помойки из нескольких, один правильный бинарник для нужной архитектуры, пусть и в обычном APK?
А вот вместо компиляции при установке лучше сделать компиляцию перед отдачей, нехай сервер работает, он мощный и с кондеем, заодно закеширует для других с такой же архитектурой.
Переубедить Вас, к сожалению, мне не удастся, поэтому сразу перейду к оскорблениям.
Здравствуйте, samius, Вы писали:
S>Вот, именно что выглядит "как".
А только это и важно.
Т.е., с одной стороны, у нас есть некий уровень реализации полиморфизма с т.з. программиста:
— перегрузка имен ф-ий;
— виртуальные ф-ии;
— параметрический полиморфизм некоторого ранга (туда же обязательный автовывод типов при ранге большем 1, иначе такой полиморфизм будет неюзабелен).
С другой стороны есть механики его обеспечения компилятором — матчинг типа и соответствующей ему ф-ии/метода на этапе компиляции/оптимизации или на этапе исполнения через таблицу ф-ий, как для случая виртуальных ф-ий в ООП или в некоторых сценариях с использованием классов типов в том же Хаскеле.
S>Класс типов осуществляет диспетчеризацию статически, сводя параметрический и ad hoc полиморфизм в единую модель.
Неверно. Тут в разные годы пробегали примеры на Хаскель с использованием классов типов, где без динамического матчинга времени исполнения никак — компилятор Хаскель создаёт таблицы ф-ий для их инстансов для конкретных типов.
Но все эти вещи, повторюсь, относительно прозрачны для программиста. Начинающего программиста должны интересовать лишь возможности языка, а более опытного — дополнительно понимание "цены" каждого вида полиморфизма в рантайме.
Например, в классике ООП:
foreach(Widget w in widgets)
w.Draw(context);
— динамический ad hoc полиморфизм на виртуальной ф-ии Draw.
А вот здесь:
Rectangle r = new Rectangle(bounds);
r.Draw(context);
хороший компилятор должен должен будет вставить прямой вызов Draw, а не виртуальный, т.е. имеем статический ad hoc полиморфизм.
По-сути мы зацепились вокруг того, что хотя компилятор C# в 99% случаев был бы способен разресолвить параметрический полиморфизм на этапе компиляции (т.е. приведя его к ad hoc через вывод монотипов, прямо как на шаблонах С++), однако же, ради "экономии" размера бинарника всё будет сведено к динамическому ad hoc-полиморфизму на основе виртуальных вызовов типов-ограничений (интерфейсов или абстрактных/виртуальных баз).
S>т.е. если мы ограничиваем рассмотрение типов множеством типов некого класса (или множество типов, с определенным оператором сравнения, конструктором копирования и т.п.), то выходит что это как бы параметрический полиморфизм, несмотря на то, что оно ограничено явным образом.
Разные виды полиморфизма ни в коем случае не ортогональны друг другу, а часто друг через друга выражаются или некие случаи представляют из себя одновременно несколько разновидностей полиморфизма. Поэтому, ИМХО, — это рассуждения вникуда, когда пытаются один вид полиморфизма "тщательно отделить" от другого.
Еще раз. "Полиморфизм" в общем смысле — он ровно один, означает способность ЯП автоматически сопоставлять конкретные одноимённые ф-ии/методы (или операторы, что тоже есть ф-ии) конкретным типам, что позволяет программисту делать меньше работы, т.е. полиморфизм повышает выразительность языка. Но степень подобной "автоматизации" и её рантайм-цена у разных языков разная.
S>Но он параметрический лишь до той степени, пока не потребуется взять тип, не удовлетворяющий ограничению. В то время как кошерно параметрический код не требует от этого типа более ничего.
Ну как это "ничего"? Мы с "самого низа" используем ну хотя бы операторы языка. Операторы — это тоже ф-ии, язык с хорошей поддержкой полиморфизма должен позволять определять семантику этих операторов для различных типов или их классов. Например, в Хаскеле предопределены некоторые базовые классы типов, необходимые для использования операторов языка: Eq, Ord, Num, Real, Integral, Monad или для базовых операций преобразования в строку — Show. Т.е., совсем "из ничего" не получится.
S>Т.е. я могу согласиться с тем, что equal_to параметрически полиморфна на множестве типов с определенным оператором сравнения, объединенном с множеством типов, для которых существует явная специализация equal_to. Но при этом ее ad hoc природу не спрятать.
А вот не надо пытаться тщательно отделять мух от котлет, когда речь о полиморфизме. ))
Потому что это зачастую банально невозможно.
Как конкретный тип может иметь одновременно признаки разных классов, так и конкретный сценарий полиморфизма может одновременно быть случаем совместной работы разных "трюков" обеспечения полиморфизма или даже одновременно являться любым из некоего множества "трюков" в их граничных/частных ситуациях.
Здравствуйте, samius, Вы писали:
S>Т.е. я могу согласиться с тем, что equal_to параметрически полиморфна на множестве типов с определенным оператором сравнения
Хм, так а вроде только это моё утверждение и вызывало у тебя возражения. Если ты теперь с ним согласился, то:
1. не вижу причин для дальнейших споров
2. инлайновые параметрически полиморфные компараторы всё же существуют в природе. Во всяком случае в C++.
Здравствуйте, Ops, Вы писали:
_>>Ну это понятно. И можно даже догадаться о причинах (в самых первых версиях предполагался прикладной код исключительно на Java — хаха). Но если уж так сложилось, то llvm был бы хорошим решением проблемы. Тем более, что в последних версиях и у Java кода появилась компиляция при установке. Ops>Так а что сложилось-то? Кто мешает отдавать вместо помойки из нескольких, один правильный бинарник для нужной архитектуры, пусть и в обычном APK?
Технически проблем нет. Но это как бы надо делать (слегка поменять инфраструктуру), в то время как сейчас "и так всё работает". )))
Ops>А вот вместо компиляции при установке лучше сделать компиляцию перед отдачей, нехай сервер работает, он мощный и с кондеем, заодно закеширует для других с такой же архитектурой.
Нуу для самых требовательных к производительности задач может быть выгоднее компиляция как раз на конечном устройстве, т.к. можно будет использовать все возможности процессора (а не брать некий минимальный уровень, как принято сейчас). Хотя для мобильных процессоров это пока не столько актуально как для десктопных (где какой-нибудь AVX2 очень заметно круче SSE4), но всё же...
Здравствуйте, Serginio1, Вы писали:
S>Здравствуйте, samius, Вы писали:
S>>Это я уточняю вариант. Т.е. пишу что речь не про SQL или еще что-то там. Т.е. когда деревья транслируются в IL, то способ вызова оператора сравнения невозможно отличить от того что получается при обычной компиляции исходника C#. Именно это я хотел сказать.
S> Я же тебе дал ссылкую Там показано во, что транслуруются Expression<Func<int,bool>> greaterThenZero=value=> value>0;
S>А вот Iquerable принимает как раз Expression. То есть когда ты видишь Where(value=> value>0) то это не Func<int,bool> а Expression<Func<int,bool>> S>которые могут и компилироваться в инлайн. Ты же передаешь не функцию, а дерево
Какая разница, что я передаю, если обычный оператор <, он же переписанный линк реврайтером, он же поданный в виде Expression и скомпилированный в рантайме, все они вызываются одинакого с точностью до инструкции при выполнении?
S>>Это известно со времен LinqToSQL S> Правильно, но работаем мы не с Func, а с Expression.
И? А если бы мы работали с DynamicMethod, то оператор < вызывался бы как-то по другому?
Здравствуйте, alex_public, Вы писали:
_>Здравствуйте, samius, Вы писали:
_>>>Это каким этом образом перегрузка функций является одним и тем же кодом? При перегрузке у тебя как раз получается несколько версий функции в исходнике. Продемонстрируй пример своего тезиса) S>>Я написал совсем не то, что ты передернул. Так что, или у тебя с падежами проблемы, или ты хочешь от меня демонстрацию не моего тезиса.
_>Эээ что? Ты написал, что из моего определения "следует что перегрузка функций — параметрический полиморфизм" (это точная цитата). Вот я тебе и предлагаю привести конкретный пример (перегрузку функций, подходящую под моё определение параметрического полиморфизма), который демонстрировал бы правоту этого твоего тезиса.
Да я это написал, а ты меня спросил (см выделенное выше).
А пример, который ты просишь — ровно то, что мы и обсуждаем: equal_to, который единым образом для разных типов вызывает совершенно различный код, определенный в совершенно разных мономорфных функциях.
S>>А вот то что ты подаешь строку на вход S>>
S>>apply f :: Num t1 => t1 -> t1
S>>
S>>- тут apply с ее параметрическим полиморфизмом уже не виновата.
_>О, прогресс, наконец то зафиксировали некоторое согласие! И так данная функция apply — это параметрическим полиморфизм в чистом виде. И с этим никто не спорит. ОК.
Ок
_>>>А после этого твоего ответа рассмотрим такой код на C++: _>>>
_>>>И соответственно будет интересно услышать от тебя какая разница у этого кода с примером на Хаскеле. И на уровне исходных кодов и на уровне машинных. S>>Мм, разницу в исходнике посмотри diff-ом,
_>diff то как раз разницу покажет. А вот любой вменяемый программист скажет что разницы в данных двух примерах кода нет.
Не уверен. Давай спросим любого вменяемого? Как будем определять вменяемость?
_>Но меня больше интересует другое. С твоей точки зрения apply из C++ примера — это какой полиморфизм? )
именно apply — выглядит параметрически полиморфно так же как и apply в Хаскеле, с той разницей, что применение с ее помощью разных функций приведет к распуханию бинарника и обращениям в рантайме к разным версиям, что указывает на ad hoc.
_>Тут как раз всё просто. Данный вариант функции apply невозможно засунуть в бинарный модуль (библиотеку), как это сделано в Хаскеле. В то же время конечное приложение, использующий данный (C++) вариант функции apply будет оптимизировано гораздо лучше своего аналога на Хаскеле.
Оптимизировано в каком отношении?
И как возможность оптимизации влияет на классификацию?
S>>Вроде есть. Но там у нас подобие полиморфизма первого ранга. Так что, ради твоей забавы не стану корячиться.
_>Угу, именно про это я имел в виду, когда писал в предыдущем сообщение "нет ни удобства, ни быстродействие". )))
Лично я в плане удобства С++ -у предпочитаю C#. А быстродействие меня (и не только) пока устраивает.
_>Цитаты то ты приводил нормальные. Только делаешь из них неадекватные выводы. Причём сам это потом (после долгого и занудного разбора) это признаёшь. Так что в дискуссии с тобой проще рассмотреть конкретный пример кода и из него сразу всё становится ясно.
Мои выводы ты пока не смог оспорить.
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, samius, Вы писали:
S>>Вот, именно что выглядит "как".
V>А только это и важно.
Кому как
V>Т.е., с одной стороны, у нас есть некий уровень реализации полиморфизма с т.з. программиста: V>- перегрузка имен ф-ий; V>- виртуальные ф-ии; V>- параметрический полиморфизм некоторого ранга (туда же обязательный автовывод типов при ранге большем 1, иначе такой полиморфизм будет неюзабелен).
согласен
V>С другой стороны есть механики его обеспечения компилятором — матчинг типа и соответствующей ему ф-ии/метода на этапе компиляции/оптимизации или на этапе исполнения через таблицу ф-ий, как для случая виртуальных ф-ий в ООП или в некоторых сценариях с использованием классов типов в том же Хаскеле.
верно. Но цитата из Пирса однозначно отсылает к механике выполнения в рантайме. И если интерпретатор, рантайм, или еще кто выполняет разные версии кода для разных типов, то это ad hoc.
S>>Класс типов осуществляет диспетчеризацию статически, сводя параметрический и ad hoc полиморфизм в единую модель.
V>Неверно. Тут в разные годы пробегали примеры на Хаскель с использованием классов типов, где без динамического матчинга времени исполнения никак — компилятор Хаскель создаёт таблицы ф-ий для их инстансов для конкретных типов.
Согасен. Для программиста это выглядит статически, а в рантайме может использоваться динамика для избежания распухания, или по каким-то другим мотивам. Статика или динамика не сказывается на универсальности.
V>Но все эти вещи, повторюсь, относительно прозрачны для программиста. Начинающего программиста должны интересовать лишь возможности языка, а более опытного — дополнительно понимание "цены" каждого вида полиморфизма в рантайме.
Верно, у всего своя цена.
V>Например, в классике ООП: V>
V>foreach(Vidget v in vidgets)
V> v.Draw(context);
V>
V>- динамический ad hoc полиморфизм на виртуальной ф-ии Draw.
+1
V>А вот здесь: V>
V>Rectangle r = new Rectangle(bounds);
V>r.Draw(context);
V>
V>хороший компилятор должен должен будет вставить прямой вызов Draw, а не виртуальный, т.е. имеем статический ad hoc полиморфизм.
+1
V>По-сути мы зацепились вокруг того, что хотя компилятор C# в 99% случаев был бы способен разресолвить параметрический полиморфизм на этапе компиляции (т.е. приведя его к ad hoc через вывод монотипов, прямо как на шаблонах С++), однако же, ради "экономии" размера бинарника всё будет сведено к динамическому ad hoc-полиморфизму на основе виртуальных вызовов типов-ограничений (интерфейсов или абстрактных/виртуальных баз).
не вполне распарсил выделенное
А то что компилятор C# был бы способен многое — это верно.
S>>т.е. если мы ограничиваем рассмотрение типов множеством типов некого класса (или множество типов, с определенным оператором сравнения, конструктором копирования и т.п.), то выходит что это как бы параметрический полиморфизм, несмотря на то, что оно ограничено явным образом.
V>Разные виды полиморфизма ни в коем случае не ортогональны друг другу, а часто друг через друга выражаются или некие случаи представляют из себя одновременно несколько разновидностей полиморфизма. Поэтому, ИМХО, — это рассуждения вникуда, когда пытаются один вид полиморфизма "тщательно отделить" от другого.
Не вполне согласен. Есть чистые случаи (пусть они крайности), есть комбинированные.
V>Еще раз. "Полиморфизм" в общем смысле — он ровно один, означает способность ЯП автоматически сопоставлять конкретные одноимённые ф-ии/методы (или операторы, что тоже есть ф-ии) конкретным типам, что позволяет программисту делать меньше работы, т.е. полиморфизм повышает выразительность языка. Но степень подобной "автоматизации" и её рантайм-цена у разных языков разная.
Хорошо, тут не с чем спорить.
S>>Но он параметрический лишь до той степени, пока не потребуется взять тип, не удовлетворяющий ограничению. В то время как кошерно параметрический код не требует от этого типа более ничего.
V>Ну как это "ничего"? Мы с "самого низа" используем ну хотя бы операторы языка. Операторы — это тоже ф-ии, язык с хорошей поддержкой полиморфизма должен позволять определять семантику этих операторов для различных типов или их классов. Например, в Хаскеле предопределены некоторые базовые классы типов, необходимые для использования операторов языка: Eq, Ord, Num, Real, Integral, Monad или для базовых операций преобразования в строку — Show. Т.е., совсем "из ничего" не получится.
Вот все что я выделил — это https://wiki.haskell.org/Polymorphism#Ad-hoc_polymorphism
С этим есть разногласия? А я говорил о параметрическом.
S>>Т.е. я могу согласиться с тем, что equal_to параметрически полиморфна на множестве типов с определенным оператором сравнения, объединенном с множеством типов, для которых существует явная специализация equal_to. Но при этом ее ad hoc природу не спрятать.
V>А вот не надо пытаться тщательно отделять мух от котлет, когда речь о полиморфизме. )) V>Потому что это зачастую банально невозможно.
Что тут сложного? equal_to — ad hoc, Eq a — ad hoc. Но если внезапно из рассмотрения выкинуть все типы, кроме тех, у которых определен оператор == или инстанс Eq, то тогда они выглядят как параметрические.
V>Как конкретный тип может иметь одновременно признаки разных классов, так и конкретный сценарий полиморфизма может одновременно быть случаем совместной работы разных "трюков" обеспечения полиморфизма или даже одновременно являться любым из некоего множества "трюков" в их граничных/частных ситуациях.
Здравствуйте, alex_public, Вы писали:
_>Здравствуйте, samius, Вы писали:
S>>Т.е. я могу согласиться с тем, что equal_to параметрически полиморфна на множестве типов с определенным оператором сравнения
_>Хм, так а вроде только это моё утверждение и вызывало у тебя возражения. Если ты теперь с ним согласился, то:
вырвал таки из контекста. Я с этим согласен, если из рассмотрения выбросить любые типы, не реализующие оператор ==.
_>1. не вижу причин для дальнейших споров
аналогично _>2. инлайновые параметрически полиморфные компараторы всё же существуют в природе. Во всяком случае в C++.
дада. На синтетически ограниченном наборе типов, не глядя в распухание бинарника. В таком ракурсе не возражаю.
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Я например уже несколько раз говорил про создание проекта. Установили VS Code, установили расширение на базе OmniSharp "ивсеработает" — как C# проект создать?
открываете пустую папку, запускаете встроенный терминальчик и в нем набираете dotnet new console — все не покидая VS Code
Если у Вас нет паранойи, то это еще не значит, что они за Вами не следят.
Здравствуйте, samius, Вы писали:
S>Здравствуйте, Serginio1, Вы писали:
S>>Здравствуйте, samius, Вы писали:
S>>>Это я уточняю вариант. Т.е. пишу что речь не про SQL или еще что-то там. Т.е. когда деревья транслируются в IL, то способ вызова оператора сравнения невозможно отличить от того что получается при обычной компиляции исходника C#. Именно это я хотел сказать.
S>> Я же тебе дал ссылкую Там показано во, что транслуруются Expression<Func<int,bool>> greaterThenZero=value=> value>0;
S>>А вот Iquerable принимает как раз Expression. То есть когда ты видишь Where(value=> value>0) то это не Func<int,bool> а Expression<Func<int,bool>> S>>которые могут и компилироваться в инлайн. Ты же передаешь не функцию, а дерево S>Какая разница, что я передаю, если обычный оператор <, он же переписанный линк реврайтером, он же поданный в виде Expression и скомпилированный в рантайме, все они вызываются одинакого с точностью до инструкции при выполнении?
Разница есть. Если Func то вызовется этот метод, а деревья развернутся и по сути проинлайнчятся S>>>Это известно со времен LinqToSQL S>> Правильно, но работаем мы не с Func, а с Expression. S>И? А если бы мы работали с DynamicMethod, то оператор < вызывался бы как-то по другому?
DynamicMethod это метод а дерево это дерево. Дерево нужно скомпилировать для выполнения. А в Linq To Sql оно просто собирается и из него строится выражение SQL
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, TK, Вы писали:
EP>>Я например уже несколько раз говорил про создание проекта. Установили VS Code, установили расширение на базе OmniSharp "ивсеработает" — как C# проект создать? TK>открываете пустую папку, запускаете встроенный терминальчик и в нем набираете dotnet new console
Так именно об этом и речь — создание проекта через консоль, open folder и прочие уши — нет той самой интегрированности (буква I в IDE).
TK>- все не покидая VS Code
Ну да, вот тебе консоль и ни в чём себе не отказывай
Здравствуйте, Serginio1, Вы писали:
S>Здравствуйте, samius, Вы писали:
S>>Какая разница, что я передаю, если обычный оператор <, он же переписанный линк реврайтером, он же поданный в виде Expression и скомпилированный в рантайме, все они вызываются одинакого с точностью до инструкции при выполнении? S> Разница есть. Если Func то вызовется этот метод, а деревья развернутся и по сути проинлайнчятся
Я говорю об компараторе, а не о делегате.
S>>И? А если бы мы работали с DynamicMethod, то оператор < вызывался бы как-то по другому? S> DynamicMethod это метод а дерево это дерево. Дерево нужно скомпилировать для выполнения. А в Linq To Sql оно просто собирается и из него строится выражение SQL
DynamicMethod тоже без компиляции не выполнится.