Скажите пожалуйста, а switch-case для enum в Си++ — это тоже динамическая типизация?
V>Ты мне покажи вот так: V>main' :: Integer -> Integer -> a -> b -> Integer
V>Потом подай на a и b одинаковые типы извне. Вот это и будет настоящий ПП, а не тот, которым вы хотите незаслуженно обозвать систему типов Хаскеля.
Не понял. Что должна делать такая функция? Ругаться при компиляции на разные типы? Или молча жрать все? Тогда в чём замысел?
Здравствуйте, vdimas, Вы писали:
V>В каких разных? Продемонстрируй плиз разные пространства имен для конструктора АлгТД и для одноименного идентификатора метки типа в конструкции ПМ некоего значения, созданного с помощью этого конструктора.
Я говорил про имя типа и имя конструктора.
V>Эээ... колега, а что вообще могло бы означать "упаковка другого типа" для АлгТД?
Вот и мне интересно. Это ведь вы утверждаете, что конструкторы АлгТД — типы.
V>А если так перефразировать: V>Матчинг АлгТД в Хаскеле аналогично проверяет в рантайм дискриминатор объединения, то бишь тип запакованного значения.
Дескриминатор-то он, разумеется, проверяет в рантайме. А тип "запакованного" значения — нет. О чем и весь этот разговор.
K>>Ну, может и можно сказать, что конструктор типа "упаковывает" типа по аналогии с тем, как конструктор "упаковывает" значение. Вот только конструкторы типов в рантайме не матчатся (в рантайме их нет).
V>А как конструкторы могут матчиться?
Ну вот, приехали. А что, что-то может матчиться кроме конструкторов?
V>Ведь конструктор — это ф-ия.
Совсем не обязательно. В ocaml, например, конструктор функцией не является. Но даже если всякий конструктор — функция, то все равно не всякая функция — конструктор.
V>Может матчиться лишь некое ID размеченного объединения, то бишь матч всегда идет по ЗНАЧЕНИЮ
Правильно. Имя конструктора и есть этот ID.
V>в данном случае это значение метки типа. Т.е. можно сказать, что идет матч по типу завернутого значения.
Это значение к метке типа не имеет никакого отношения. Т.е. так сказать нельзя.
-- так можноdata FooBar = Foo Int | Bar Int-- так нельзяdata Foo = Foo Int | Foo Bool
т.е. в рантайме проверяются не типы. ч.т.д.
V>Угу, ты повторно налегаешь на подтипирование, хотя я его не упоминал.
Постоянно упоминаете, когда говорите о проверке метки типа в рантайме.
V>Я догадываюсь, что ты намекаешь на реализацию наподобие АлгТД в Немерле, но я-то здесь при чем?
Не намекаю. Я объясняю, что является типом в хаскеле, а что не является.
V>Размеченное объединение обязательно хранит метку обернутого в АлгТД типа. Почему именно типа? Потому что согласно определения, размеченное объединение хранит в себе не только сам элемент, но обязательно некий уникальный идентификатор мн-ва, к которому принадлежит хранимый элемент. Мн-во — это тип, элемент мн-ва — это значение типа.
Тип — это не всякое множество, а множество, пренадлежность к которому может проверить тайпчекер. Статически.
V>data List a = Nil | Cons a (List a)
V>Для значения дескриминатора Nil_tag хранится tuple(/*empty*/), для значения Cons_tag хранится tuple(a, List<a>). Оба тупла и есть хранимые значения. Но сии значения-туплы имеют тип, как ни крути.
Туплы имеют тип. Но этот тип не находится с алгтд в отношениях подтипирования.
V>И да, от техники подтипирования в том же Немерле такая схема по-сути не отличается. Хоть ты и додумал за меня малость, насчет подтипирования, но происходящие в обоих случаях проверки типов при паттерн-матчинге — это суть проверки значения некоей метки. Вся разница лишь в том, что в Хаскеле метка представлена "унутре" интегральным значением, а в Немерле — адресом (сылкой) на дескриптор типа. По идее, тоже интегральным значением (адреса).
В хаскеле (ghc) эта "метка" как раз и представлена ссылкой на дескриптор блока памяти и (в случае небольшого числа конструкторов) тегом в указателе на блок.
K>>Ну так boost::variant это не сумма, а объединение — чего вы от него хотите. variant< int, bool > это int или bool.
V>Не так, это еще хранимый признак типа, как и положено. Поэтому это или container<0, int> или container<1, bool>. Т.е. в плане хранения — дотягивают. Они недотягивают в момент диспетчеризации по конкретным хранимым типам, бо для одного и того же типа будет вызвана одна и та же ветка диспетчеризации
Вот вы и описываете разницу между сабтайпингом (boost::variant) и алгебраическим типом. Еще одно различие. Через параметр типа variant< int, bool > можно передать и int и bool. Потому, что любые значения этих типов являются также и значениями вариантного типа. Это и называется "отношение подтипирования". Между типами "упакованными" в сумму и суммой такого отношения нет. Через параметр типа Either Int Bool нельзя передать ни значение типа Int, ни значение типа Bool. Только Either Int Bool.
V>Да пофиг. Реализация инстансов классов на технике-аналоге vtable ничем по-сути от происхоящего с помощью АлгТД не отличается.
Вот только инстансы классов на технике-аналоге vtable не реализуются (если у нас полиморфизм ранга-1).
V>Тем более, что обсуждаемый пример можно переписать на АлгТД и обойтись без классов типов.
Нельзя. Потому, что нам нужны тайплевел вычисления, а не рантайм-проверка.
V>Для тега алгТД место в рантайме таки требуется.
Никакие "Теги" АлгТД в рантайме не хранятся. Есть ссылка на InfoTable. У каждого вида лайаута данных в памяти — своя таблица.
V>Или ты считаешь, что процедура сравнения тега размеченного объединения и распаковка затем хранимого значения чем-то отличается от динамической типизации? Это абсолютно такое же кол-во телодвижений за ту же стоимость.
То, является что-то типизацией или не является не определяется стоимостью. Типизация — это проверка типа. Если мы проверяем значения на совпадение с BoxInt, true или 0 — это не проверка типа потому, что все это не типы. Не всякая проверка — проверка типа.
V>Именно. А приводимый пример фактически надуманный, т.к. что там проверять-то?, коль списки формируются параллельно.
Ну так то, что списки формируются параллельно и проверяется.
V>Да неполноценный это ПП ни разу. В любой точке примера используется один и тот же тип для обоих списков, а потом заявляется, что мы якобы проверяем что типы одинаковы. Хотя такими их объявили сами же.
Ну так смысл проверки типов в том, чтоб проверять соответствие функции типу, которым ее проаннотировали. Если функция не будет строить списки параллельно — будет ошибка компиляции.
V>Угу, как возражение, что при вызове ф-ий используется неявное ПМ привел явную реализацию на ПМ. Поздравляю.
Привел реализацию в которой явно видно, что есть проверка счетчика для прерывания рекурсии, а никакого "выбора функции из группы" нет.
V>Табличная диспетчеризация таки есть.
В обсуждаемом случае нет.
K>>Не верно. Все функции выбираются в компайл-тайм. V>
Да, смешно читать, что человек может нафантазировать про тайпклассы, не зная, как они работают.
V>Каким образом? Чтобы выбор сделать, надо отказаться от боксированного представления, т.е. заранее знать, где конец списка.
Не нужно знать, где конец списка. Мы начинаем построение с Nil — это статически известно. выбираем одну функцию и подставляем ее вместо функции тайпкласса. Во всех остальных случаях будет функция для Cons — одна и та же — подставлем ее. Все, вся диспетчерезация закончилась на этапе компиляции.
K>>Но весь смысл этого куска кода в compile-time проверке! V>Да нет там никакой проверки, не изобретай! Ограничение идет прямо в самой сигнатуре main': V>main' :: ScalarProduct a => Integer -> Integer -> a -> a -> Integer
Правильно, это ограничение и проверяется.
V>Т.е. в самой сигнатуре main' черным по белому сказано, что a->a. Как можно было потом радоваться, что у нас скомпиллировалась строчка в теле main': V>scalarProduct a1 a2 V>или V>scalarProduct (Cons x a1) (Cons y a2) V>если a1 и a2 имеют один и тот же тип по опредедению main'?
Ну так в этом проверка типа и заключается. Если в функции не будет "черным по белому сказано", что списки одинаковой длины — будет ошибка компиляции.
V>Ты мне покажи вот так: V>main' :: Integer -> Integer -> a -> b -> Integer
Тут написано, что типы могут быть одинаковыми, а могут и раными — все равно. Что это проверяет-то?
V>Ну коль Cons a параметризируется типом Cons a', то у нас выходит, скажем, де-факто параметрический рекурсивный тип в примере.
Отличная шутка! А любая функция, у которой область определения — подмножество области значений — "де-факто рекурсивная"? А то ведь ее можно так применить f(f(х))
K>>Дескриминаторов типа в Хаскеле просто не существует V>True, False, Cons, Nil — вот тебе существующие в рантайм дискриминаторы, хранимые вместе с данными.
Это и есть данные. Не типы.
V>Это конструкторы АлгТД в одном контексте и теги АлгТД, то бишь теги хранимого типа — в другом, например в конструкции ПМ.
Еще раз. Медленно. Теги конструктора и теги типа — разные вещи. И в конструкции ПМ никакие типы не проверяются. Тип там один — тип матчимого АлгТД. Проверяется статически.
V>А что, тебя смущает вырожденный случай размеченного объединения навроде Bool?
Ничем не смущает. Меня смущает, что вы True и False считаете типами.
... << RSDN@Home 1.2.0 alpha 4 rev. 1476>>
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Здравствуйте, Klapaucius, Вы писали:
K>Здравствуйте, samius, Вы писали:
K>>>Вот вы говорите можно, а из обсуждаемого здесь опыта известно, что нельзя. Как же так? S>>Здесь обсуждается другой опыт. А опыт написать Succ<Succ<Succ<...>>> сколько ума хватит раз не обсуждается.
K>Да не написать Succ<Succ<Succ<...>>> а получить еще один из готового. Как тут: K>
K>instance ScalarProduct a => ScalarProduct (Cons a)
K>
А причем тут наличие/отсутствие ПП?
S>>Вторая фича тут
— это импредикативность, верно?
K>Нет, не верно.
Прошу прощения. Но тогда я вообще не понимаю, как пункт 2 относится к полиморфизму.
S>>Вы доказывали что-то другое, причем я ответил по этому доказательству.
K>Вы по доказательству ответили, что оно не считается и все тут.
Я ответил что вы сделали слишком сильные выводы из определения. Это в том случае, если использовать определение с википедии. Ну а то, на которое вы ссылаетесь — я не знаю, откуда оно взялось.
K>>>Т.е. и 32-битный int — это тоже самое настоящее целое число? S>>Нет. Я же согласился что это софистика.
K>И чем, по-вашему, это обоснование через "все возможные" программы отличается от вашего?
Это важно? Имеет какое-то отношение к ПП?
S>>Предикативный и импредикативный — это формы, а не определение ПП.
K>Точно. И что? Импредикативного никто и не требует.
Ок, пусть так.
S>>Вы дали ссылку и по ссылке вторым пунктом импредикативность. Что же вы обсуждаете, если не импредикативность?
K>Ок. Выкинте упоминание об импредикативности — оно там "для справки". K>1) Возможность написать однородный (работающий одинаково для любого типа) код
Не возражаю. K>2) Типизировать этот код обобщенным типом, содержащим переменные, которые конкретизируются применением обобщенного типа к конкретному.
Вот это откуда? И можно разжевать, что значит обобщенный тип, содержащий переменные?
Вот как это в TAPL (если я правильно понял, о чем речь):
Parametric polymorphism,the topic of this chapter, allows a single piece of
code to be typed “generically,” using variables in place of actual types, and
then instantiated with particular types as needed.
И в этом нет ничего такого, что не позволил бы шаблон в C++.
K>Типизировать шаблонный код в C++ нельзя вообще никак.
Вот как то же выглядит в переводе
... позволяет давать участку кода "обобщенный тип", используя переменные вместо настоящих типов, а затем конкретизировать, замещая переменные типами.
Что вы здесь подразумеваете под "типизировать"?
S>>У него не получилось кое-что другое, о чем я не говорю. А вот написать наперед заданное число раз Cons<Cons<... он не попробовал. А это помогло бы
K>Нда. Кто decl читал — тот в цирке не смеется.
Мну цирк и до decl-а не прикалывал.
K>>>В системе типов C# 2 и выше — есть. S>>Аналога explicit forall в C# нет. Если бы был, можно было бы описать абстракцию функтора/монады и не пришлось бы жарить уток как в Query expression pattern.
K>1)explicit forall не обязателен для такого простого типа. Он тут для понятности. explicit forall, кстати, в Хаскеле без расширений нет. K>2)В C# он наоборот есть — программист просто обязан писать его в сигнатуре: K>
K>T foo<T>(Bar<T> a)
K>
K>что то же самое, что K>
K>foo :: forall t. Bar t -> t
K>
K>В хаскеле же писать его не обязательно, там где он очевиден — это просто сахар.
Я об этом (http://en.wikibooks.org/wiki/Haskell/Polymorphism#Higher_rank_types). C# такое не умеет.
S>>Типы применяются во время выполнения
K>Нет, не применяются. Как выглядит применение во время выполнения в C# мы уже обсудили.
Нет, не обсудили. Вы не захотели обсуждать, на какую глубину применяются типы в компайл-тайме и чем занимается рантайм при введении значительной глубины структуры (например от 1000).
S>>, для каждого рекурсивного вызова _main выполняется докомпиляция JIT-ом.
K>Зачем его докомпилировать? Это же ссылочные типы, для них никакие специализации не нужны!
S>>Аргументы?
K>Аргументы ниже.
K>>>JIT-компилятора для C# не существует в природе. Допустим, что мы обсуждаем JIT-компиляцию CIL. Вы утверждаете, что в link-time, ngen-ом этот код полностью не скомпилировать? S>>Не так. в один проход мы его скомпилируем, но по мере необходимости рекурсивных вызовов он будет докомпиляться. S>>А где-нибудь в сингулярити, где JIT-а нет, такой код работать не будет
K>Докажите, что он не будет там работать.
У меня нет под рукой сингулярити. Придется поверить так. Каждый new Cons<A>(...) согласно особенностям рантайма требует свой RuntimeType, а так же свои native реализации конструктора и метода scalarProduct. Хотя я не считаю себя специалистом по дотнет рантайму, но дотнет был моей основной специализацией с 2002-го года, и уверяю, мне неизвестно ни одного факта, позволяющего предполагать что Cons будет обходиться одной native реализацией своих методов и обходиться одним RuntimeType-ом во всех конкретизациях. Да, с List<T> одна реализация native методов прокатывает для всех reference типов T. Но это немного другое, там ни один метод List<T> не зависит от природы типа T (reference типа). А вот реализация scalarProduct — очень даже зависит.
Может в конце концов убедит то что у _main<A>, у scalarProduct от вызова к вызову разные MethodInfo?
public int scalarProduct(Cons<A> second)
{
Func<Cons<A>, int> f = scalarProduct;
return value * second.value + tail.scalarProduct(second.tail); //<-- set breakpoint here
}
Вот такой трюк позволяет убедиться в том, что f при различных <A> совершенно разные объекты. Очевидно, что одна и та же нативная реализация метода не позволит получать разные объекты.
K>>>И как быть с Java у которой в байт-коде нет ПП и, следовательно, нет смысла о JIT говорить? Как быть с хаскелем? S>>А никак не надо быть, мы ведь обсуждаем ПП ЯВУ а не байт-кода.
K>Так и я о том же. По вашему параметрические типы должны применятся в рантайме. Поэтому вы и обсуждаете компиляцию байткода в котором ПП есть. И только рантаймовую — возможность линктаймовой компиляции вы полностью игнорируете. В случае с C# лично для меня ситуация с рантаймом понятна, но вокруг нее столько всяких недопониманий и суеверий, что я просто сразу предлагаю: обсуждаем случаи, в которых никаких двусмысленностей нет: в Java и Haskell параметрические типы не могут применятся в рантайме в принципе потому, что в рантайме они не существуют.
K>>>Главный вопрос: как мы получаем ошибку компиляции C# за долго до того, как полиморфный код якобы скомпилируется в рантайме. S>>О какой конкретно ошибке речь?
K>Об ошибке, когда код генерирует неравные списки. Она возникает в компайл-тайм.
А с чего им быть неравными? Да и это доказано во время компиляции C#, что они будут равными. Так что я не вижу никакой ошибки компиляции, на вопрос ответить затрудняюсь, т.к. не понял его.
S>>Вообще-говоря, С# проверяет ограничения при компиляции в IL и получает гарантии что они не будут нарушены в рантайме. Если такая проверка обламывается, мы получаем ошибку времени компиляции в IL. Если нет — то в JIT все будет как по рельсам.
K>Т.е. вы хотите сказать, что система типов второго C# unsound, статически проверить безопасность компилятор не может.
Я такого не хочу сказать. Проверить безопасность компилятор может, и делает это. А вот конкретизирует типы и JIT-ит код методов в рантайме. Это я хочу сказать. K>Спорить с этим сложно, потому что благодаря таким мегафичам как ковариантность массивов и даункасты — так оно, собственно, и есть. С дженериками C# таких проблем, правда, нет, но мне проще обсудить полиморфизм на примере другого языка, чем вас в этом убедить.
В этом это в чем? В том что JIT не докомпиляет каждый вложенный вызов _main<A>/scalarProduct? Наверное на другом языке это будет сделать еще сложнее.
K>>>Нужно конкретизировать все до момента тайпчека, вы хотели сказать? S>>наверное
K>Ну, тоесть параметрических типов в C++ нет, а параметрический полиморфизм, по вашему, есть? Оригинально.
А кто сказал что должны существовать параметрические типы? Определение касается вообще куска кода и способа сделать его обобщенным. Так что, что шаблон, что макрос, могут удовлетворять определению.
Здравствуйте, samius, Вы писали:
S>А причем тут наличие/отсутствие ПП?
Вот как раз это я тут и объясняю в 128-и сообщениях. Без всякого толка, как видно.
S>Но тогда я вообще не понимаю, как пункт 2 относится к полиморфизму.
Первый пункт говорит про код. Второй — про типизацию этого кода. Если не рассматривать типизацию, как вы вообюще отличите параметрический полиморфизм от полиморфизма через сабтайпинг? Код и там и там однородный, только способы его типизировать отличаются.
S>Я ответил что вы сделали слишком сильные выводы из определения.
И в чем слишкомсильность их? Что существует тип forall a. Succ a? Ну а какой полиморфный код вы типизируете, если даже такой тип не существует?
S>Это в том случае, если использовать определение с википедии. Ну а то, на которое вы ссылаетесь — я не знаю, откуда оно взялось.
Это пересказ обределения из TAPL своими словами.
K>>И чем, по-вашему, это обоснование через "все возможные" программы отличается от вашего? S>Это важно? Имеет какое-то отношение к ПП?
Это имеет непосредственное отношение к обсуждаемой теме. Потому, что вы аргументируете таким способом (потенциальную) бесконечность типов. Если я применяю ваш способ неправильно — укажите мне в чем ошибка.
K>>2) Типизировать этот код обобщенным типом, содержащим переменные, которые конкретизируются применением обобщенного типа к конкретному. S>Вот это откуда? И можно разжевать, что значит обобщенный тип, содержащий переменные?
Вы же прямо из TAPL сюда куски текста копируете, значит доступ к тексту у вас есть. А там все разжевано.
S>
S>Parametric polymorphism,the topic of this chapter, allows a single piece of
S>code to be typed “generically,” using variables in place of actual types, and
S>then instantiated with particular types as needed.
S>И в этом нет ничего такого, что не позволил бы шаблон в C++.
Проще сказать, что из описаного шаблон бы позволил. Видите, тут написано, что обобщенный код сначала типизируется обобщенным типом. Шаблонный код не типизируется. И типизировать его нельзя — тогда часть выразительных возможностей шаблонов будет недоступна. Типизируемый код получается только после инстанциации.
S>Что вы здесь подразумеваете под "типизировать"?
Это и явный forall — не одно и то же. Мы вообще обсуждаем самый упрощенный вариант полиморфизма (ML-like) там возможен только полиморфизм ранга 1.
S>C# такое не умеет.
Haskell 98 на котором написан обсуждаемый код — тоже не умеет.
S>Нет, не обсудили. Вы не захотели обсуждать, на какую глубину применяются типы в компайл-тайме и чем занимается рантайм при введении значительной глубины структуры (например от 1000).
Я просто не вижу какое отношение это обсуждение деталей реализации к основной теме треда. И каким образом оно может быть продолжено. Допустим даже, что в C# все применяется в рантайме и т.д. — вывод-то какой из этого? Что для ПП нужна поддержка рантайма? Нет. Приведены примеры реализаций ПП без всякой рантайм-кодогенерации. Что в C++ есть ПП? Нет, эти два вопроса вообще никак не связаны.
K>>Так и я о том же. По вашему параметрические типы должны применятся в рантайме. Поэтому вы и обсуждаете компиляцию байткода в котором ПП есть. И только рантаймовую — возможность линктаймовой компиляции вы полностью игнорируете. В случае с C# лично для меня ситуация с рантаймом понятна, но вокруг нее столько всяких недопониманий и суеверий, что я просто сразу предлагаю: обсуждаем случаи, в которых никаких двусмысленностей нет: в Java и Haskell параметрические типы не могут применятся в рантайме в принципе потому, что в рантайме они не существуют.
Ну правильно, упоминания о реализациях без всякой поддержки рантайма вы опять проигнорировали.
K>>Об ошибке, когда код генерирует неравные списки. Она возникает в компайл-тайм. S>А с чего им быть неравными?
Ну, перепишите код функции так, чтоб она генерировала неравные списки. С того и будут. И будет ошибка компиляции.
K>>Т.е. вы хотите сказать, что система типов второго C# unsound, статически проверить безопасность компилятор не может. S>Я такого не хочу сказать. Проверить безопасность компилятор может, и делает это. А вот конкретизирует типы и JIT-ит код методов в рантайме. Это я хочу сказать.
Т.е. вы не утверждаете как остальные мои оппоненты тут, что проверка рантаймовая? В чем тогда суть вашего возражения?
S>В этом это в чем? В том что JIT не докомпиляет каждый вложенный вызов _main<A>/scalarProduct?
Нет, в том, что типобезопасность дженериков проверяется статически, а не в рантайме. К счастью, вас в этом убеждать и не требуется.
K>>Ну, тоесть параметрических типов в C++ нет, а параметрический полиморфизм, по вашему, есть? Оригинально. S>А кто сказал что должны существовать параметрические типы?
Я сказал. В определении параметрического полиморфизма так написано. Поэтому он и "параметрический" и отличается от других видов полиморфизма.
S>Определение касается вообще куска кода и способа сделать его обобщенным. Так что, что шаблон, что макрос, могут удовлетворять определению.
Не могут. Если вы определяете "параметрический полиморфизм" просто как однородный код, тогда под него подпадают и другие виды полиморфизма. Но не шаблоны и не макросы, потому что с их помощью писать однородный код нельзя.
... << RSDN@Home 1.2.0 alpha 4 rev. 1476>>
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Здравствуйте, Klapaucius, Вы писали:
K>Здравствуйте, samius, Вы писали:
S>>А причем тут наличие/отсутствие ПП?
K>Вот как раз это я тут и объясняю в 128-и сообщениях. Без всякого толка, как видно.
Да, заметно.
S>>Но тогда я вообще не понимаю, как пункт 2 относится к полиморфизму.
K>Первый пункт говорит про код. Второй — про типизацию этого кода. Если не рассматривать типизацию, как вы вообюще отличите параметрический полиморфизм от полиморфизма через сабтайпинг? Код и там и там однородный, только способы его типизировать отличаются.
ПП от СП я отличаю по определению (одного, другого). Ни то ни другое определение (в википедии, по крайней мере) не используют термин "типизация".
К вам, собственно встречный вопрос. Как вы их отличаете? Подод к вопросу тоже есть. Вы берете пример migmit-а, в котором задействованы bounded и subtype полиморфизмы, и утверждаете что ПП там нет в случае С++ и есть в случае C#.
S>>Я ответил что вы сделали слишком сильные выводы из определения.
K>И в чем слишкомсильность их? Что существует тип forall a. Succ a? Ну а какой полиморфный код вы типизируете, если даже такой тип не существует?
Я же не утверждаю что он не существует. Я утвреждаю что существование такого типа не связано с определением. Тем более, не очевидно существование такого типа в конкретной программе. А существование его в какой-то абстрактной программе — такая же софистика, как и существование бесконечного числа типов в бесконечном числе программ.
S>>Это в том случае, если использовать определение с википедии. Ну а то, на которое вы ссылаетесь — я не знаю, откуда оно взялось.
K>Это пересказ обределения из TAPL своими словами.
Обращу внимание, что в TAPL нет упоминания о типе, содержащем переменные.
K>>>И чем, по-вашему, это обоснование через "все возможные" программы отличается от вашего? S>>Это важно? Имеет какое-то отношение к ПП?
K>Это имеет непосредственное отношение к обсуждаемой теме. Потому, что вы аргументируете таким способом (потенциальную) бесконечность типов. Если я применяю ваш способ неправильно — укажите мне в чем ошибка.
Мой основной довод — это то, что бесконечность типов не требуется. Попытку представить бесконечность типов в бесконечности программ предлагаю игнорировать. Точно так же как и существование типа forall a. Succ a.
K>>>2) Типизировать этот код обобщенным типом, содержащим переменные, которые конкретизируются применением обобщенного типа к конкретному. S>>Вот это откуда? И можно разжевать, что значит обобщенный тип, содержащий переменные?
K>Вы же прямо из TAPL сюда куски текста копируете, значит доступ к тексту у вас есть. А там все разжевано.
А там об этом ничего нет. Там говорится об использовании переменных вместо actual types, а вовсе не о типах, содержащих переменные.
S>>
S>>Parametric polymorphism,the topic of this chapter, allows a single piece of
S>>code to be typed “generically,” using variables in place of actual types, and
S>>then instantiated with particular types as needed.
S>>И в этом нет ничего такого, что не позволил бы шаблон в C++.
K>Проще сказать, что из описаного шаблон бы позволил. Видите, тут написано, что обобщенный код сначала типизируется обобщенным типом. Шаблонный код не типизируется. И типизировать его нельзя — тогда часть выразительных возможностей шаблонов будет недоступна. Типизируемый код получается только после инстанциации.
Не согласен. Там написано что кусок кода типизируется "обобщенно", используя переменные вместо типов. И ничего о параметрических типах, кстати.
S>>Что вы здесь подразумеваете под "типизировать"?
K>Под "типизировать терм" я понимаю "классифицировать терм, задать (проверить) его принадлежность к какому-то определенному типу".
Я думаю, что если бы трактовка "typed generically" была бы именно такой, то в переводе это было бы как-то отражено. В переводе же "типизация" вообще куда-то пропала.
S>>C# такое не умеет.
K>Haskell 98 на котором написан обсуждаемый код — тоже не умеет.
Согласен. Тогда мы в с++ и C# имеем forall, который непонятно чем отличается от forall H98
S>>Нет, не обсудили. Вы не захотели обсуждать, на какую глубину применяются типы в компайл-тайме и чем занимается рантайм при введении значительной глубины структуры (например от 1000).
K>Я просто не вижу какое отношение это обсуждение деталей реализации к основной теме треда. И каким образом оно может быть продолжено. Допустим даже, что в C# все применяется в рантайме и т.д. — вывод-то какой из этого?
Я влез в эту тему что бы выяснить вашу позицию по поводу разграничения C++ и C# на тему присутствия в них ПП. Вы глядя на примеры migmit-а утверждаете что в С# ПП есть, а в С++ — нет. Вот мне и захотелось уточнить, почему вы так считаете. Аргументами была бесконечность типов. Теперь же выяснилось (или как минимум, допустилось), что C# своей потенциальной бесконечности типов обязан особенностям рантайма и без них пример migmit-а работать не будет.
K>Что для ПП нужна поддержка рантайма? Нет.
Согласен, в общем случае не нужна и для C# не нужна тоже. Поддержка рантайма нужна для работы примера migmit-а, связь которого с определением ПП туманна. Там ПП присутствует в форме bounded полиморфизма с замесом на subtype полиморфизм.
K>Приведены примеры реализаций ПП без всякой рантайм-кодогенерации. Что в C++ есть ПП? Нет, эти два вопроса вообще никак не связаны.
Да, приведены. В С++ ПП есть, но это действительно не связано с примерами ПП без рантайм-кодогенерации. Тем более, что в C++ этот ПП присутствует без всякой рантайм-кодогенерации.
K>>>Так и я о том же. По вашему параметрические типы должны применятся в рантайме. Поэтому вы и обсуждаете компиляцию байткода в котором ПП есть. И только рантаймовую — возможность линктаймовой компиляции вы полностью игнорируете. В случае с C# лично для меня ситуация с рантаймом понятна, но вокруг нее столько всяких недопониманий и суеверий, что я просто сразу предлагаю: обсуждаем случаи, в которых никаких двусмысленностей нет: в Java и Haskell параметрические типы не могут применятся в рантайме в принципе потому, что в рантайме они не существуют.
K>Ну правильно, упоминания о реализациях без всякой поддержки рантайма вы опять проигнорировали.
А что мне на них отвечать? Они есть, я с этим спорить не собирался. Да, то что ПП должны применяться в рантайме — я такого не утвреждал, если что. Утверждал я лишь то, что в примере migmit-а (и в моем тоже) типы в C# применяются в рантайме. Ни в коей мере это не является необходимым условием ПП.
S>>А с чего им быть неравными?
K>Ну, перепишите код функции так, чтоб она генерировала неравные списки. С того и будут. И будет ошибка компиляции.
А, без проблем. Только к какому выводу это приведет? В C++ тоже ведь будет ошибка компиляции.
K>>>Т.е. вы хотите сказать, что система типов второго C# unsound, статически проверить безопасность компилятор не может. S>>Я такого не хочу сказать. Проверить безопасность компилятор может, и делает это. А вот конкретизирует типы и JIT-ит код методов в рантайме. Это я хочу сказать.
K>Т.е. вы не утверждаете как остальные мои оппоненты тут, что проверка рантаймовая? В чем тогда суть вашего возражения?
Нет, не утверждаю. Но утверждать то, что в рантайме никаких проверок совсем нет — тоже не берусь. Наверняка есть.
Суть возражения была в том, что обсуждаемая фича в C# работает за счет рантайм конкретизации и кодогенерации. Без этих фич C# в отношении обсуждаемых примеров будет столь же бесполезен, как и C++. Разве что в C# мы сможем написать typeof(Cons<>), а в C++ нет.
S>>В этом это в чем? В том что JIT не докомпиляет каждый вложенный вызов _main<A>/scalarProduct?
K>Нет, в том, что типобезопасность дженериков проверяется статически, а не в рантайме. К счастью, вас в этом убеждать и не требуется.
Верно, не требуется. В обсуждаемых примерах она проверяется статически (как минимум, в том числе статически).
K>>>Ну, тоесть параметрических типов в C++ нет, а параметрический полиморфизм, по вашему, есть? Оригинально. S>>А кто сказал что должны существовать параметрические типы?
K>Я сказал. В определении параметрического полиморфизма так написано. Поэтому он и "параметрический" и отличается от других видов полиморфизма.
Нет, в определении такого не написано. Ни в википедии, ни в TAPL. "Параметрический" он потому, что параметризуется код (single piece of code), а не тип.
S>>Определение касается вообще куска кода и способа сделать его обобщенным. Так что, что шаблон, что макрос, могут удовлетворять определению.
K>Не могут. Если вы определяете "параметрический полиморфизм" просто как однородный код, тогда под него подпадают и другие виды полиморфизма.
Нет, другие виды полиморфизма отличаются своими определениями. Ключевые отличия:
ad-hoc — используется специальная информация о типах (специализация)
subtyping — тут есть 2 определения. а) работает для всех подтипов автоматически; б) для ООП полиморфизма — с возможностью специализации кода для некоторых типов за счет override.
bounded — гибрид ПП и subtyping-а, где на типы накладываютя ограничения в виде обещаний о присутствии каких-то атрибутов(конструкторов/методов/и даже полей).
K>Но не шаблоны и не макросы, потому что с их помощью писать однородный код нельзя.
как это?
#define ID x = (x)
template <class T> T id(const T& v) { return v; }
Разве такие определения не позволяют использовать их однородно для различных типов?
Здравствуйте, samius, Вы писали:
S>Не согласен. Там написано что кусок кода типизируется "обобщенно", используя переменные вместо типов. И ничего о параметрических типах, кстати.
Ну и как такое протипизировать:
template <class C, class T>
void foo(int x)
{
C<T>::template Foo<T>::typename Bar y;
y.Baz = x;
}
Можно потом SFINAE ещё подкрутить и попробовать протипизировать. Не инстанцированную конкретную функцию, а обобщённый шаблон.
Здравствуйте, VoidEx, Вы писали:
VE>Здравствуйте, samius, Вы писали:
S>>Не согласен. Там написано что кусок кода типизируется "обобщенно", используя переменные вместо типов. И ничего о параметрических типах, кстати.
VE>Ну и как такое протипизировать:
В TAPL написано "using variables in place of actual types".
VE>
VE>template <class C, class T>
VE>void foo(int x)
VE>{
VE> C<T>::template Foo<T>::typename Bar y;
VE> y.Baz = x;
VE>}
VE>
Т.е. оно уже typed "generically" согласно TAPL. Осталось лишь "and then instantiated with particular types as needed".
VE>Можно потом SFINAE ещё подкрутить и попробовать протипизировать. Не инстанцированную конкретную функцию, а обобщённый шаблон.
Не понятно, что значит попробовать протипизировать. Определение говорит о двух вещах:
1) использовать переменные вместо типов
2) инстанциировать с конкретными типами (подставить их вместо переменных).
Здравствуйте, samius, Вы писали:
VE>>Об этом же. Ставим C = int, T = float. Какой тип получился?
S>Фиговый какой-то. Но это же не повод обвинять C++ в отсутствии ПП! Мы ведь можем написать шаблон, который будет себе вполне соответствовать ПП.
Не фиговый, а нет такого типа, ошибка типизации, типизация не прошла. Типизация происходит только после подстановки. О чём и речь. Вы, конечно, можете написать такой шаблон, который при любом подставляемом типе таки стипизируется, но стипизируется он уже после.
Здравствуйте, VoidEx, Вы писали:
VE>Здравствуйте, samius, Вы писали:
VE>>>Об этом же. Ставим C = int, T = float. Какой тип получился?
S>>Фиговый какой-то. Но это же не повод обвинять C++ в отсутствии ПП! Мы ведь можем написать шаблон, который будет себе вполне соответствовать ПП.
VE>Не фиговый, а нет такого типа, ошибка типизации, типизация не прошла. Типизация происходит только после подстановки. О чём и речь. Вы, конечно, можете написать такой шаблон, который при любом подставляемом типе таки стипизируется, но стипизируется он уже после.
Что за "стипизируется"?
Пункт 1 — объявить переменные типов. Можно? Да. Язык C++ позволяет. Я не говорю о вашем примере. Я говорю о возможности.
Пункт 2 — подставить вместо переменных конкретные типы. Можно? Да.
А всякие там "до", "после", "стипизируется", "потенциальная бесконечность" — это уже спекуляции.
Здравствуйте, VoidEx, Вы писали:
VE>Здравствуйте, samius, Вы писали:
S>>Что за "стипизируется"?
VE>typed
S>>Пункт 1 — объявить переменные типов. Можно? Да. Язык C++ позволяет. Я не говорю о вашем примере. Я говорю о возможности.
VE>Не объявить, а be typed “generically,” using variables in place of actual types
Окей. В русской версии это выглядит как "давать участку кода “обобщенный” тип, используя переменные вместо настоящих типов".
S>>Пункт 2 — подставить вместо переменных конкретные типы. Можно? Да.
VE>Можно, но не всегда, ибо typed будет уже после подстановки, и может не сработать.
Никто же не утверждает что всегда, что любое использование шаблона есть ПП. Речь лишь о том, что ПП в C++ присутствует и _могут_ быть приведены примеры, где шаблон вполне соответствует определению ПП (которое не требует параметрических типов или бесконечностей типов в одной программе).
Здравствуйте, samius, Вы писали:
VE>>Не объявить, а be typed “generically,” using variables in place of actual types S>Окей. В русской версии это выглядит как "давать участку кода “обобщенный” тип, используя переменные вместо настоящих типов".
Но там нет типа. Там шаблон, а тип появляется после подстановки. И это ужасное C<T>::template Foo<T>::typename Bar превращается в MyStruct. А может и не превращается, и тогда получаем ошибку типизации.
VE>>Можно, но не всегда, ибо typed будет уже после подстановки, и может не сработать.
S>Никто же не утверждает что всегда, что любое использование шаблона есть ПП. Речь лишь о том, что ПП в C++ присутствует и _могут_ быть приведены примеры, где шаблон вполне соответствует определению ПП (которое не требует параметрических типов или бесконечностей типов в одной программе).
Здравствуйте, VoidEx, Вы писали:
VE>Здравствуйте, samius, Вы писали:
VE>>>Не объявить, а be typed “generically,” using variables in place of actual types S>>Окей. В русской версии это выглядит как "давать участку кода “обобщенный” тип, используя переменные вместо настоящих типов".
VE>Но там нет типа. Там шаблон, а тип появляется после подстановки. И это ужасное C<T>::template Foo<T>::typename Bar превращается в MyStruct. А может и не превращается, и тогда получаем ошибку типизации.
Если может превращается, а может и не превращается, то о каком ПП речь? ПП должен работать одинаково для всех типов. И если там для какого-то типа заложены знания что нечто ужасное превратится в MyStruct, а для другого не превратится, то это уже не ПП.
VE>>>Можно, но не всегда, ибо typed будет уже после подстановки, и может не сработать.
S>>Никто же не утверждает что всегда, что любое использование шаблона есть ПП. Речь лишь о том, что ПП в C++ присутствует и _могут_ быть приведены примеры, где шаблон вполне соответствует определению ПП (которое не требует параметрических типов или бесконечностей типов в одной программе).
VE>В таком смысле и в Си есть ПП VE>
VE>#define ID(x) x
VE>
В общем, кроме того что переменной типа не видно, других претензий в отношении определения ПП не могу предъявить. И сам уже писал что это является примером ПП, только скобочки забыл вокруг первого x.
Здравствуйте, samius, Вы писали:
S>ПП от СП я отличаю по определению (одного, другого). Ни то ни другое определение (в википедии, по крайней мере) не используют термин "типизация".
Но они только способом типизации однородного кода и отличаются.
S>К вам, собственно встречный вопрос. Как вы их отличаете?
Отличаю по способу типизации однородного кода. Другого-то способа нет.
S>Подод к вопросу тоже есть. Вы берете пример migmit-а, в котором задействованы bounded и subtype полиморфизмы, и утверждаете что ПП там нет в случае С++ и есть в случае C#.
То, что квантификация во всех примерах ограниченная я с самого начала говорил. Это ничего не меняет — кол-во "ограниченных" типов все равно бесконечно. Bounded-полиморфизм — это сочетание параметрического полиморфизма и сабтайпинга, т.е. наличие полноценного параметрического полиморфизма подразумевается. Никаких работающих примеров без ПП, например только subtype среди обсуждаемых нет.
S>Я же не утверждаю что он не существует. Я утвреждаю что существование такого типа не связано с определением. Тем более, не очевидно существование такого типа в конкретной программе.
Ну так тип объявлен в конкретной программе.
S>Обращу внимание, что в TAPL нет упоминания о типе, содержащем переменные.
Ну разумеется есть. Он процентов на 80 состоит из упоминаний "типа, содержащем переменные"
S>Мой основной довод — это то, что бесконечность типов не требуется. Попытку представить бесконечность типов в бесконечности программ предлагаю игнорировать.
Отлично.
S>Точно так же как и существование типа forall a. Succ a.
Т.е. в вашем определении ПП типизировать полиморфный код нельзя?
K>>Вы же прямо из TAPL сюда куски текста копируете, значит доступ к тексту у вас есть. А там все разжевано. S>А там об этом ничего нет.
Ну, это неправда.
S>Там говорится об использовании переменных вместо actual types, а вовсе не о типах, содержащих переменные.
Да ну, в главе о "типах, содержащих переменные" не говорится о "типах, содержащих переменные"?
S>Не согласен. Там написано что кусок кода типизируется "обобщенно", используя переменные вместо типов. И ничего о параметрических типах, кстати.
А что такое параметрические типы, по-вашему? Ну, скажу тогда, что шаблонный код "обобщенно, используя переменные вместо(?) типов". "Вместо типов" — вообще анекдот. не вместо типов вообще, а вместо конкретных типов. Переменная типа — это тип. Посмотрите, где семантика расписана переменные типа справа от ( — операции типизации.
S>Я думаю, что если бы трактовка "typed generically" была бы именно такой, то в переводе это было бы как-то отражено. В переводе же "типизация" вообще куда-то пропала.
Какой смысл рассуждать о том, сколько ангелов поместится на выдернутом из контекста абзаце, когда в его непосредственной окресности совершщенноь ясно описывается, с примерами и что такое тип и что такое типизировать и вообще все остальное, что вы сейчас выводите из каких-то странных предположений о переносе смысла при переводе.
S>Тогда мы в с++ и C# имеем forall, который непонятно чем отличается от forall H98
Нету в C++ квантора всеобности, о чем и разговор.
S>Я влез в эту тему что бы выяснить вашу позицию по поводу разграничения C++ и C# на тему присутствия в них ПП. Вы глядя на примеры migmit-а утверждаете что в С# ПП есть, а в С++ — нет. Вот мне и захотелось уточнить, почему вы так считаете.
Потому, что код, написанный, исходя из предположения, что полиморфизм в C# параметрический работает так же, как и в других языках с параметрическим полиморфизмом и в соотвествии с теорией, построеной на свойствах параметрического полиморфизма. С другой стороны, код, написанный, исходя из предположения, что полиморфизм в C++ параметрический не работает так же, как и в других языках с параметрическим полиморфизмом и не соотвествует теории, построеной на свойствах параметрического полиморфизма.
S>Аргументами была бесконечность типов. Теперь же выяснилось (или как минимум, допустилось), что C# своей потенциальной бесконечности типов обязан особенностям рантайма и без них пример migmit-а работать не будет.
Т.е. в каком-то гипотетическом рантайме гипотетического языка (который C# не является потому, что у него другая система типов и семантика) может не быть параметрического полиморфизма. Какой из этого следует вывод?
S>Согласен, в общем случае не нужна и для C# не нужна тоже. Поддержка рантайма нужна для работы примера migmit-а, связь которого с определением ПП туманна. Там ПП присутствует в форме bounded полиморфизма с замесом на subtype полиморфизм.
Ну а на Хаскеле пример работает без поддержки рантайма. Ну так что, нужна поддержка рантайма для этого или нет?
K>>Приведены примеры реализаций ПП без всякой рантайм-кодогенерации. Что в C++ есть ПП? Нет, эти два вопроса вообще никак не связаны. S>Да, приведены. В С++ ПП есть, но это действительно не связано с примерами ПП без рантайм-кодогенерации. Тем более, что в C++ этот ПП присутствует без всякой рантайм-кодогенерации.
Ну, если определять ПП как "что-то, что есть в C++" тогда да.
S>А что мне на них отвечать? Они есть, я с этим спорить не собирался. Да, то что ПП должны применяться в рантайме — я такого не утвреждал, если что. Утверждал я лишь то, что в примере migmit-а (и в моем тоже) типы в C# применяются в рантайме.
Применение типов в рантайме в C# отличается от применения в компайл-тайме синтаксически:
Перепутать их никак невозможно. Кроме того, если бы типы применялись в рантайме — тайпчекер не смог бы проверить их. "Код генерируется в рантайме" — это не то же самое, что и "Типы применяются в рантайме".
K>>Ну, перепишите код функции так, чтоб она генерировала неравные списки. С того и будут. И будет ошибка компиляции. S>А, без проблем. Только к какому выводу это приведет? В C++ тоже ведь будет ошибка компиляции.
На C++ не написать код, который правильно работает.
S>Суть возражения была в том, что обсуждаемая фича в C# работает за счет рантайм конкретизации и кодогенерации. Без этих фич C# в отношении обсуждаемых примеров будет столь же бесполезен, как и C++.
Именно в C# фича работает, потому что он компилируется в байткод с ПП. Что и где там потом генерируется из совсем другого языка к делу отношения не имеет.
K>>Я сказал. В определении параметрического полиморфизма так написано. Поэтому он и "параметрический" и отличается от других видов полиморфизма. S>Нет, в определении такого не написано. Ни в википедии, ни в TAPL.
В TAPL совершенно точно написано. Определение в википедии не читал.
S>"Параметрический" он потому, что параметризуется код (single piece of code), а не тип.
Чем код-то параметризуется?
S>>>Определение касается вообще куска кода и способа сделать его обобщенным. Так что, что шаблон, что макрос, могут удовлетворять определению.
S>Нет, другие виды полиморфизма отличаются своими определениями. Ключевые отличия: S>subtyping — тут есть 2 определения. а) работает для всех подтипов автоматически;
Здравствуйте, samius, Вы писали:
VE>>Но там нет типа. Там шаблон, а тип появляется после подстановки. И это ужасное C<T>::template Foo<T>::typename Bar превращается в MyStruct. А может и не превращается, и тогда получаем ошибку типизации. S>Если может превращается, а может и не превращается, то о каком ПП речь? ПП должен работать одинаково для всех типов. И если там для какого-то типа заложены знания что нечто ужасное превратится в MyStruct, а для другого не превратится, то это уже не ПП.
Здравствуйте, Klapaucius, Вы писали:
K>То, что квантификация во всех примерах ограниченная я с самого начала говорил. Это ничего не меняет — кол-во "ограниченных" типов все равно бесконечно. Bounded-полиморфизм — это сочетание параметрического полиморфизма и сабтайпинга, т.е. наличие полноценного параметрического полиморфизма подразумевается. Никаких работающих примеров без ПП, например только subtype среди обсуждаемых нет.