Здравствуйте, Sinclair, Вы писали:
EP>>Видимо для реализации любой вычислимой функции. EP>>Но согласен, не для каждой задачи нужна полнота — тем не менее, аналог while есть практически в каждом современном языке, а соответственно "можно делать плохие вещи". S>Повторюсь: далеко не всякий аналог while даёт нам возможность "делать плохие вещи".
Тогда это не полный аналог while, а замена только для некоторых его аспектов.
И если в языке нет возможности "делать плохие вещи" — то он не будет являться полным по Тьюрингу. Безусловно такие языки(например) имеют свои области применения, но это далеко не мэйнстрим.
Re[38]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>>>Практически основной use-case. Посмотри хотя бы на типичную реализацию Dispose. I>>Что я должен там увидеть ?
EP>Совпадение времени жизни ресурса с временем жизни объекта.
Там точно этого не увидишь
EP>>>1. Основной use case — scoped lifetime: в C++ нет каскада правок, в C# — есть. I>>Не так — в C# каскадные правки нужны только тогда, когда добавляется интерфейс.
EP>И что это меняет?
Буквально всё — и в С++ и в С# каскадные правки в основном вылазят там, где класс меняет обязанности. Как правило новый класс нужно использовать немного иначе, что очевидно, а часто радикально иначе, например нужно выбрать правильный момент открытия ресурса а бывает еще и с закрытием надо постараться.
I>>В С++ если объект становится ресурсом, далеко не факт, что использовать его можно точно так же , как и раньше.
EP>Это не факт только в особо маргинальных случаях, часто и так являющимися undefined behavior.
Вот бы узнать, что это за особо маргинальные случаи
Re[39]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
EP>>>>1. Основной use case — scoped lifetime: в C++ нет каскада правок, в C# — есть. I>>>Не так — в C# каскадные правки нужны только тогда, когда добавляется интерфейс. EP>>И что это меняет? I>Буквально всё — и в С++ и в С# каскадные правки в основном вылазят там, где класс меняет обязанности.
Обязанности те же самые — изменилась только реализация, private секция.
I>Как правило новый класс нужно использовать немного иначе, что очевидно, а часто радикально иначе, например нужно выбрать правильный момент открытия ресурса а бывает еще и с закрытием надо постараться.
Подавляющее большинство ресурсов успешно вписывается в схему constructor-acquire destructor-release.
I>>>В С++ если объект становится ресурсом, далеко не факт, что использовать его можно точно так же , как и раньше. EP>>Это не факт только в особо маргинальных случаях, часто и так являющимися undefined behavior. I>Вот бы узнать, что это за особо маргинальные случаи
Например, если при удалении всего pool'а не вызывается каждый деструктор, а просто освобождается вся память, с расчётом на то, что там нет ресурсов кроме памяти.
Re[40]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
I>>Буквально всё — и в С++ и в С# каскадные правки в основном вылазят там, где класс меняет обязанности.
EP>Обязанности те же самые — изменилась только реализация, private секция.
Правильно понимаю, запись в файл и её отсутствие это одно и то же ? Непонятно.
I>>Как правило новый класс нужно использовать немного иначе, что очевидно, а часто радикально иначе, например нужно выбрать правильный момент открытия ресурса а бывает еще и с закрытием надо постараться.
EP>Подавляющее большинство ресурсов успешно вписывается в схему constructor-acquire destructor-release.
А большинство не-ресурсов используется как попало. Вот вставил ты файловый ресурс в такой объект и вот фокус — объект инстанцируется в изолированом контексе и файловые операции будут фейлиться если только не вызваны в определенный момент времени. Опаньки ! Все такие вызовы
Re[46]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Тогда это не полный аналог while, а замена только для некоторых его аспектов. EP>И если в языке нет возможности "делать плохие вещи" — то он не будет являться полным по Тьюрингу. Безусловно такие языки(например) имеют свои области применения, но это далеко не мэйнстрим.
Снова повторюсь: какая конкретно полезная функциональность недоступна вам при отсутствии полноты по Тьюрингу (или при отсутствии бесконечных циклов)?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[65]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Базовый способ записи алгоритмов — (псевдо)код. Не сталкивался с записыванием алгоритмов с помощью диаграмм даже самыми яростными фанатами UML. По моему, такой ерундой только школьные учителя лет 20 назад страдали.
Ну да, ну да) И гугл вот тоже выдаёт исключительно псевдокод по запросу на "алгоритм". )))
K>Во-первых, непонятно, почему только типов и все. В ФЯ бывают системы модулей, например.
Модули — это уже другая uml диаграммка, как раз та, про которую я сказал, что чуть ли не единственная нормально применимая в чистом ФП. И это инструмент совсем другого уровня детализации.
K>Во-вторых, мне непонятно противопоставление "всего-навсего типов" и "ого-го всей архитектуры".
Намекаю: где на диаграмме можно увидеть полный набор функций проектируемой программы и их взаимодействие между собой?
K>Надо продолжать, ничего не понятно. Что не так с инкапсуляцией, например?
Нууу её в Хаскеле просто нет. )))
K>Как мы знаем из книги "Физики шутят", "очевидно, что ..." означает "я этого не проверял, но ...".
И тем не менее физики обычно знают о чём говорят, в отличие от вас. )
K>Ваши повторы не помогают потому, что они состоят сначала из анонсов: "вот скоро покажу", "вот сейчас", "близится демонстрация ужасов ужасных" K>Потом происходит резкий переход к воспоминаниям: "как мы уже видели", "не раз показано", "повторяю и повторяю". K>При этом самое главное звено — собственно демонстрация — обычно вовсе выпадает. K>Справедливости ради, один раз вы все-таки попытались продемонстрировать конкретные ужасы, только это не удалось, теперь остается только уверять, что они там были.
Я вот всё думал, что мне напоминает эта наша дискуссия... Так это же в точности диалоги с киевлянами с политической ветки в последние месяцы. Прямо идеальное соответствие наблюдается:
— а у вас там нацики! (а в Хаскеле код становится ужасным на императивных задачах!)
— ничего подобного (...)
— а вот же ролики на ютубе с ними (вот же примеры кода с ужасом)
— да это не нацики; а даже если и нацики, их мало и они не во власти; а даже если и много и во власти, то значит так надо, чтобы победить бандитов и защититься от агрессии соседей. (да нет там ужасов в монадном коде; а даже если если и есть, то совсем немного и в редких случаях; а даже если и не в редких, то всё равно это всё компенсируется красотой кода в других местах).
В политической ветки все подобные дискуссии естественно ничем полезным не кончались. И я почем-то не сомневаюсь, что данная наша дискуссия завершится точно так же. )))
K>Я согласен с тем, что вы не единственный носитель такого парадоксального подхода. Логика же тут явно неочевидна, потому, что язык для определенной области это не GPL, а DSL.
И снова прямое передёргивание. Я говорил, что языки "хороши в какой-то определённой области", а не созданы исключительно для неё.
K>Также ваши воззрения не связаны с реальностью (пардон май френч) в которой языки программирования общего назначения существуют и применяются в широком спектре несхожих областей, часто очень далеких от области с которой началось распространение.
Не вижу никаких противоречий с моими высказываниями (оригинальными, а не "доработанными")...
_>>1. А причём тут логарифм? С чего вы взяли, что сравнение должно быть в логарифмах? K>Обратите внимание на шкалы графика. Видите там 1e+0, 1e+1, 1e+2 ?
Причём тут вообще график то? Я говорю про данные для него, которые там везде указаны.
K>Хорошая корреляция. В современном рейтинге ее не считают, но это же по графику видно, что хорошая. Впрочем, создается ощущение, что вы просматриваете страницу в текстовом браузере и графика не видите вовсе. Это объясняет и ваши загадочные утверждения о том, что они видимо что-то неверно посчитали, потому что у них процентный рейтинг только от СО зависит, хотя если посмотреть на график причина очевидна. K>Для тех, кто заказывает интернет страницы по телетайпу, я даже могу пересказать в общих чертах: дело в том, что на оси гитхаба мы видим в правой части шкалы 1e+10, а в верхней части шкалы СО — только 1e+5. Это означает, что строки на гитхабе растут гораздо быстрее вопросов на СО. Рассмотрим простой пример: На языке Сартр написана одна строчка на гитхабе, а на языке Антракс 10000 строк. При этом про Сартр спросили на СО 1 раз, а про Антракс — 100 раз. Получается, что доля Сартра на гитхабе примерно 1e-3%, а доля Антракса на гитхабе примерно 99.99%. Зато на СО у Сартра примерно 0.99%, а у Антракса только примерно 99.01%. Посчитаем среднее: для Сартра это ~ 0.5%, а для Антракса ~ 99.5%. Легко видеть, что рейтинг по такому агрегату будет существенно сильнее похож на более медленно растущий СО-рейтинг, чем на быстрый гитхаб-рейтинг. По хорошему говоря, агрегировать такие рейтинги нужно с соответствующим поправочным к-том, хотя посчитано все правильно (но зря). К счастью, есть график и процентный агрегированный рейтинг не нужен.
Очаровательные рассуждения) Только проведены они совсем не для тех данных, которые вызывают сомнения... В данном случае то проблем нет. А вот что у нас получается для расклада: Сартр написана одна строчка на гитхабе и 100 вопросов на СО, а на языке Антракс 10000 строк на гитхабе и 1 вопрос на СО? Если посчитано честное среднее, то оба языка будут рядом в рейтинге. Однако рейтинг данных товарищей для подобных случаев однозначно показывает преимущество Сартра...
K>Вы видимо забыли, с чего начался разговор о рейтинге. Вы противопоставили популярности хаскеля и го, а из рейтингов следует, что это маргинальные языки с неотличимой популярностью (точнее, без оной).
С этим никто и не спорит. Дискуссия о рейтингах является отдельной темой, а не попыткой назвать язык Го популярным (кстати, лично мне данный язык не особо симпатичен).
K>Ну так компилятор позволяет проаннотировать функцию pure не аннотируя входные данные как immutable. Т.е. то, что он проверяет к чистоте никакого отношения не имеет. Это некоторое свойство, придуманное авторами D непонятно что значащее.
Совершенно верно. И данной свойство является чем-то вроде аналитического продолжения классического понятия чистоты на мутабельные данные. Т.к. в случае иммутабельных данных имеем полное соответствие с чистотой из Хаскеля.
_>>оно позволяет использовать некоторые бонусы чистых функций и для полностью императивного кода. K>Например?
Гарантию отсутствия побочных эффектов. Т.е. помощь на уровне дизайна. Что-то вроде модификатора const из C++, только на другом уровне абстракции.
K>Задача заключается в проверке "поддержки иммутабельности" в языке, посредством создания как можно большего числа промежуточных значений в виде иммутабельных структур данных таким образом, чтоб часть из них можно было выкинуть за ненадобностью, а часть нет. Т.е. есть работа как для компилятора (устраняющего ненужные промежуточные значения), так и рантайма, которому есть что быстро размещать в памяти и, к примеру, переписывать по месту.
Ну так это получается тест не на поддержку иммутабельности, а на скорость GC и т.п. Т.е. я не вижу разницы в подобном тесте для мутабельных и для иммутабельных данных, т.к. непонятно какие оптимизации может тут добавить компилятор для иммутабельных данных — пересоздание структур будет происходить в любом случае и будет занимать основное время.
K>Решается эта задача, вычислением простых чисел тупым методом. K>primes — иммутабельный односвязный список простых чисел (помещающихся в Int32 для простоты реализации в D), упорядоченный по возрастанию, которые получаются из списка нечетных чисел начиная с 5, отфильтрованных функцией isPrime и присоединенных к этому списку в начале чисел 2 и 3 K>isPrime — функция, проверяющая, является ли число простым проверкой его делимости на простые числа из списка primes, квадраты которых меньше либо равны проверяемому числу. K>main — основная функция, которая отбирает из списка простых чисел те, что меньше 2 в 24-ой степени, считает их количество и выводит его в консоль. K>дальше следуют реализации аналогов стандартных функций для работы со списками, реализованных через другие функции для работы со списками.
Задачка понятна, но не ясно где в ней логично использовать иммутабельные данные. Очевидно же, что тут как раз явный пример задачи оптимально решаемой с мутабельными данными. Собственно сам факт захвата 16 гигов оперативки однозначно свидетельствует о чудовищной не оптимальности подхода с иммутабельными данными.
K>От вас я ожидаю решения той же задачи на D максимально приближенным способом, чтоб оценивать одно и то же, и/или какие-то поправки для моего кода, которые позволили бы приблизится к чему-то среднему между нашими вариантами, если мой нельзя воспроизвести на D.
Нечто отдалённо похожее записывается на D вообще в одну строчку:
Этот код не отжирает память вообще и при этом работает несколько секунд. Но это работа с мутабельными данными.
Если же очень хочется устроить тестирование GC в D, то для этого достаточно заменить "~=" на "~" в коде выше — получим постоянные создания новых структур. Но, т.к. реализация GC в D совсем другая, то и последствия другие — память опять же не будет отжираться, а вот быстродействие существенно упадёт.
Re[66]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>И гугл вот тоже выдаёт исключительно псевдокод по запросу на "алгоритм". )))
Гугл, разумеется, много чего выдаст на эту тему, но на практике я никогда не сталкивался со сколько-нибудь масштабным использованием UML-диаграмм для записи алгоритмов, что не может не радовать.
_>Модули — это уже другая uml диаграммка, как раз та, про которую я сказал, что чуть ли не единственная нормально применимая в чистом ФП. И это инструмент совсем другого уровня детализации.
Нет, модули в ФЯ это инструмент как раз того же уровня детализации, как и классы в ООЯ. На вашу "уже другую UML диаграмму" они не ложатся.
K>>Во-вторых, мне непонятно противопоставление "всего-навсего типов" и "ого-го всей архитектуры". _>Намекаю: где на диаграмме можно увидеть полный набор функций проектируемой программы и их взаимодействие между собой?
Не понял намека. Вы не намекайте, а прямо скажите, в чем в данном случае разница.
_>Нууу её в Хаскеле просто нет. )))
Правда что-ли? В вашем воображаемом хаскеле чего не возьми — ничего нет.
Но в реально существующем хаскеле ситуация другая.
_>И тем не менее физики обычно знают о чём говорят, в отличие от вас. )
А при чем тут я? Очевидными-то сейчас вы называете всякие потусторонние вещи, которые процитировать нельзя, на которые сослаться нельзя. Про них можно только подмигивать и улыбаться.
_>Я вот всё думал, что мне напоминает эта наша дискуссия...
Вы, конечно, искрометно спародировали сейчас ход нашей дискуссии.
— Покажите монадные ужасы.
— Дискутировал я как-то про Украину...
Смех смехом, но вы обычно, конечно, съезжаете с темы не так далеко.
Впрочем, есть идея: если в разговоре про мифические монадные ужасы вы про Украину пишете — не исключено, что когда с вами про Украину дискутируют — вы приводите кучу ссылок на монадные ужасы и множество примеров кода. Надо будет проверить ваши посты в политике, заодно и недоумевающих оттуда сюда перенаправлю. А то они бедняжки, наверняка, никак не могут понять — при чем же тут монады.
_>И снова прямое передёргивание. Я говорил, что языки "хороши в какой-то определённой области", а не созданы исключительно для неё.
Тут как раз разница минимальна. "хороши" / "созданы для". Принципиальная разница между вашей "определенной областью" и моим "широким спектром областей с кое-какими исключениями". У языков общего назначения "определенной области" нет. Не удивительно, что на мой вопрос об "определенной области" для C++ вы ничего не ответили.
_>Причём тут вообще график то? Я говорю про данные для него, которые там везде указаны.
ОК, посмотрите на данные (кол-ва измененных строк и заданных вопросов) и посмотрите сколько их у одних языков и у других. И представьте их в виде точек на графике у которого шкалы не логарифмические. Теперь понятно причём тут логарифм?
_>Очаровательные рассуждения) Только проведены они совсем не для тех данных, которые вызывают сомнения...
Да какая разница, действие эффекта от этого не изменится.
_>В данном случае то проблем нет.
Отлично.
_>А вот что у нас получается для расклада: Сартр написана одна строчка на гитхабе и 100 вопросов на СО, а на языке Антракс 10000 строк на гитхабе и 1 вопрос на СО? Если посчитано честное среднее, то оба языка будут рядом в рейтинге.
Но они не окажутся рядом на графике. И вообще вблизи линии тренда. Т.е. по одному взгляду на график будет видно: с ними что-то не то, это "выбросы". Впрочем, на том же графике видно, что такое случается либо с совсем уже редкими языками — это облако точек в нижней левой части, либо вообще не языками программирования вроде XML — один из немногих "выбросов" в верхней правой части графика.
_>Однако рейтинг данных товарищей для подобных случаев однозначно показывает преимущество Сартра...
Ну так и даже понятно почему. Поэтому я уже в 256 предыдущих сообщениях писал — рейтинг с процентами не нужен — смотрите на график.
_>Совершенно верно. И данной свойство является чем-то вроде аналитического продолжения классического понятия чистоты на мутабельные данные.
А смысл в этом какой? Ну "продолжили" мы чистоту до ее отсутствия, теперь проверяем что-то чистотой функции не являющееся. Дальше-то что? В чем отличие от ситуации, когда мы это странное "продолжение" не проверяем?
_>Т.к. в случае иммутабельных данных имеем полное соответствие с чистотой из Хаскеля.
Ну да. Только компилятор позволяет аннотировать pure и в тех случаях, когда данные мутабельны. Или нет?
_>Гарантию отсутствия побочных эффектов.
Но ведь этой гарантии нет. Если бы проверялась иммутабельность — она бы была. Но иммутабельность не проверяется.
_>Ну так это получается тест не на поддержку иммутабельности, а на скорость GC и т.п.
Ну, правильно. Поддержка иммутабельности заключается в:
1) Проверки компилятора. (как уже выяснилось, что-то проверяется, да только не то)
2) Поддержка рантайма. А это процентов на 90% скорость GC, остальное — всякая экзотика.
3) Оптимизации компилятора — т.е. выкидывание ненужных аллокаций, для которых мы можем статическим анализом ненужность определить.
Поэтому тест на поддержку иммутабельности — это "на скорость GC и т.п.". А что он по-вашему должен проверять?
_>Т.е. я не вижу разницы в подобном тесте для мутабельных и для иммутабельных данных, т.к. непонятно какие оптимизации может тут добавить компилятор для иммутабельных данных — пересоздание структур будет происходить в любом случае и будет занимать основное время.
Оптимизации компилятор может добавить — это например дефорестация и эскейп-анализ. Я же говорю, при выключенных оптимизациях и при включенных время работы и объемы аллокаций отличаются в десятки раз.
_>Задачка понятна, но не ясно где в ней логично использовать иммутабельные данные.
Иммутабельные данные в ней логично использовать везде. Потому, что мы проверяем поддержку иммутабельных данных. Было бы странно испытывать поддержку иммутабельных, а использовать мутабельные, нес па?
_>Собственно сам факт захвата 16 гигов оперативки однозначно свидетельствует о чудовищной не оптимальности подхода с иммутабельными данными.
Нет никакого захвата 16 гигов оперативки. Есть размещение 16 Гб объектов в куче. Не одновременно, а последовательно. Одновременно в памяти не больше 16 Мб.
_>Нечто отдалённо похожее записывается на D вообще в одну строчку: _>
У вас тут смешивается "библиотечная" часть, которая простые числа считает и "пользовательская", которая знает что вам нужны только те, что не больше 2^^24
_>Этот код не отжирает память вообще
В астрале что-ли простые числа хранит?
_>и при этом работает несколько секунд.
Нормально. И мой пример несколько секунд работает.
_>Но это работа с мутабельными данными.
Ну так сделайте такой, который работает с иммутабельными данными.
_>для этого достаточно заменить "~=" на "~" в коде выше
Сильно сомневаюсь в этом. Что, диапазоны/итераторы/или что там в D, которые тут для организации конвейера использованы — иммутабельные?
_>Но, т.к. реализация GC в D совсем другая, то и последствия другие — память опять же не будет отжираться,а вот быстродействие существенно упадёт.
Ну, то есть иммутабельность в D не поддерживается. Что и требовалось доказать.
'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
Re[66]: Есть ли вещи, которые вы прницпиально не понимаете...
_>Этот код не отжирает память вообще и при этом работает несколько секунд. Но это работа с мутабельными данными.
Этот вариант выдает неверный ответ — на 1 меньше, т.к. забыл простое число "2". Я добавил двойку к тройке (скорость заметно упала при этом, т.к. больше ненужных делений делается), сравнил:
Glasgow Haskell Compiler, Version 7.6.3, stage 2 booted by GHC version 7.6.3
$ ghc prs.hs -o prs -O2
$ time ./prs
1077871
real 0m16.089s
user 0m15.980s
sys 0m0.076s
-------------------------------------------------------------------------------
DMD64 D Compiler v2.065
$ dmd prs.d -ofprsd -O -release -inline
$ time ./prsd
1077871
real 0m9.370s
user 0m9.352s
sys 0m0.000s
Сперва в DMD забыл указать -inline, получилось 19 с лишним секунд — медленнее однопоточного хаскеля.
Если вариант на хаскеле собрать с -threaded (многопоточный рантайм) и запустить с +RTS -N4 -RTS, работает вдвое дольше (32 с), а если с -N2, то всего на секунду дольше (17.3 с). Чудеса автопараллелизма!
Re[67]: Есть ли вещи, которые вы прницпиально не понимаете...
Если в хаскельном варианте заменить самописные filter, all, takeWhile на стандартные библиотечные, работает 18.5 секунд, т.е. процентов на 10 медленнее.
Re[67]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Гугл, разумеется, много чего выдаст на эту тему, но на практике я никогда не сталкивался со сколько-нибудь масштабным использованием UML-диаграмм для записи алгоритмов, что не может не радовать.
Подчёркиваю: запрос был не на слово "диаграмма", а на слово "алгоритм"...
K>Нет, модули в ФЯ это инструмент как раз того же уровня детализации, как и классы в ООЯ. На вашу "уже другую UML диаграмму" они не ложатся.
Ну так это в ФЯ, а в uml диаграмма пакетов выглядит совсем по другому и служит для других целей. Т.е. собственно как я и говорил, для ФЯ uml подходит слабо.
K>Не понял намека. Вы не намекайте, а прямо скажите, в чем в данном случае разница.
Я вроде бы достаточно точно сформулировал: где на диаграмме можно увидеть полный набор функций и их взаимодействие между собой? Ведь в ФП именно это во многом задаёт архитектуру приложения.
K>Правда что-ли? В вашем воображаемом хаскеле чего не возьми — ничего нет. K>Но в реально существующем хаскеле ситуация другая.
Ну так тогда наверное можно посмотреть на примеры инкапсуляции? )
K>Тут как раз разница минимальна. "хороши" / "созданы для". Принципиальная разница между вашей "определенной областью" и моим "широким спектром областей с кое-какими исключениями". У языков общего назначения "определенной области" нет. Не удивительно, что на мой вопрос об "определенной области" для C++ вы ничего не ответили.
Повторюсь ещё раз. У C++ (как и у других ему подобных), есть область, в которой он очевидный лидер. Плюс его можно вполне эффективно использовать во многих других областях, но там у него будут сильные конкуренты, использование которых часто более оправдано.
K>ОК, посмотрите на данные (кол-ва измененных строк и заданных вопросов) и посмотрите сколько их у одних языков и у других. И представьте их в виде точек на графике у которого шкалы не логарифмические. Теперь понятно причём тут логарифм?
Мне всегда было очевидно почему так построен график — для удобства просмотра. Но мне не понятно с каких это оснований мы должны в анализе использовать логарифмы.
K>Но они не окажутся рядом на графике. И вообще вблизи линии тренда. Т.е. по одному взгляду на график будет видно: с ними что-то не то, это "выбросы". Впрочем, на том же графике видно, что такое случается либо с совсем уже редкими языками — это облако точек в нижней левой части, либо вообще не языками программирования вроде XML — один из немногих "выбросов" в верхней правой части графика.
C и скажем C# как раз являются примером подобных данных, разве что не настолько контрастных (хотя на мой взгляд "в 5 раз" — это очень не слабо). Совсем не редкие или ненормальные языки.
K>Ну так и даже понятно почему. Поэтому я уже в 256 предыдущих сообщениях писал — рейтинг с процентами не нужен — смотрите на график.
Ну хотя бы в одном мы пришли к общему мнению: рейтинг языков от данных товарищей является фуфлом.
K>А смысл в этом какой? Ну "продолжили" мы чистоту до ее отсутствия, теперь проверяем что-то чистотой функции не являющееся. Дальше-то что? В чем отличие от ситуации, когда мы это странное "продолжение" не проверяем?
Я ответил на это ещё в предыдущем сообщение (чуть ниже цитируемого).
K>Ну да. Только компилятор позволяет аннотировать pure и в тех случаях, когда данные мутабельны. Или нет?
Естественно позволяет, иначе не получилось бы продолжение. ) Но и хаскелевскую чистоту мы получаем в D одним движением руки.
K>Но ведь этой гарантии нет. Если бы проверялась иммутабельность — она бы была. Но иммутабельность не проверяется.
А какие побочные эффекты возможны с мутабельными параметрами? )
K>Ну, правильно. Поддержка иммутабельности заключается в: K>1) Проверки компилятора. (как уже выяснилось, что-то проверяется, да только не то)
Ээээм, вроде как претензии были к модификатору pure, а не к модификатору immutable. Или уже и к нему что-то нашлось? )))
K>2) Поддержка рантайма. А это процентов на 90% скорость GC, остальное — всякая экзотика.
Ну скорость GC конечно тоже можно померять (хотя лично я, кодируя в стиле C++, обычно не особо использую GC и в D)... Только тогда это прямо так и надо называть. А не говорить про "тестирование иммутабельности". Потому как последнее означает сравнение скорости с данным модификатором или без него (но в любом случае с GC), а не сравнение насилования GC против нормального кода.
K>3) Оптимизации компилятора — т.е. выкидывание ненужных аллокаций, для которых мы можем статическим анализом ненужность определить.
Работа в статике у D думаю одна из самых сильных вообще. Хотя это сделано для несколько других целей. )
K>Поэтому тест на поддержку иммутабельности — это "на скорость GC и т.п.". А что он по-вашему должен проверять?
В случае D это должно быть что-то связанное именно с этим модификатором. Потому как GC используется и с мутабельными данными.
K>Иммутабельные данные в ней логично использовать везде. Потому, что мы проверяем поддержку иммутабельных данных. Было бы странно испытывать поддержку иммутабельных, а использовать мутабельные, нес па?
Да, но тестовый пример же мы сами выбираем и логично выбрать такой, в котором использование иммутабельных данных будет не искусственно введённой ересью, а чем-то приносящим реальную пользу. В данном случае на код насилующий память попусту просто противно смотреть.
K>Нет никакого захвата 16 гигов оперативки. Есть размещение 16 Гб объектов в куче. Не одновременно, а последовательно. Одновременно в памяти не больше 16 Мб.
А, ну значит я неправильно понял. Собственно я так и думал, что не может быть настолько всё плохо и где-то нестыковка.
_>>для этого достаточно заменить "~=" на "~" в коде выше K>Сильно сомневаюсь в этом. Что, диапазоны/итераторы/или что там в D, которые тут для организации конвейера использованы — иммутабельные?
Нет, не иммутабельные, хотя это тоже тривиально добавляется (просто модификатор к начальному списку, а остальное всё автоматом через шаблоны). Просто здесь мы включаем насилие над GC (постоянное пересоздание структур), в то время как код с "~=" производит модификацию одной начальной структуры и соответственно GC практически не напрягается.
K>Ну, то есть иммутабельность в D не поддерживается. Что и требовалось доказать.
Хы, т.е. не поддерживается — это означает что код насилующий GC отстаёт от кода не делающего этого? ) Ну так в таком случае в Хаскеле иммутабельность тоже не поддерживается, т.к. его код тоже отстаёт от варианта не насилующего GC.
Re[67]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, D. Mon, Вы писали:
DM>Этот вариант выдает неверный ответ — на 1 меньше, т.к. забыл простое число "2". Я добавил двойку к тройке (скорость заметно упала при этом, т.к. больше ненужных делений делается), сравнил:
1. Ну с двойкой — это я просто не люблю писать очевидно неэффективный код. )))
2. Вообще то это совсем не самый быстрый код. Изначально я написал тупой императивный вариант в лоб:
Так вот у меня он работает приблизительно в 2 раза быстрее варианта через reduce. Но его нельзя одним движением превратить в вариант насилующий GC, так что я переписал его в более функциональном стиле, который и показал здесь.
DM>Если вариант на хаскеле собрать с -threaded (многопоточный рантайм) и запустить с +RTS -N4 -RTS, работает вдвое дольше (32 с), а если с -N2, то всего на секунду дольше (17.3 с). Чудеса автопараллелизма!
Кстати, здесь должен SIMD рулить ещё. Но я его в D не умею (только в C++), а сам dmd похоже тоже не умеет. Вот очень интересно было бы сравнить результаты на компиляторе gdc — тот же умеет simd автоматический (если правильные ключи указать).
Re[68]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, D. Mon, Вы писали:
DM>По идее, он в плане насилия над GC ничем не должен отличаться, вся разница в скорости из-за плохого инлайнера и оптимизатора, код с рэнджами тормозит.
Ну да, здесь всё дело в оптимизаторе (поэтому опять же интересно было бы взглянуть на результаты работы gdc). А насилие над GC включается, если мы меняем "~=" на "~" — это как раз получается по сути некий тест GC, как в коде на Хаскеле.
Re[70]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>(поэтому опять же интересно было бы взглянуть на результаты работы gdc)
Поставил gdc-4.8, длинный вариант с isPrime ускорился с 2.9 до 2.5 сек. Короткий вариант на рэнджах не скомпилился, жалуется
/usr/include/d/4.8/std/functional.d:184: Error: function prs.main.__lambda3!(int[], int).__lambda3.not!(__lambda7).not!(int).not is a nested function and cannot be accessed from find
Завтра попробую еще поиграться.
Re[71]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, D. Mon, Вы писали:
DM>Поставил gdc-4.8, длинный вариант с isPrime ускорился с 2.9 до 2.5 сек. Короткий вариант на рэнджах не скомпилился, жалуется DM>/usr/include/d/4.8/std/functional.d:184: Error: function prs.main.__lambda3!(int[], int).__lambda3.not!(__lambda7).not!(int).not is a nested function and cannot be accessed from find
DM>Завтра попробую еще поиграться.
Не знаю какие там опции нормально подходят. Но если он полностью проглотит опции от gcc, то я бы попробовал что-то вроде: -march=native -O2 -finline-functions -ftree-vectorize -flto
Re[68]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>1. Ну с двойкой — это я просто не люблю писать очевидно неэффективный код. )))
И при этом ты написал очевидно неэффективный алгоритм. Простые числа больше 3х могут быть найдены исключительно в 6*N +- 1, например 19 это 6*3 + 1, 29 это 6*5 — 1
Re[68]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Подчёркиваю: запрос был не на слово "диаграмма", а на слово "алгоритм"...
Это было понятно с самого начала. Ответ тот же.
_>Ну так это в ФЯ, а в uml диаграмма пакетов выглядит совсем по другому и служит для других целей.
Пакеты — это пакеты, а модули — это модули.
На что это:
signature OrdSig =
sig
type Item
val > : Item * Item -> bool
end;
structure IntItem =
struct
type Item = int
val op == = (op = : int * int -> bool)
val op > = (op > : int * int -> bool)
end;
больше похоже: на интерфейс и класс или на какие-то "пакеты"?
_>Т.е. собственно как я и говорил, для ФЯ uml подходит слабо.
Причем обосновываете вы это тем, что не знаете про средства организации кода в ФЯ. Это, конечно, ставит на них крест.
_>Я вроде бы достаточно точно сформулировал: где на диаграмме можно увидеть полный набор функций и их взаимодействие между собой? Ведь в ФП именно это во многом задаёт архитектуру приложения.
А где это можно на диаграмме в случае ООЯ увидеть? Вот там же и в случае ФЯ. В чем разница-то?
_>Ну так тогда наверное можно посмотреть на примеры инкапсуляции? )
Есть как самый обычный и привычный для любого ОО-программиста инструментарий в виде объявлений функций/конструкторов публичными или приватными, так и средства инкапсуляции менее привычные либо с ней у ОО-программиста вовсе не ассоциирующиеся вроде экзистенциальных типов/параметрического полиморфизма и замыканий/частичного применения.
_>Повторюсь ещё раз.
Видимо это означает, что вы опять не назовете "определенную область" C++
_>У C++ (как и у других ему подобных), есть область, в которой он очевидный лидер.
Так и вышло. "У нас есть конкретная область, но мы вам о ней не расскажем."
_>Мне всегда было очевидно почему так построен график — для удобства просмотра. Но мне не понятно с каких это оснований мы должны в анализе использовать логарифмы.
Тяжелый случай. Ладно, представьте, что вы стоите перед телевизором, подключенным к ресиверу. Вы поворачиваете ручку регулятора громкости и видите на индикаторе, как он меняется с -40 на -30 и вы слышите, как по телевизору говорят: "у восточного побережья Швамбрании произошло землетрясение магнитудой 7 с афтершоками магнитудой 5".
Почему на индикаторе было не 0.0001 и 0.001, а по телевизору не сказали "магнитудой 10000000 и 100000"? Никаких графиков же не было!
_>C и скажем C# как раз являются примером подобных данных
Конечно не являются.
_>разве что не настолько контрастных (хотя на мой взгляд "в 5 раз" — это очень не слабо).
Нет, 5 раз это очень слабо, когда разница бывает в 1000 раз и даже больше.
_>Ну хотя бы в одном мы пришли к общему мнению: рейтинг языков от данных товарищей является фуфлом.
"Фуфлом" является агрегат по процентам, а рейтинг в широком смысле "фуфлом" не является. С другой стороны TIOBE является "фуфлом" и в широком и в узком и в каком угодно другом смысле.
_>Я ответил на это ещё в предыдущем сообщение (чуть ниже цитируемого).
Этот ответ основывался на ложном утверждении, что какая-то гарантия есть.
_>Естественно позволяет, иначе не получилось бы продолжение. ) Но и хаскелевскую чистоту мы получаем в D одним движением руки.
Каким движением, если компилятор считает, что код, который чистым не является вовсе — чистый?
_>А какие побочные эффекты возможны с мутабельными параметрами? )
Любые, разумеется.
_>Ээээм, вроде как претензии были к модификатору pure, а не к модификатору immutable. Или уже и к нему что-то нашлось? )))
Так именно чистота, гарантируемая компилятором и нужна, а не какие-то "модификаторы". Вот есть у вас "модификатор" immutable и какой от него толк помимо упомянутых дрессировки программиста и чувства глубокого удовлетворения? Компилятор-то тут все равно бессилен, ничего интересного он не наоптимизирует.
_>Ну скорость GC конечно тоже можно померять (хотя лично я, кодируя в стиле C++, обычно не особо использую GC и в D)...
Ну так в том и дело, как обычно на D программируют. Вы декларируете некую "поддержку", а потом сами же заявляете о ее невостребованности. Широкое использование иммутабельных структур данных приводит к выделению памяти для зиллионов объектов в секунду и с этим нужно что-то делать, чтоб это работало с приемлемой скоростью. Если же иммутабельные структуры не использовать, а кодировать "в стиле C++" — то уже все равно по большей части какой там GC.
_>Только тогда это прямо так и надо называть. А не говорить про "тестирование иммутабельности". Потому как последнее означает сравнение скорости с данным модификатором или без него (но в любом случае с GC),
Ничего не понял. У вас все, похоже, сводится к тому, что можно какой-то модификатор где-то поставить. Ну вот есть у вас структура мутабельная, там вы все по месту переписываете, а есть структура иммутабельная и она персистентна, вы при каких-то операциях с ней возвращаете новую версию, а старая сохраняется. Вы же понимаете последствия этого и как с ними можно справляться? Вот именно возможности свести отрицательные последствия к минимуму я и называю поддержкой иммутабельности. Она позволяет пользоваться плюсами на практике сводя минусы к приемлемому уровню.
_>а не сравнение насилования GC против нормального кода.
Ну, не выдумывайте. Никакого насилия над сборщиком тут нет. В моем примере сборщик ~2% времени работает. Процент выживаемости-то низкий, работа в тепличных условиях. Так что любой точный, компактифицирующий сборщик на этом тесте себя нормально покажет, даже написанный школьником копирующий сборщик Чейни. Надо было, конечно, придумать тест потруднее, чтоб выгода от поколений была и т.д.
_>Работа в статике у D думаю одна из самых сильных вообще. Хотя это сделано для несколько других целей. )
Я очень рад за вас и за Уолта, но в данном случае, когда мы обсуждаем поддержку иммутабельности, имеет смысл продемонстрировать такую работу для обсуждаемых целей, а не каких-то "других".
_>В случае D это должно быть что-то связанное именно с этим модификатором. Потому как GC используется и с мутабельными данными.
Ну так что?
_>Да, но тестовый пример же мы сами выбираем и логично выбрать такой, в котором использование иммутабельных данных будет не искусственно введённой ересью, а чем-то приносящим реальную пользу.
А, ну конечно. Ненужность кода не позволяет адекватно оценить производительность, потому что если код нужный, то Боги Полезности наполнят вычислитель духовной силой Всеобщего Блага и тот, разогнавшись до 1024ГГц, все посчитает просто мгновенно!
_>В данном случае на код насилующий память попусту просто противно смотреть.
Мои соболезнования. И спасибо, что сами вы никакой с иммутабельными данными работающий код не продемонстрировали, пожалели меня. На него ведь так тяжело смотреть!
_>Просто здесь мы включаем насилие над GC (постоянное пересоздание структур), в то время как код с "~=" производит модификацию одной начальной структуры и соответственно GC практически не напрягается.
Обратите внимание, что почти все функции в моем примере принимают на вход иммутабельный список и возвращают иммутабельный список. Это никакие не итераторы-диапазоны. Это функции, работающие с неизменяемой структурой данных, что мы и проверяем. Не итераторы, а списки. Если вы просто сделаете одну единственную коллекцию с простыми числами иммутабельной — аналогом моего кода ваш не станет. Он станет если: 1) все функции в конвейере будут принимать и возвращает иммутабельные структуры данных и 2) количество "стадий" конвейера будет сопоставимо. Я старался их сделать побольше, вы же наоборот на них экономите, это цели теста не соответствует.
_>Хы, т.е. не поддерживается — это означает что код насилующий GC отстаёт от кода не делающего этого? ) Ну так в таком случае в Хаскеле иммутабельность тоже не поддерживается, т.к. его код тоже отстаёт от варианта не насилующего GC.
Нет, код, создающий новые экземпляры и выделяющий память, конечно, обычно медленнее, чем код, меняющий на месте. Речь идет о том, чтоб уменьшить эту разницу до более-менее приемлемой.
Попробуйте написать аналог моего кода, тогда и посмотрим.
'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
Re[67]: Есть ли вещи, которые вы прницпиально не понимаете...
DM>Сперва в DMD забыл указать -inline, получилось 19 с лишним секунд — медленнее однопоточного хаскеля.
Неплохо! Заметно, что для авторов библиотеки не безразлично насколько быстро "конвейеры" работают (большая редкость, на самом деле).
И заметно, что компилятор что-то оптимизирует. Непонятно только, почему -O не подразумевает -inline.
DM>Убунта 64 бита, Core i3 2.4 GHz (2 cores * 2 threads) DM>Если вариант на хаскеле собрать с -threaded (многопоточный рантайм) и запустить с +RTS -N4 -RTS, работает вдвое дольше (32 с), а если с -N2, то всего на секунду дольше (17.3 с). Чудеса автопараллелизма!
Что тут странного, многопоточность никак не используется, а оверхед многопоточный рантайм добавляет. Тут только странно, что с -N2 всего на секунду больше — обычно оверхед заметнее. Ну и в том, что при -N4 на двух ядрах тормоза — удивительного еще меньше. Лучшая производительность вообще обычно достигается если указывать n-1 для n-ядерного или n для n-ядерного с гипертредингом.
DM>Если в хаскельном варианте заменить самописные filter, all, takeWhile на стандартные библиотечные, работает 18.5 секунд, т.е. процентов на 10 медленнее.
Это упомянуто мной прямо в посте с кодом теста (у меня разница, впрочем, получилась больше). И даже написано почему так происходит.
А код на D быстрее заработает, если лапшевые имплементации функций заменить на комбинирование комбинаторов?
И не могли бы вы замерить, как быстродействие реагирует на увеличение числа "стадий" "конвейера"?
И не могли бы вы еще и написать более близкий аналог хаскельного примера — а то я подозреваю, что мой оппонент может еще 2-3 месяца легко разговор поддерживать прежде чем до такого кода дело дойдет.
'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
Re[68]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
DM>>Если вариант на хаскеле собрать с -threaded (многопоточный рантайм) и запустить с +RTS -N4 -RTS, работает вдвое дольше (32 с), а если с -N2, то всего на секунду дольше (17.3 с). Чудеса автопараллелизма!
K>Что тут странного, многопоточность никак не используется, а оверхед многопоточный рантайм добавляет.
В том примере активно насилуется сборщик мусора, а он в многопоточном варианте должен быть сильно быстрее однопоточного. А еще мог бы работать хотя бы отчасти параллельно основному потоку. Поэтому я все же ожидал увидеть ускорение. Попробую еще с -N3...
Или там особые ключи нужны для параллельной сборки мусора?
K>А код на D быстрее заработает, если лапшевые имплементации функций заменить на комбинирование комбинаторов? K>И не могли бы вы замерить, как быстродействие реагирует на увеличение числа "стадий" "конвейера"?
Позже попробую. Но в принципе уже сейчас по двум примерам видно, что код на рэнджевых комбинаторах втрое медленнее дубового на циклах. И чем больше комбинаторов наворачивать, тем оно обычно медленнее, а потом и вовсе инлайнер ломается (пару версий компилятора назад сталкивался на некоторых проектах).
K>И не могли бы вы еще и написать более близкий аналог хаскельного примера
С ленивым построением связного списка что-ли? Думаю, там в разы медленнее выйдет.
Re[69]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, D. Mon, Вы писали:
DM>В том примере активно насилуется сборщик мусора, а он в многопоточном варианте должен быть сильно быстрее однопоточного.
Рассуждение было бы верным, если бы сборщик действительно работал заметное время. Но это не так. Можете сами посмотреть, запустив с +RTS -s
У меня вот что:
16,022,855,308 bytes allocated in the heap
56,525,316 bytes copied during GC
16,944,480 bytes maximum residency (7 sample(s))
1,360,536 bytes maximum slop
35 MB total memory in use (0 MB lost due to fragmentation)
Tot time (elapsed) Avg pause Max pause
Gen 0 30624 colls, 0 par 0.08s 0.15s 0.0000s 0.0006s
Gen 1 7 colls, 0 par 0.03s 0.05s 0.0071s 0.0235s
INIT time 0.00s ( 0.00s elapsed)
MUT time 8.58s ( 8.52s elapsed)
GC time 0.11s ( 0.20s elapsed)
EXIT time 0.00s ( 0.00s elapsed)
Total time 8.70s ( 8.72s elapsed)
%GC time 1.3% (2.2% elapsed)
Alloc rate 1,867,873,842 bytes per MUT second
Productivity 98.7% of total user, 98.5% of total elapsed
Ключевые данные выделены.
Никакого насилия. При проведении теста ни один сборщик не пострадал.
DM>А еще мог бы работать хотя бы отчасти параллельно основному потоку. Поэтому я все же ожидал увидеть ускорение.
Нет, он параллельно основному потоку не работает, он stop-the-world. Останавливает все потоки мутатора и собирает параллельно, загружая несколько ядер.
DM>Позже попробую. Но в принципе уже сейчас по двум примерам видно, что код на рэнджевых комбинаторах втрое медленнее дубового на циклах. И чем больше комбинаторов наворачивать, тем оно обычно медленнее, а потом и вовсе инлайнер ломается (пару версий компилятора назад сталкивался на некоторых проектах).
А что и где можно почитать про дишные диапазоны и оптимизацию кода с ними?
K>>И не могли бы вы еще и написать более близкий аналог хаскельного примера DM>С ленивым построением связного списка что-ли?
Да.
DM>Думаю, там в разы медленнее выйдет.
Ну, чего-то такого я и ожидаю, но интереснее получить замер, а не какие-то предположения строить.
'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