Re[69]: Есть ли вещи, которые вы прницпиально не понимаете...
От: alex_public  
Дата: 23.04.14 12:30
Оценка:
Здравствуйте, Klapaucius, Вы писали:

K>Пакеты — это пакеты, а модули — это модули.

K>На что это:
K>...
K>больше похоже: на интерфейс и класс или на какие-то "пакеты"?

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

Ну и главное: мы же обсуждаем не языки вообще, а в контексте uml. Так вот там есть строго определённые виды диаграмм (классов, пакетов и т.п.), наборы сущностей (классы, пакеты и т.п.) и виды взаимосвязей между ними. Т.е. в любом случае, если захочется пользоваться инструментарием uml (а он весьма развитый и удобный сейчас), то придётся как-то укладываться в эти правила, а не придумывать новые. Так вот у ФП с этим большие сложности...

K>Причем обосновываете вы это тем, что не знаете про средства организации кода в ФЯ. Это, конечно, ставит на них крест.


Пока эти средства не введены в uml, действительно имеем тут крест.

K>А где это можно на диаграмме в случае ООЯ увидеть? Вот там же и в случае ФЯ. В чем разница-то?


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

K>Так вы уже посмотрели. Вот прямо в этом треде пример использования инкапсуляции приводится в объяснении устройства IO http://rsdn.ru/forum/philosophy/5384654.1
Автор: Klapaucius
Дата: 05.12.13


И кто нам помешает написать свою функцию, работающую как угодно с данными IO? )

K>Есть как самый обычный и привычный для любого ОО-программиста инструментарий в виде объявлений функций/конструкторов публичными или приватными, так и средства инкапсуляции менее привычные либо с ней у ОО-программиста вовсе не ассоциирующиеся вроде экзистенциальных типов/параметрического полиморфизма и замыканий/частичного применения.


Ничего подобного нет. Максимум что есть, это та самая структура модулей. В которой реализуется инкапсуляция уровня языка C (типа функции реализованной в .c файле, но не объявленной в .h файле).

Ну и конечно же замыкания (которые кстати везде есть) — не зря же их называют "объектами для бедных". )))

K>Видимо это означает, что вы опять не назовете "определенную область" C++


Вы не знаете области, в которых C++ является очевидным лидером? ) Это забавно для данного форума... )

K>Тяжелый случай. Ладно, представьте, что вы стоите перед телевизором, подключенным к ресиверу. Вы поворачиваете ручку регулятора громкости и видите на индикаторе, как он меняется с -40 на -30 и вы слышите, как по телевизору говорят: "у восточного побережья Швамбрании произошло землетрясение магнитудой 7 с афтершоками магнитудой 5".

K>Почему на индикаторе было не 0.0001 и 0.001, а по телевизору не сказали "магнитудой 10000000 и 100000"? Никаких графиков же не было!

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

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

Так какие у нас обоснования для применения логарифмов при обсуждение количества вопросов о данном языке на SO?

K>Нет, 5 раз это очень слабо, когда разница бывает в 1000 раз и даже больше.


Разница в 1000 раз есть только между мейнстримом и маргинальными языками. А внутри группы мейнстрима как раз наблюдается разница "в разы".

K>Каким движением, если компилятор считает, что код, который чистым не является вовсе — чистый?


Это уже просто вопрос терминологии. Компилятор прекрасно знает какая именно чистота подразумевается тут.

_>>А какие побочные эффекты возможны с мутабельными параметрами? )

K>Любые, разумеется.

Ждём демонстрацию)

K>Так именно чистота, гарантируемая компилятором и нужна, а не какие-то "модификаторы". Вот есть у вас "модификатор" immutable и какой от него толк помимо упомянутых дрессировки программиста и чувства глубокого удовлетворения? Компилятор-то тут все равно бессилен, ничего интересного он не наоптимизирует.


Ну это смотря в каком языке. ) Если мы говорим про D, то все величины без всяких модификаторов расположены в памяти конкретного потока (т.е. у каждого потока своя копия). Величины с модификатором share расположены в общей памяти (т.е. одна копия на все потоки), но при этом доступ к ним сопровождается соответствующми блокировками. А вот в случае модификатора immutable мы имеем естественно одну копию на всех, но с доступом без всяких блокировок.

K>Ну так в том и дело, как обычно на D программируют. Вы декларируете некую "поддержку", а потом сами же заявляете о ее невостребованности. Широкое использование иммутабельных структур данных приводит к выделению памяти для зиллионов объектов в секунду и с этим нужно что-то делать, чтоб это работало с приемлемой скоростью. Если же иммутабельные структуры не использовать, а кодировать "в стиле C++" — то уже все равно по большей части какой там GC.


Всё правильно. Только иммутабельные структуры весьма полезны и при кодирование в стиле C++. Ну а проработка возможности выделения "зиллионов объектов в секунду" для языка ориентированного на быстродействие весьма странно — в любом случае (даже с самым гениальным GC) такой код будет заметно медленнее работы со статическим выделением.

K>Ничего не понял. У вас все, похоже, сводится к тому, что можно какой-то модификатор где-то поставить. Ну вот есть у вас структура мутабельная, там вы все по месту переписываете, а есть структура иммутабельная и она персистентна, вы при каких-то операциях с ней возвращаете новую версию, а старая сохраняется. Вы же понимаете последствия этого и как с ними можно справляться? Вот именно возможности свести отрицательные последствия к минимуму я и называю поддержкой иммутабельности. Она позволяет пользоваться плюсами на практике сводя минусы к приемлемому уровню.


Приемлемым этот уровень пока что бывает только в теории. )

_>>В случае D это должно быть что-то связанное именно с этим модификатором. Потому как GC используется и с мутабельными данными.

K>Ну так что?

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

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

K>Обратите внимание, что почти все функции в моем примере принимают на вход иммутабельный список и возвращают иммутабельный список. Это никакие не итераторы-диапазоны. Это функции, работающие с неизменяемой структурой данных, что мы и проверяем. Не итераторы, а списки. Если вы просто сделаете одну единственную коллекцию с простыми числами иммутабельной — аналогом моего кода ваш не станет. Он станет если: 1) все функции в конвейере будут принимать и возвращает иммутабельные структуры данных и 2) количество "стадий" конвейера будет сопоставимо. Я старался их сделать побольше, вы же наоборот на них экономите, это цели теста не соответствует.


Как раз последовательность работающую с диапазонами в D можно делать произвольной длинны — разница будет не очень существенная. Заметное замедление происходит только в точке пересоздание списка чисел.

K>Нет, код, создающий новые экземпляры и выделяющий память, конечно, обычно медленнее, чем код, меняющий на месте. Речь идет о том, чтоб уменьшить эту разницу до более-менее приемлемой.

K>Попробуйте написать аналог моего кода, тогда и посмотрим.

Так уже всё написали же и измерили. И результаты говорят сами за себя. Если взять код на D работающий по месту за приемлемое быстродействие (хотя думаю переписав его на C++ получим ещё более быстрый код), то:

— код на Хаскеле (естественно размножающий данные) работает в 6-7 раз медленнее.
— код на D размножающий данные работает раз в 15 медленнее. Причём это не зависит от того, используем мы immutable данные или нет.

Да, наверное если добавить специальную оптимизацию для работы с immutable данными, то соответствующий код на D догонит вариант на Хаскеле. Но фокус в том, что и такое быстродействие абсолютно не приемлемо по сравнению с вариантом модифицирующим данные.

Кстати, интересный нюанс. В D одинаково легко записываются оба вида кода (причём он получается практически одинаковый и в одну строку). А интересно как будет выглядеть код на Хаскеле, работающий по принципу модификации одного набора данных? )
Re[72]: Есть ли вещи, которые вы прницпиально не понимаете...
От: D. Mon Великобритания http://thedeemon.livejournal.com
Дата: 23.04.14 17:32
Оценка:
Здравствуйте, alex_public, Вы писали:

DM>>Поставил gdc-4.8, длинный вариант с isPrime ускорился с 2.9 до 2.5 сек.


_>Не знаю какие там опции нормально подходят. Но если он полностью проглотит опции от gcc, то я бы попробовал что-то вроде: -march=native -O2 -finline-functions -ftree-vectorize -flto


C -flto он поперхнулся (lto1: internal compiler error: in streamer_get_pickled_tree, at tree-streamer-in.c:1050
Please submit a full bug report), а без -flto остальные опции принял молча, однако быстрее программа не стала. Те же 2.5 сек.
Re[70]: Есть ли вещи, которые вы прницпиально не понимаете...
От: D. Mon Великобритания http://thedeemon.livejournal.com
Дата: 23.04.14 18:51
Оценка: 12 (1)
Здравствуйте, Klapaucius, Вы писали:

DM>>В том примере активно насилуется сборщик мусора, а он в многопоточном варианте должен быть сильно быстрее однопоточного.


K>Рассуждение было бы верным, если бы сборщик действительно работал заметное время. Но это не так. Можете сами посмотреть, запустив с +RTS -s

K> %GC time 1.3% (2.2% elapsed)

Ага, спасибо. А если 98% времени работает лишь основной поток, чем объясняется такое сильное замедление при увеличении числа потоков (-N2-3-4) ?

K>А что и где можно почитать про дишные диапазоны и оптимизацию кода с ними?


Про оптимизацию где почитать не знаю, что-то выуживается из тонн обсуждений на дивном форуме, что-то подсказывает с++сный опыт и здравый смысл в сочетании с пониманием основных принципов. Собсно, рэнджи суть обычные шаблоны и структуры, специальная поддержка их в языке минимальна (foreach, оператор [], да и все, вроде).

Общие вещи есть тут:
http://dlang.org/phobos/std_range.html
http://www.informit.com/articles/printerfriendly.aspx?p=1407357&rll=1 (идеология)
https://github.com/PhilippeSigaud/D-templates-tutorial
http://ddili.org/ders/d.en/ranges.html
Re[73]: Есть ли вещи, которые вы прницпиально не понимаете...
От: alex_public  
Дата: 23.04.14 19:21
Оценка:
Здравствуйте, D. Mon, Вы писали:

DM>C -flto он поперхнулся (lto1: internal compiler error: in streamer_get_pickled_tree, at tree-streamer-in.c:1050

DM>Please submit a full bug report), а без -flto остальные опции принял молча, однако быстрее программа не стала. Те же 2.5 сек.

Ну да, на подобном коде чудес и не должно быть. Автовекторизация разве что могла бы сработать, но видимо тот цикл всё же не по зубам. Т.е. дальнейшее ускорение уже только руками (simd+многопоточность), а это не имеет отношения к сравнению языков/компиляторов.

Жаль gdc не смог прожевать код в функциональном стиле. Кстати, как раз из-за его нестабильности я его и не использую. Хотя по слухам под линухом он работает стабильнее чем под виндой. )
Re[71]: Есть ли вещи, которые вы прницпиально не понимаете...
От: Klapaucius  
Дата: 24.04.14 11:59
Оценка:
Здравствуйте, D. Mon, Вы писали:

DM>Ага, спасибо. А если 98% времени работает лишь основной поток, чем объясняется такое сильное замедление при увеличении числа потоков (-N2-3-4) ?


Сборщик и тормозит. Статистика, конечно, показывает и рост для мутатора, но если параллельный сборщик отключить ключем -qg — остается минимальный оверхед (который, видимо, создается планировщиком и балансировщиком нагрузки, который пытается найти в очереди единственной рабочей capability таски для n-1 простаивающих):

ST 8.52  0.20 // однопоточный рантайм
N1 9.28  0.29 sync: 0
N2 9.37  0.55 sync: 4738
N3 9.49  1.06 sync: 22952 qg 8.84  0.29 sync: 0 // однопоточный сборщик
N4 9.81  1.28 sync: 27920 qg 8.96  0.34 sync: 0
------- 4 Cores ---------
N5 10.75 2.06 sync: 45340 qg 8.87  0.34 sync: 0
N6 10.92 2.37 sync: 42422
N7 11.66 2.54 sync: 42171
N8 11.72 2.47 sync: 57688 qg 8.85  0.39 sync: 0


Причем для поддержания приемлемого оверхеда не нужно отключать параллельный сборщик вообще. Достаточно отключить его только для нулевого поколения ключем -qg1. Совсем не удивительно, что программа, в которой сборка мусора занимает относительно заметное время тоже быстрее работает с параллельной сборкой только для первого поколения:
import qualified Data.IntMap as Map

rnds = iterate $ \x -> (75*x) `mod` 65537
main = print . Map.findMax . Map.fromListWith (+) . take 10000000 . map (\x -> (x,1::Int)) . rnds $ 1


для N4:
однопоточный сборщик
MUT: 5.45 GC: 8.86
параллельный сборщик 0 и 1-е поколения
MUT: 5.93 GC: 8.08
параллельная сборщик 1-е поколение
MUT: 5.29 GC: 6.70

Тут, скорее, удивительно, что они собираются выиграть, собирая параллельно 512K G0 и для чего вообще параллельная сборка включена по умолчанию для G0?

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

DM>Собсно, рэнджи суть обычные шаблоны и структуры, специальная поддержка их в языке минимальна (foreach, оператор [], да и все, вроде).

Тут я, похоже, невнятно выразился. Я имел в виду не "как писать быстрый код с диапазонами", а на какие оптимизации общего назначения полагается их библиотечная реализация.
'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[72]: Есть ли вещи, которые вы прницпиально не понимаете...
От: D. Mon Великобритания http://thedeemon.livejournal.com
Дата: 24.04.14 13:23
Оценка: 12 (1)
Здравствуйте, Klapaucius, Вы писали:

K>Сборщик и тормозит. Статистика, конечно, показывает и рост для мутатора, но если параллельный сборщик отключить ключем -qg — остается минимальный оверхед (который, видимо, создается планировщиком и балансировщиком нагрузки, который пытается найти в очереди единственной рабочей capability таски для n-1 простаивающих)

K>Причем для поддержания приемлемого оверхеда не нужно отключать параллельный сборщик вообще. Достаточно отключить его только для нулевого поколения ключем -qg1. Совсем не удивительно, что программа, в которой сборка мусора занимает относительно заметное время тоже быстрее работает с параллельной сборкой только для первого поколения:

Занятно, спасибо!

K>Тут я, похоже, невнятно выразился. Я имел в виду не "как писать быстрый код с диапазонами", а на какие оптимизации общего назначения полагается их библиотечная реализация.


Ключевой принцип там — все, что можно описать статически, в компайл-тайме, должно быть так описано. В частности, функции высшего порядка обычно передаются не как рантайм-значения (указатель на функцию либо делегат), а как компайл-тайм значения (параметр шаблона), так их легче инлайнить. Избегают классов с виртуальными методами, вместо этого строят на каждый чих шаблонами структуры, методы для которых получаются невиртуальными и в каждом вызове известными, такие тоже хорошо инлайнятся. Т.к. инлайнер — наше все.
Отдельная популярная тема — сохранение комбинаторами максимума статической информации. Если у исходного рэнджа статически известна длина или известно, что он бесконечный, или известно, что он умеет отдавать элементы по индексу и т.п., в типе результата это будет обычно отражено и в дальшейшем использовано для минимизации рантайм-проверок. Также есть практика у комбинаторов делиться статической информацией об их входных рэнджах (к которым они применены), за счет чего reverse.reverse превращается в id, например. Все вместе это позволяет считать нечто вроде last . take 10 . reverse . take 20 $ [1..] за О(1).
Re[70]: Есть ли вещи, которые вы прницпиально не понимаете...
От: Klapaucius  
Дата: 24.04.14 13:33
Оценка:
Здравствуйте, alex_public, Вы писали:

_>Интерфейсы или классы должны иметь свои экземпляры.


Что, одного экземпляра уже не достаточно — синглетон, например, не класс? Про статические классы я и не говорю.

_>А если их нет, то это уже скорее просто некие пространства имён или же вообще пакеты.


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

_>Ну и главное: мы же обсуждаем не языки вообще, а в контексте uml. Так вот там есть строго определённые виды диаграмм (классов, пакетов и т.п.), наборы сущностей (классы, пакеты и т.п.) и виды взаимосвязей между ними.


Так я вам даже перечислил эти виды взаимосвязей для диаграммы классов — там ничего ООП специфичного нет. Между модулями, классами типов, рекордами, функциями и много чем еще могут быть те же отношения.

_>Т.е. в любом случае, если захочется пользоваться инструментарием uml (а он весьма развитый и удобный сейчас), то придётся как-то укладываться в эти правила, а не придумывать новые. Так вот у ФП с этим большие сложности...


Которые, как и все прочие упомянутые вами сложности — сложности-которые-нельзя-называть.

_>Пока эти средства не введены в uml, действительно имеем тут крест.


Вот только вы никак не можете сказать — что же такое требуется в UML ввести для их поддержки. Потому, что ничего и не нужно вводить — там все уже есть.

_>В ООП программе архитектуру приложения обычно задают классы/объекты (который отлично видны на диаграммке классов, вместо со всеми своими методами), а не глобальные функции...


В ФП программе архитектуру приложения обычно задают модули/классы типов/АлгТД/функции (который отлично видны на диаграммке классов, вместо со всеми своими дочерними структурами), а не глобальные функции...

_>И кто нам помешает написать свою функцию, работающую как угодно с данными IO? )


Нам помешает то, что конструктор IO приватный.

_>Ничего подобного нет.


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

_>Максимум что есть, это та самая структура модулей. В которой реализуется инкапсуляция уровня языка C (типа функции реализованной в .c файле, но не объявленной в .h файле).


Одна история увлекательнее другой — в C оказывается и модули уже появились.

_>Ну и конечно же замыкания (которые кстати везде есть)


Точно, и почти везде (кроме C++, как обычно) они даже работают.

_>не зря же их называют "объектами для бедных". )))


Да, а объекты — "замыканиями для бедных".

_>Вы не знаете области, в которых C++ является очевидным лидером? ) Это забавно для данного форума... )


Конечно знаю, и не одну. Более того, для любого N таких областей найдется такой пользователь этого форума, который назовет N+1-ю область. Об этом и речь.

_>Причины измерения уровней подобных энергетических величин (типа громкости звука и т.п.) в децибелах имеет вполне определённую природную причину — восприятие этих величин человеческими чувствами.


На самом деле основная причина — скорее восприятие чисел человеческим мозгом.

_>Но никто не употребляет логарифмы просто так везде или скажем просто для больших величин. Никто не говорит, что например солнце больше земли на 20 децибел.


Говорят, что у Солнца при наблюдении с Земли звездная величина −26.7, а у Земли при наблюдении с Солнца — −3.84

_>Так какие у нас обоснования для применения логарифмов при обсуждение количества вопросов о данном языке на SO?


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

_>Разница в 1000 раз есть только между мейнстримом и маргинальными языками. А внутри группы мейнстрима как раз наблюдается разница "в разы".


Вот именно. Т.е. все работает как надо — чем вы недовольны-то?

_>Это уже просто вопрос терминологии. Компилятор прекрасно знает какая именно чистота подразумевается тут.


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

_>Ждём демонстрацию)


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

_>Если мы говорим про D, то все величины без всяких модификаторов расположены в памяти конкретного потока (т.е. у каждого потока своя копия). Величины с модификатором share расположены в общей памяти (т.е. одна копия на все потоки), но при этом доступ к ним сопровождается соответствующми блокировками. А вот в случае модификатора immutable мы имеем естественно одну копию на всех, но с доступом без всяких блокировок.


Замечательно, значит какая-то смысловая нагрузка у "модификатора" все же есть!

_>иммутабельные структуры весьма полезны и при кодирование в стиле C++.


Конечно они полезны, но одновременно и вредны. И в рамках С++ c этим мало что можно сделать — получится в лучшем случае размен одной вредности на другую.

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


Это вовсе не странно, а очень актуально практически для всех языков кроме C++ и C в том числе и более быстродействующих, чем D — вроде Явы.

_>в любом случае (даже с самым гениальным GC) такой код будет заметно медленнее работы со статическим выделением.


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

_>Приемлемым этот уровень пока что бывает только в теории. )


Конечно-конечно. Никто же не использует иммутабельные структуры на практике. Только "поддерживает".

_>Так вот я и не знаю что) У меня в коде широко используются иммутабельные данные, но я не особо представляю как померить "производительность" этого. Т.к. используются они таким образом, что замена их на мутабельные не приводит к увеличению быстродействия (а часто даже наоборот). Т.е. при таком использование вопрос о "поддержке иммутабельности" (подразумевая снижение цены за это) вообще не стоит, т.к. это наоборот выгоднее даже.


Судя по смыслу, которым наделяется слово "иммутабельный" в D, тут у вас противопоставление "с блокировками" — "без блокировок". Ну тут понятно, конечно, что без блокировок должно быть быстрее.

_>Да, вот в вашем примере переход на мутабельные данные вызывает ускорение на порядок


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

_>Как раз последовательность работающую с диапазонами в D можно делать произвольной длинны — разница будет не очень существенная. Заметное замедление происходит только в точке пересоздание списка чисел.


Ну так смысл задачи — организовать множества таких "точек пересоздания", а не свести к одной.

K>>Попробуйте написать аналог моего кода, тогда и посмотрим.

_>Так уже всё написали же и измерили.

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

_>И результаты говорят сами за себя.


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

_>код на Хаскеле (естественно размножающий данные) работает в 6-7 раз медленнее.


Вообще-то 16.09/9.370 ~ 1.717, а вовсе не 6-7. При этом стадий в конвейере у вас меньше, и если их добавить — код навряд ли заработает быстрее.

_>код на D размножающий данные работает раз в 15 медленнее.


Вот напишете аналог моего кода — тогда и измерим.

_>Кстати, интересный нюанс. В D одинаково легко записываются оба вида кода (причём он получается практически одинаковый и в одну строку).


Очевидно потому, что это почти один и тот же код, а не "оба вида" кода.

Вы вместо аналога моего кода написали что-то имеющее слабое отношение к теме разговора и теперь на голубом глазу декларируете какие-то "оба вида" и "6-7 раз". Организация конвейеров в 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[71]: Есть ли вещи, которые вы прницпиально не понимаете...
От: alex_public  
Дата: 24.04.14 20:18
Оценка:
Здравствуйте, Klapaucius, Вы писали:

K>Что, одного экземпляра уже не достаточно — синглетон, например, не класс? Про статические классы я и не говорю.


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

А вот статические классы действительно являются прямым аналогом пространств имён.

K>Вот только вы никак не можете сказать — что же такое требуется в UML ввести для их поддержки. Потому, что ничего и не нужно вводить — там все уже есть.


А ну, ОК. Тогда значит вас не затруднит назвать, на какой конкретно диаграмме uml (их виды чётко определены) и каким конкретно значком (их набор и свойства тоже чётко указаны в спецификации uml) можно отобразить например те самые модули из Хаскеля?

K>Нам помешает то, что конструктор IO приватный.


Это нам как-то мешает прочитать внутренние данные IO? )

K>Одна история увлекательнее другой — в C оказывается и модули уже появились.


В C их роль выполняют файлы. Если очень нервирует такой подход, то можно взять например Паскаль (без ООП) — его модули тоже реализуют "инкапсуляцию" того же уровня. )

_>>не зря же их называют "объектами для бедных". )))

K>Да, а объекты — "замыканиями для бедных".

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

K>На самом деле основная причина — скорее восприятие чисел человеческим мозгом.


Нет, речь совсем не про числа, а именно про человеческие чувства: http://ru.wikipedia.org/wiki/%D0%97%D0%B0%D0%BA%D0%BE%D0%BD_%D0%92%D0%B5%D0%B1%D0%B5%D1%80%D0%B0_%E2%80%94_%D0%A4%D0%B5%D1%85%D0%BD%D0%B5%D1%80%D0%B0

K>Такие, что вещи, характеризующиеся числами растущими по экспоненте, часто удобно сравнивать и представлять "с применением логарифмов".


Ерунда. Если взять например характерные линейные размеры различных космических объектов, то там тоже будут разницы на порядки. И если будет желание отобразить это всё на картинке, то безусловно надо будет использовать логарифмическую шкалу (иначе получится уродливо). Однако при этом никто не будет сравнивать вместо диаметра Земли и Марса их логарифмы — в этом не будет вообще никакого смысла.

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


А вот это уже не так однозначно... Если мы будем брать именно программирование (а не абстрактные математические понятия), то пока что явное понятие чистоты есть всего в паре известных языков. Так что совсем не однозначно какое именно из них брать. Более того, т.к. определение из второго языке не противоречит первому, а всего лишь расширяет его на область вообще отсутствующую в первом, то картина становится ещё интереснее.

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


И что такого в этом, если это не глобальная/статическая переменная, а передаваемый параметр? )

==============
На всё дальнейшее я отвечу здесь целиком. Поскольку я заметил, что у нас тут наблюдается различие в самой базовой концепции. И пока не разберёмся с ним, обсуждать мелкие детали смысла нет — всё равно не поймём друг друга (точнее я то сомневаюсь в понимание в любом случае, но так хоть теоретический шанс есть).

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

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

P.S. А всё же хотелось бы увидеть решение задачки с простыми числами через мутабельные данные на Хаскеле и оценить его быстродействие и главное внешний вид. Последнее особенно интересно в контексте старой беседы о монадных ужасах.
Re[73]: Есть ли вещи, которые вы прницпиально не понимаете...
От: alex_public  
Дата: 24.04.14 20:22
Оценка:
А вот ещё интересно бы попробовать с gdc такой функциональный вариант на мутабельных данных:
int CountPrimes(int m, int v=5, int[] primes=[3])
{
    if(v>m) return primes.length+1;
    return CountPrimes(m, v+2, primes.until!(p=>p*p>v).all!(p=>v%p)?primes~=v:primes);
}
writeln(CountPrimes(2^^24));

Здесь вроде как всего один уровень вложенности лямбд — вдруг прожуёт. )

На dmd этот вариант у меня работает точно так же, как и первый функциональный вариант (который в одну строчку).
Re[74]: Есть ли вещи, которые вы прницпиально не понимаете...
От: D. Mon Великобритания http://thedeemon.livejournal.com
Дата: 26.04.14 16:45
Оценка:
Здравствуйте, alex_public, Вы писали:

_>А вот ещё интересно бы попробовать с gdc такой функциональный вариант на мутабельных данных:

_>int CountPrimes(int m, int v=5, int[] primes=[3])
_>Здесь вроде как всего один уровень вложенности лямбд — вдруг прожуёт. )

Не, не прожевал. Та же ошибка про вложенную лямбду.

_>На dmd этот вариант у меня работает точно так же, как и первый функциональный вариант (который в одну строчку).


А у меня чуток медленнее (9.7 vs. 9.4).
Re[72]: Есть ли вещи, которые вы прницпиально не понимаете...
От: Klapaucius  
Дата: 28.04.14 12:56
Оценка:
Здравствуйте, alex_public, Вы писали:

_>Одного достаточно. Ключевое различие в способе обращений к данным — через обязательно требуемую переменную, а не через имя класса.


Ну да, без этого обязательного требования диаграмму же построить нельзя... Так, погодите-ка. Можно!

_>А вот статические классы действительно являются прямым аналогом пространств имён.


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

_>А ну, ОК. Тогда значит вас не затруднит назвать, на какой конкретно диаграмме uml (их виды чётко определены) и каким конкретно значком (их набор и свойства тоже чётко указаны в спецификации uml) можно отобразить например те самые модули из Хаскеля?


Предлагаю для этого использовать элемент Class со стереотипом <<module>> на диаграмме классов.

K>>Нам помешает то, что конструктор IO приватный.

_>Это нам как-то мешает прочитать внутренние данные IO? )

Да, потому что чтоб получить внутренние данные АлгТД его нужно деконструировать паттерн-матчингом. И если конструктор приватный — это невозможно, матчить не с чем.

_>В C их роль выполняют файлы.


Нет, не выполняют.

_>Если очень нервирует такой подход, то можно взять например Паскаль (без ООП) — его модули тоже реализуют "инкапсуляцию" того же уровня. )


Не нужно сравнивать модули паскаля. Сравните лучше модули хаскеля — чем вас такая инкапсуляция не устраивает по сравнению с той, что есть в ООЯ — вы претензии озвучить можете?

_>>>не зря же их называют "объектами для бедных". )))

K>>Да, а объекты — "замыканиями для бедных".
_>Ага, и это отлично ложится на мою главную мысль, о том что будущее за мультипарадигменными языками

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

_>в которых есть полноценная поддержка и объектов и замыканий и всего остального.


Как только такой язык появится — обязательно мне сообщите.

K>>На самом деле основная причина — скорее восприятие чисел человеческим мозгом.

_>Нет, речь совсем не про числа, а именно про человеческие чувства

Одно с другим связано непосредственно. Человеческий мозг привыкает работать с теми датчиками, которые у него есть.

K>>Такие, что вещи, характеризующиеся числами растущими по экспоненте, часто удобно сравнивать и представлять "с применением логарифмов".


_>Если взять например характерные линейные размеры различных космических объектов, то там тоже будут разницы на порядки. И если будет желание отобразить это всё на картинке, то безусловно надо будет использовать логарифмическую шкалу (иначе получится уродливо). Однако при этом никто не будет сравнивать вместо диаметра Земли и Марса их логарифмы — в этом не будет вообще никакого смысла.


Абсолютно никакого. Потому, что диаметры Земли и Марса отличаются вовсе не на порядки. Параметры планет сходных типов вообще варьируются не сильно. Да и астрономы редко оперируют линейными размерами — это обычно сильно гипотетические величины, заметное кол-во исключений появилось, практически, в самое последнее время.
Классификация планет вообще только зарождается, в зрелой классификации звезд параметры и графики уже известны — диаграмма Герцшпрунга-Рассела с логарифмическими осями и логарифмическими же "рейтингами": спектральным классом и абсолютной звездной величиной.

_>Если мы будем брать именно программирование (а не абстрактные математические понятия), то пока что явное понятие чистоты есть всего в паре известных языков. Так что совсем не однозначно какое именно из них брать.


Брать математическое. Мозговые тараканы между мозгами переносятся плохо.

_>Более того, т.к. определение из второго языке не противоречит первому


Противоречит. То, что называется чистым в D в хаскеле не называется и наоборот.

_>И что такого в этом, если это не глобальная/статическая переменная, а передаваемый параметр? )


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

_>На всё дальнейшее я отвечу здесь целиком. Поскольку я заметил, что у нас тут наблюдается различие в самой базовой концепции. И пока не разберёмся с ним, обсуждать мелкие детали смысла нет — всё равно не поймём друг друга (точнее я то сомневаюсь в понимание в любом случае, но так хоть теоретический шанс есть).


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

_>Насколько я вижу, вы явно придерживаетесь точки зрения типа "иммутабельные данные — это абсолютное добро"


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

_>и вследствие этого предпочитаете использовать их вообще везде. Даже если это абсолютно не ложится на задачу (как было во всех предыдущих примерах)


Нет, я их использую в данном случае потому, что обсуждается поддержка их использования. И потому предлагаю примеры с их использованием: что обсуждаем то и демонстрируем на примерах. Вы же начали про поддержку иммутабельности в Ди, а предъявили пример, в котором ни одной иммутабельной структуры нет.

_>и соответственно за это приходится платить существенную цену (в виде падения быстродействия).


Для того, чтоб продемонстрировать поддержку иммутабельности нужно показать пример, где за нее приходится платить существенную цену. Потому, что если цена несущественная — степень поддержки измерить затруднительно.

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


Вопрос поддержки X возникает при использовании X. Снижение цены X не имеет значения только если X не использовать.

_>Хотя как мы видим по примерам в этой теме, на многих задачах даже приблизиться к производительности решений с мутабельными данными всё равно не выходит и с помощью всех ухищрений Хаскеля — отставание в разы.


Отставание в 1.7 раз. Дальнейшее увеличение разрыва связано с "фортранизацией" кода, что ожидаемо. Правда у меня разница между максимальным аналогом вашего кода (см. ниже) и моим тестом больше (3.25 раз).
Но и такая разница вполне может быть приемлемой. Особенно по сравнению с тем, что мы получим в случае языка "без поддержки". К сожалению, вы упорно не хотите демонстрировать аналог моего кода и мы так и не узнаем, какая разница будет для Ди.

_>У меня же подход совсем другой. Я использую иммутабельные данные там, где они такие по условию задачи.


Да, да, это мы уже обсуждали. И боги "условий задачи" волшебным образом срезают накладные расходы.

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

_>P.S. А всё же хотелось бы увидеть решение задачки с простыми числами через мутабельные данные на Хаскеле и оценить его быстродействие и главное внешний вид. Последнее особенно интересно в контексте старой беседы о монадных ужасах.


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

import Control.Applicative
import Control.Monad
import qualified Data.Vector.Unboxed as U
import qualified Data.Vector.Unboxed.Mutable as M

-- Я не смог вспомнить и сходу нагуглить библиотеку с "динамическим массивом",
-- для хаскеля это суровая экзотика, так что я просто релизовал его самостоятельно.
-- начальный буфер - 1000 элементов, при переполнении растет в 4 раза.

data Buffer m a = Buffer { len :: !Int, buf :: !(M.MVector m a) }

over f (Buffer c b) = f . U.take c <$> U.unsafeFreeze b

(Buffer c b) <| a | M.length b > c = add b | otherwise = add =<< M.grow b (c*3) where 
    add nb = Buffer (c+1) nb <$ M.write nb c a

buffer l = flip (foldM (<|)) l . Buffer 0 =<< M.new 1000 

-- конец реализации.

-- А вот и сам пример:

main = print . len =<< flip (U.foldM step) (U.takeWhile (<= 2^24) . U.enumFromStepN (5::Int) 2 $ 2^24) 
    =<< buffer [2, 3::Int] where
    step primes x = do 
        t <- over (U.all ((/= 0) . (rem x)) . U.takeWhile ((<= x) . (^2))) primes 
        if t then primes <| x else pure primes


Монадные ужасы в данном случае >>= либо <$> вместо $, foldM вместо foldl, и немного do-нотации (можно и без нее обойтись тем же >>=).
Работает это у меня 2.62 секунды на i5-3330 Win x64, GHC 7.6.3 x32, llvm 3.3. Мой пример работал 8.52 сек., так что разница 3.25 раз.
Следует заметить, впрочем, что если ренджи в D мутабельные (я пока не ознакомился с ними достаточно подробно, но судя по тому, что у них есть методы вроде moveFront() возвращающие элемент, но не возвращающие новый рендж), и, следовательно, вы используете в своем примере мутабельные структуры вообще везде, то векторы в моем примере иммутабельные (как и стримы, в которые они преобразуются оптимизатором), так что все промежуточные данные у меня наоборот иммутабельные, кроме единственного "динамического массива", однако, судя по разнице с "списочным" примером, работает мой код на хаскеле быстрее вашего приближенно аналогичного на 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[73]: Есть ли вещи, которые вы прницпиально не понимаете...
От: alex_public  
Дата: 29.04.14 03:03
Оценка:
Здравствуйте, Klapaucius, Вы писали:


_>>Одного достаточно. Ключевое различие в способе обращений к данным — через обязательно требуемую переменную, а не через имя класса.

K>Ну да, без этого обязательного требования диаграмму же построить нельзя... Так, погодите-ка. Можно!

Причём тут диаграммы, если здесь шла речь про разницу между объектами и пространствами имён/пакетами?

K>Предлагаю для этого использовать элемент Class со стереотипом <<module>> на диаграмме классов.


Ага... Тогда автоматически появляются следующие вопросы... Какими значками будем обозначать классы/типы Хаскеля? И главное, каким образом мы разместим иерархию типов данного модуля внутри подобного значка модуля? )

_>>Это нам как-то мешает прочитать внутренние данные IO? )

K>Да, потому что чтоб получить внутренние данные АлгТД его нужно деконструировать паттерн-матчингом. И если конструктор приватный — это невозможно, матчить не с чем.

С чего это IO стал алгебраическим типом данных? )

K>Не нужно сравнивать модули паскаля. Сравните лучше модули хаскеля — чем вас такая инкапсуляция не устраивает по сравнению с той, что есть в ООЯ — вы претензии озвучить можете?


А там есть какие-то принципиальные отличия по уровню инкапсуляции? ) Буквально тоже самое — банально реализуем функцию в коде модуля, но не описываем её в интерфейсе. Инкапсуляция уровня древнего Паскаля, когда он ещё без ООП был.

_>>в которых есть полноценная поддержка и объектов и замыканий и всего остального.

K>Как только такой язык появится — обязательно мне сообщите.

Чем например D не подходит? )

K>Одно с другим связано непосредственно. Человеческий мозг привыкает работать с теми датчиками, которые у него есть.


При работе с формулами мы используем абстракции, а не ощущениями.

K>Абсолютно никакого. Потому, что диаметры Земли и Марса отличаются вовсе не на порядки. Параметры планет сходных типов вообще варьируются не сильно. Да и астрономы редко оперируют линейными размерами — это обычно сильно гипотетические величины, заметное кол-во исключений появилось, практически, в самое последнее время.


Ну добавим сюда Юпитер и получим разницу на порядок — от этого появятся логарифмы? ))) Я не говорю уже про то, что если взять не диаметры, а массы...

K>Классификация планет вообще только зарождается, в зрелой классификации звезд параметры и графики уже известны — диаграмма Герцшпрунга-Рассела с логарифмическими осями и логарифмическими же "рейтингами": спектральным классом и абсолютной звездной величиной.


Для начала логарифмическим там является только звёздная величина. Происхождение которой теряется где-то в древней Греции и опять же полностью основано на человеческих чувствах (зрение).

_>>Если мы будем брать именно программирование (а не абстрактные математические понятия), то пока что явное понятие чистоты есть всего в паре известных языков. Так что совсем не однозначно какое именно из них брать.


K>Брать математическое. Мозговые тараканы между мозгами переносятся плохо.


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

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

Могу предположить, что если бы D стал мейнстримным языком лет 10 назад (вполне реально, если бы его изначально поддержала какая-то из мегакорпораций), то именно его определение чистоты стало бы общепринятым в программирование. Ну а пока это вообще маргинальный термин. )

K>Противоречит. То, что называется чистым в D в хаскеле не называется и наоборот.


Не противоречит, т.к. в Хаскеле просто нет такой области, которая есть в D (и любых императивных языках) — функций работающих с мутабельными параметрами. Соответственно если сравнивать только по общим областями (по работе с функциями иммутабельных параметров), то определения полностью совпадают. Т.е. мы имеем классическое расширение определения на новую область.

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


С учётом наличия в языке удобных инструментов для контроля за параметрами функции (это же не только immutable, но и например модификаторы in/out/inout) мы можем очень чётко формулировать (причём всё это в объявление, а не в реализации) наши условия на эффекты от данной функции. Так что на мой взгляд у нас есть полный контроль эффектов, причём даже более тонкий, чем в Хаскеле.

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


Нет, речь не о нужности, а о адекватности примеров. Если мы будем рассматривать примеры кода, которые никто и никогда не напишет на D на практике (потому как они на порядок медленнее своих мутабельных аналогов при одинаковой внешности кода), то подобное тестирование выглядит очень глупо.

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

K>Нет, я их использую в данном случае потому, что обсуждается поддержка их использования. И потому предлагаю примеры с их использованием: что обсуждаем то и демонстрируем на примерах. Вы же начали про поддержку иммутабельности в Ди, а предъявили пример, в котором ни одной иммутабельной структуры нет.


Так пример то предъявил не я. )

Ну а в ответ на ваш пример я показал уже 4 его реализации на D с разным быстродействием. В том числе и с иммутабельными данными. Причём все они реализуются тривиально и соответственно при программирование на D всегда будет использоваться один (самый быстрый) вариант. В отличие от Хаскеля, где быстрый вариант (для Хаскеля быстрый ) сопровождается ужасами.

K>Для того, чтоб продемонстрировать поддержку иммутабельности нужно показать пример, где за нее приходится платить существенную цену. Потому, что если цена несущественная — степень поддержки измерить затруднительно.


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

K>Отставание в 1.7 раз. Дальнейшее увеличение разрыва связано с "фортранизацией" кода, что ожидаемо.


Какой очаровательный термин для нормального императивного кода. ))) Причём что самое забавное, именно такой код скорее всего и будет писаться на практике.

Да, но и и функциональный код на D можно довести до оптимального быстродействия, слегка подправив алгоритм. Например так:
reduce!((p, v)=>p.find!(q{b%a==0||a^^2>b})(v).front()^^2>v?p~=v:p)([2, 3], iota(5, 2^^24)).count.writeln;


K>Правда у меня разница между максимальным аналогом вашего кода (см. ниже) и моим тестом больше (3.25 раз).

K>Но и такая разница вполне может быть приемлемой. Особенно по сравнению с тем, что мы получим в случае языка "без поддержки". К сожалению, вы упорно не хотите демонстрировать аналог моего кода и мы так и не узнаем, какая разница будет для Ди.

Всё показывали и измеряли. Просто вы в упор не хотите видеть. С учётом этого вашего последнего результата теперь получаем совсем законченную табличку:
— код на D с мутабельными данными (нормальный вид и даже не один вариант) — 1х
— код на Хаскеле с мутабельными данными (страшный вид) — 2x
— код на Хаскеле с иммутабельными данными (нормальный вид) — 6х
— код на D с иммутабельными данными (нормальный вид) — 15x.

Цифры естественно довольно приближённый, но порядок величины из них вполне понятен.

K>Да, да, это мы уже обсуждали. И боги "условий задачи" волшебным образом срезают накладные расходы.


K>Снижение накладных расходов означает расширение области применимости. Понятно, что даже в языках "без поддержки" есть маргинальные области, в которых использование может быть оправдано. Но масштабное использование возможно только в языке "с поддержкой".


Это просто разные подходы к проектированию вообще. У вас подход "всунуть иммутабельные данные везде, где только получится". А у меня подход "использовать иммутабельные данные там, где они такие по условию задачи". Соответственно при моём подходе область применимость никак не завязана на "поддержку в языке".

K>Это отклонение от темы, но максимальный аналог вашего кода я продемонстрирую. Я бы мог, конечно, еще побороться за сохранение темы обсуждения, но раз уж вы окончательно переключились с демонстрации поддержки (вами же и заявленной) иммутабельности в D на обвинение меня в том, что я, якобы "считаю иммутабельность абсолютным добром", ждать демонстрации кода на D, работающего с иммутабельными данными, не приходится.


Демонстрация была с самого начала.

K>...

K>Монадные ужасы в данном случае >>= либо <$> вместо $, foldM вместо foldl, и немного do-нотации (можно и без нее обойтись тем же >>=).

Хыхы, ну я этот ужастик даже комментировать не буду. Вы то всё равно не согласитесь с моей оценкой, но зато любой вменяемый читатель сразу же оценит разницу между этим вашим кодом, вашим же кодом для иммутабельного случая и кодом на D. Так сказать очередное подтверждение моим словам. Но вы естественно будете и дальше утверждать, что ничего подобного в этой темке не было. )))

K>Следует заметить, впрочем, что если ренджи в D мутабельные (я пока не ознакомился с ними достаточно подробно, но судя по тому, что у них есть методы вроде moveFront() возвращающие элемент, но не возвращающие новый рендж), и, следовательно, вы используете в своем примере мутабельные структуры вообще везде, то векторы в моем примере иммутабельные (как и стримы, в которые они преобразуются оптимизатором), так что все промежуточные данные у меня наоборот иммутабельные, кроме единственного "динамического массива", однако, судя по разнице с "списочным" примером, работает мой код на хаскеле быстрее вашего приближенно аналогичного на D.


Иммутабельность данных в языках типа D или C++ зависят не от класса, а от объекта. Т.е. если мы пишем "const vector<int> data;", то мы не сможем модифицировать data, хотя у него есть метод push_back и т.п.

Что касается диапазонов в D, то я бы сказал что они чем-то напоминают IEnumerable в C# с поправкой на попытку делать всё в статике и не терять информацию о типе изначальной коллекции (например если она с произвольным доступом, то это может существенно оптимизировать многие алгоритмы и т.п.).
Re[74]: Есть ли вещи, которые вы прницпиально не понимаете...
От: Klapaucius  
Дата: 29.04.14 12:17
Оценка:
Здравствуйте, alex_public, Вы писали:

_>Причём тут диаграммы, если здесь шла речь про разницу между объектами и пространствами имён/пакетами?


Как причем диаграммы? Мы не про диаграммы разве говорили все это время? Вот статические классы — это, по вашему, "пространства имен", а их на диаграмме классов показывают. Так какие вопросы к модулям?

_>Ага... Тогда автоматически появляются следующие вопросы... Какими значками будем обозначать классы/типы Хаскеля?


Аналогично, элементами Class с соответствующими стереотипами.

_>И главное, каким образом мы разместим иерархию типов данного модуля внутри подобного значка модуля? )


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

_>С чего это IO стал алгебраическим типом данных? )


А чем он по-вашему должен быть? Сепулькарием что ли?
Prelude> :i IO
newtype IO a
  = GHC.Types.IO (GHC.Prim.State# GHC.Prim.RealWorld
                  -> (# GHC.Prim.State# GHC.Prim.RealWorld, a #))
    -- Defined in `GHC.Types'
instance Monad IO -- Defined in `GHC.Base'
instance Functor IO -- Defined in `GHC.Base'


_>А там есть какие-то принципиальные отличия по уровню инкапсуляции? ) Буквально тоже самое — банально реализуем функцию в коде модуля, но не описываем её в интерфейсе. Инкапсуляция уровня древнего Паскаля, когда он ещё без ООП был.


Не нужно сравнивать модули паскаля. Сравните лучше модули хаскеля — чем вас такая инкапсуляция не устраивает по сравнению с той, что есть в ООЯ — вы претензии озвучить можете?

_>Чем например D не подходит? )


Тем, что не мультипарадигменный.

_>При работе с формулами мы используем абстракции, а не ощущениями.


Вы только что сами же и писали, что то, с какими формулами мы работаем — продиктовано ощущениями.

_>Ну добавим сюда Юпитер и получим разницу на порядок — от этого появятся логарифмы? ))) Я не говорю уже про то, что если взять не диаметры, а массы...


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

_>Для начала логарифмическим там является только звёздная величина.


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

_>Происхождение которой теряется где-то в древней Греции и опять же полностью основано на человеческих чувствах (зрение).


Ну да, и что за нее держатся-то? Вы же, наверно, понимаете, что абсолютную болометрическую зв. величину никто "глазами" не воспринимает?
Может и энтропию человек каким-то органом ощущает тоже?
Вы правы в том смысле, что все это началось с человеческой физиологии. Но сейчас это просто инструментарий для работы с большими диапазонами чисел, не только "воспринимаемыми" какими-то органами чувств, но вообще любыми. И если с помощью инструментария можно построить объединение каких-то двух "рейтингов" — в обсуждаемом нами случае SO и github — да еще так, чтоб они друг друга проверяли, то это же хорошо. Без логарифмов, популярность всех языков, кроме, допустим "большой пятерки" была бы одинаковой, зато все члены этой самой большой пятерки отличались бы по популярности друг от друга и от всех остальных крайне существенно. При этом какой бы "измеряемый" показатель мы не брали бы, популярность на ресурсе X, ресурсе Y или число ссылок в поисковике Z — во всех этих случаев популярность внутри пятерки была бы существенно различной, ее никак нельзя было бы согласовать.
Неужели эта проблема не понятна?

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


Т.е. имеющиеся проблемы — это оправдание для создания еще больших проблем?

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


Вы же сами и объяснили, почему они так считают.

_>Могу предположить, что если бы D стал мейнстримным языком лет 10 назад (вполне реально, если бы его изначально поддержала какая-то из мегакорпораций), то именно его определение чистоты стало бы общепринятым в программирование.


Если бы D стал мейнстримом 10 лет назад, обсуждаемых модификаторов в нем не было бы.

_>Ну а пока это вообще маргинальный термин. )


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

_>Не противоречит, т.к. в Хаскеле просто нет такой области, которая есть в D (и любых императивных языках) — функций работающих с мутабельными параметрами.


С ума сойти. Функции, которые не то что я тут использовал в коде, вот буквально в посте, на который вы отвечаете, а вы же сами и использовали, когда писали пример с использованием пакета array — они, оказывается, не существуют.

_>Соответственно если сравнивать только по общим областями (по работе с функциями иммутабельных параметров), то определения полностью совпадают. Т.е. мы имеем классическое расширение определения на новую область.


Проблема в том, что если вы множество чистых функций расширяете добавлением в него "нечистых" — то называть получившееся множество функций нечистыми нет никаких оснований. Вот есть у вас простые числа {2,3,7..} , вы их "расширили" добавлением всех остальных. ладно, не всех остальных, а, допустим, всех четных. Есть у вас теперь основания утверждать, что все четные числа — простые?

_>С учётом наличия в языке удобных инструментов для контроля за параметрами функции (это же не только immutable, но и например модификаторы in/out/inout) мы можем очень чётко формулировать (причём всё это в объявление, а не в реализации) наши условия на эффекты от данной функции. Так что на мой взгляд у нас есть полный контроль эффектов, причём даже более тонкий, чем в Хаскеле.


Ну вот у вас есть функция map, которая принимает какую-то функцию p или q. Как можно проконтролировать эффекты, чтоб выполнялось
map (p . q) = map p . map q

  Скрытый текст
впереди 7 месяцев рассуждений про ненужность контроля эффектов, и почему его отсутствие в ди равняется наличию


_>Нет, речь не о нужности, а о адекватности примеров. Если мы будем рассматривать примеры кода, которые никто и никогда не напишет на D на практике (потому как они на порядок медленнее своих мутабельных аналогов при одинаковой внешности кода), то подобное тестирование выглядит очень глупо.


Ну так вроде бы разжевано, что именно он проверяет и понятно, что в коде, который реально пишут на более-менее высокоуровневых языках все это востребовано. Вы же сами предъявили требования к примеру: он должен быть небольшим и одним. Что удивительного в том, что он выглядит искусственным, если он должен проверять разные вещи?
И главное, как то, что пример "выглядит глупо" повлияет на оценку производительности тех случаев, которые глупо не выглядят?

_>Так пример то предъявил не я. )


Что, кто-то захватил ваш аккаунт и оставил от вашего имени сообщение
Автор: alex_public
Дата: 22.04.14
в котором вместо иммутабельных структур используются мутабельные? Какое коварство! Ну, жду от вас теперь ваш пример, в котором используются иммутабельные структуры.

_>Ну а в ответ на ваш пример я показал уже 4 его реализации на D с разным быстродействием. В том числе и с иммутабельными данными.


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

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

Вы же не только не создаете промежуточные иммутабельные данные — вы стараетесь не сделать их "как можно больше", а наоборот, сокращаете число стадий в конвейерах. Довольно странно в сравнении того, как быстро что-то делается представлять вариант, который это что-то не делает.

_>Вот и я про это. Зачем измерять поддержку того, что в реальности никогда не будет использоваться (т.к. за это придётся платить существенную цену)? Естественно речь про языки, где нет проблем с использованием мутабельных данных


Ну, как я и предсказывал в самом начале, под "поддержкой иммутабельности" подразумевалась ее ненужность, тем более, что с "мутабельностью проблем нет" — ее и будут всегда использовать!

_>Какой очаровательный термин для нормального императивного кода.


Т.е. переписывание конвейера в цикл — это нормальный императивный код. А зачем вообще все эти ренджи в ди есть? Можно же писать нормальный императивный код в виде циклов — повторное использование и декомпозиция переоценены, весь прогресс после фортрана — путь в никуда.

_>))) Причём что самое забавное, именно такой код скорее всего и будет писаться на практике.


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

_>Да, но и и функциональный код на D можно довести до оптимального быстродействия, слегка подправив алгоритм. Например так:

_>
_>reduce!((p, v)=>p.find!(q{b%a==0||a^^2>b})(v).front()^^2>v?p~=v:p)([2, 3], iota(5, 2^^24)).count.writeln;
_>


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

_>Всё показывали и измеряли. Просто вы в упор не хотите видеть.


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

_>- код на D с мутабельными данными (нормальный вид и даже не один вариант) — 1х


Речь про страшный фортранизированный код?

_>- код на Хаскеле с мутабельными данными (страшный вид) — 2x


И что в нем страшного? Никакой фортранизации нет.

_>- код на D с иммутабельными данными (нормальный вид) — 15x.


Этот код еще не написан. Код "с использованием иммутабельных данных для хранения простых чисел" за такой не посчитать.

Вот что у нас сейчас есть в порядке убывания производительности:
код с циклами на D a la фортран
код на хаскеле, использующий иммутабельные данные между всеми стадиями конвейера, кроме структуры, хранящей простые числа (он не совсем нерелевантный, но измеряет только способность компилятора выкидывать лишние аллокации).
код с конвейером на D, использующий мутабельные данные между всеми стадиями конвейера и для хранения простых чисел.
код на хаскеле, использующий только иммутабельные данные (единственный, соответствующий условию задачи полностью).
код на D использующий мутабельные данные между всеми стадиями конвейера, кроме структуры, хранящей простые числа.

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


Это не соответствует действительности.

_>А у меня подход "использовать иммутабельные данные там, где они такие по условию задачи". Соответственно при моём подходе область применимость никак не завязана на "поддержку в языке".


Конечно связано. У вас "использовать иммутабельные данные там, где они такие по условию задачи" означает буквально следующее:
"По условию задачи тормозов быть не должно, значит используем мутабельные данные". Понятно, что применимость иммутабельных данных зависит от накладных расходов, с ними связанных напрямую. Потому, что именно от этого и зависит — подходят ли тут иммутабельные данные "по условию задачи".

_>Демонстрация была с самого начала.


Я не понимаю, на что вы рассчитываете, когда это пишете. Ведь вы же не написали аналога моего кода, либо вообще хоть какого-нибудь кода, который соответствует условию задачи. Что, если вы будете повторять что он был, то он волшебным образом появится? Нет, пока вы его не напишете, он не появится. И какой-то произвольный код, который вычисляет простые числа условию задачи не соответствует.

_>Хыхы, ну я этот ужастик даже комментировать не буду.


Конечно, вы вообще ни разу не сказали, что же конкретно не так с кодом, в котором "монадные ужасы".
main = print . len =<< flip (U.foldM step) (U.takeWhile (<= 2^24) . U.enumFromStepN (5::Int) 2 $ 2^24) =<< buffer [2, 3::Int] where
    step primes x = do 
        t <- over (U.all ((/= 0) . (rem x)) . U.takeWhile ((<= x) . (^2))) primes 
        if t then primes <| x else pure primes

-- если бы контроля за эффектами не было, код бы выглядел вот так:

main = print . len . flip (U.foldl step) (U.takeWhile (<= 2^24) . U.enumFromStepN (5::Int) 2 $ 2^24) $ buffer [2, 3::Int] where
    step primes x = 
        if over (U.all ((/= 0) . (rem x)) . U.takeWhile ((<= x) . (^2))) primes then primes <| x else pure primes

Т.е. издержки и синтаксическая нагрузка от контроля за эффектами есть, но насколько эти издержки серьезны?

_>Вы то всё равно не согласитесь с моей оценкой


Тут не важно, соглашусь я с ней или нет. Вы как раз оценивать не стесняетесь, только в этом посте вы заклеймили "монадные ужасы" несколько раз. Дело в том, что вы так и не удосужились сказать в чем они заключаются. Вся критика "монадных ужасов" здесь мной же и написана. Это синтаксические издержки на обслуживание контроля эффектов. т.е. do нотация, не один оператор композиции и один применения всех функций, а еще и дополнительные операторы для композиции стрелок клейсли и стыковки этих двух видов конвейеров, т.е для лифтинга чистых функций.
Что касается упомянутых вами "проблем с поддержкой мутабельности": да, некоторые проблемы с поддержкой мутабельности есть во всех языках с поддержкой иммутабельности. Тут трейдофф. Например, это write barrier, который замедляет работу с мутабельными ссылками в языках с быстрым ГЦ, необходимым для поддержки иммутабельных объектов, вроде Java.

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


Конечно заметит. Ничего общего (в контексте обсуждения иммутабельности) между первым и вторым кодом нет.

_>и кодом на D.


Заметит, что в коде на D короче имена, например iota место U.enumFromStepN, целые числа автоматически приводятся к bool и легковеснее тернарный оператор ?: вместо if then else. Ах да, ещеиэкономиянапробелах. На этом фоне ваши любимые "монадные ужасы" едва заметны.

_>Иммутабельность данных в языках типа D или C++ зависят не от класса, а от объекта. Т.е. если мы пишем "const vector<int> data;", то мы не сможем модифицировать data, хотя у него есть метод push_back и т.п.


Это не иммутабельность. Иммутабельность данных означает, что операции заданные над этими данными их не меняют, а возвращают новые версии, сохраняя старые.

_>Что касается диапазонов в D, то я бы сказал что они чем-то напоминают IEnumerable в C# с поправкой на попытку делать всё в статике и не терять информацию о типе изначальной коллекции (например если она с произвольным доступом, то это может существенно оптимизировать многие алгоритмы и т.п.).


Ну да. Точнее, IEnumerator, которые этот самый IEnumerable производит. И IEnumerator мутабельный. У него три мутирующих его данные (о положении внутри структуры, которую он обходит и неуправляемых ресурсах, которыми он владеет) метода MoveNext, Reset и Dispose.

Его хаскельный аналог иммутабельный:

-- | Result of taking a single step in a stream
data Step s a = Yield a s  -- ^ a new element and a new seed
              | Skip    s  -- ^ just a new seed
              | Done       -- ^ end of stream

-- | Monadic streams
data Stream m a = forall s. Stream (s -> m (Step s a)) s Size
'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[75]: Есть ли вещи, которые вы прницпиально не понимаете...
От: alex_public  
Дата: 23.05.14 01:15
Оценка:
Здравствуйте, Klapaucius, Вы писали:

_>>И главное, каким образом мы разместим иерархию типов данного модуля внутри подобного значка модуля? )

K>С использованием инструментария для обозначения вложенных классов. Т.е. внутри элемента или соответствующим отношением (емнип, плюс в круге на конце линии), если инструмент поддерживает.

В uml нет ничего подобного.

K>Не нужно сравнивать модули паскаля. Сравните лучше модули хаскеля — чем вас такая инкапсуляция не устраивает по сравнению с той, что есть в ООЯ — вы претензии озвучить можете?


Ну например как у нас там обстоят дела с массивом модулей?

_>>Чем например D не подходит? )

K>Тем, что не мультипарадигменный.

Типа снова переходим к троллизму? )))

K>Вполне возможно и появится. Сейчас, когда планеты сравнивают, на графиках в координатах период — масса, например, оси обычно логарифмические строят. Так что когда сформируется классификация планет вроде той, что уже для звезд есть — посмотрим какие там будут "рейтинги".


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

K>Вы правы в том смысле, что все это началось с человеческой физиологии. Но сейчас это просто инструментарий для работы с большими диапазонами чисел, не только "воспринимаемыми" какими-то органами чувств, но вообще любыми.


Если мы говорим про графики, то безусловно. Если же мы говорим про формулы, то ничего подобного — требуется какое-то обоснование по сути для введения логарифмов. Т.е. вот например для обсуждаемого случая есть некий рейтинг вида R=(S/S_max+G/G_max)*50, а вы по сути предлагаете заменить его чем-то вроде R'=(log(S)/log(S_max)+log(G)/log(G_max))*50. Так вот это будет совсем другой рейтинг и для обоснования наличия смысла в нём совершенно недостаточно аргумента вида "красивее выглядит на графике".

K>И если с помощью инструментария можно построить объединение каких-то двух "рейтингов" — в обсуждаемом нами случае SO и github — да еще так, чтоб они друг друга проверяли, то это же хорошо. Без логарифмов, популярность всех языков, кроме, допустим "большой пятерки" была бы одинаковой, зато все члены этой самой большой пятерки отличались бы по популярности друг от друга и от всех остальных крайне существенно. При этом какой бы "измеряемый" показатель мы не брали бы, популярность на ресурсе X, ресурсе Y или число ссылок в поисковике Z — во всех этих случаев популярность внутри пятерки была бы существенно различной, ее никак нельзя было бы согласовать.


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

K>Неужели эта проблема не понятна?


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

K>Проблема в том, что если вы множество чистых функций расширяете добавлением в него "нечистых" — то называть получившееся множество функций нечистыми нет никаких оснований. Вот есть у вас простые числа {2,3,7..} , вы их "расширили" добавлением всех остальных. ладно, не всех остальных, а, допустим, всех четных. Есть у вас теперь основания утверждать, что все четные числа — простые?


Что это за чушь? ) Мы же говорим не о самих множествах, а как раз о функциях над этим множествами. Т.е. вот допустим у нас есть область "функции иммутабельных параметров". Данная область имеется и в Хаскеле (собственно там только она и есть) и в D. И в этой области у нас могут существовать как чистые функции, так и нет. Так вот в этой области определение чистой функции Хаскеля и D будут полностью совпадать. Далее, расширим нашу область, добавив в неё ещё и функции мутабельных параметров (правда такое уже только в D возможно) и снова получим как чистые функции (в значение D) так и нет.

K>Ну вот у вас есть функция map, которая принимает какую-то функцию p или q. Как можно проконтролировать эффекты, чтоб выполнялось

K>
K>map (p . q) = map p . map q
K>

K>
  Скрытый текст
впереди 7 месяцев рассуждений про ненужность контроля эффектов, и почему его отсутствие в ди равняется наличию

Определения чистоты из D для функций p и q как раз уже достаточно для верности данного утверждения. Причём оно позволяет ещё и производить подобное преобразование по месту, а не только с генерацией новых данных.

===============
Здесь пропущено множество возражений на тему теста быстройдествия. Причину см. в конце сообщения.
===============

_>>Да, но и и функциональный код на D можно довести до оптимального быстродействия, слегка подправив алгоритм. Например так:

_>>
_>>reduce!((p, v)=>p.find!(q{b%a==0||a^^2>b})(v).front()^^2>v?p~=v:p)([2, 3], iota(5, 2^^24)).count.writeln;
_>>


K>Ну правильно, вы еще уменьшили число стадий конвейера. Но вы же, наверное, понимаете, что для всех случаев специальных функций не найдется, и надо будет пользоваться комбинациями функций между которыми как-то передаются данные?


Ну так а причём тут иммутабельность, комбинаторы и т.п.? ) Вы похоже совсем не понимаете откуда появляется разница в быстродействие в тех двух случаях. Или же вам действительно надо пояснять почему такой код
for(c: col) f(c);
for(c: col) g(c);
и такой код
for(c: col){
    f(c);
    g(c);
}

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

_>>Это просто разные подходы к проектированию вообще. У вас подход "всунуть иммутабельные данные везде,

_>>А у меня подход "использовать иммутабельные данные там, где они такие по условию задачи". Соответственно при моём подходе область применимость никак не завязана на "поддержку в языке".

K>Конечно связано. У вас "использовать иммутабельные данные там, где они такие по условию задачи" означает буквально следующее:

K>"По условию задачи тормозов быть не должно, значит используем мутабельные данные". Понятно, что применимость иммутабельных данных зависит от накладных расходов, с ними связанных напрямую. Потому, что именно от этого и зависит — подходят ли тут иммутабельные данные "по условию задачи".

Ээээм, вы серьёзно не понимаете что я хочу сказать? ) Разве не очевидно, что можно поделить используемые данные на мутабельные и иммутабельные уже просто условию задачи, а не по каким-то религиозным или же скоростным причинам? Т.е. грубо говоря ещё даже до выбора языка программирования можно обсуждать иммутабельность разных данных для конкретной задачи...

_>>Иммутабельность данных в языках типа D или C++ зависят не от класса, а от объекта. Т.е. если мы пишем "const vector<int> data;", то мы не сможем модифицировать data, хотя у него есть метод push_back и т.п.


K>Это не иммутабельность. Иммутабельность данных означает, что операции заданные над этими данными их не меняют, а возвращают новые версии, сохраняя старые.


Ну так всё правильно. У массивов D определены два разных оператора добавления ~ и ~=. Первый возвращает новую версию данных (новый массив), а второй соответственно производит добавление по месту и возвращает старый. Соответственно для просто массива доступны оба оператора, а для массива определённого с модификатором immutable (или const или in) доступен только оператор ~.

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

Все последующие возражения на тему этих наших тестов я пропустил, т.к. пока до вас не дойдут такие базовые вещи из мира императивных языков, как объяснённые выше (и соответственно не будет понято, что код с иммутабельными данными я показал давным давно), говорить собственно не о чем.
Re[76]: Есть ли вещи, которые вы прницпиально не понимаете...
От: Klapaucius  
Дата: 27.05.14 12:28
Оценка:
Здравствуйте, alex_public, Вы писали:

_>В uml нет ничего подобного.


Как же нет? Ну, я не любитель UML, но вот прямо сейчас набрал запрос https://www.google.ru/search?q=inner+class+uml и первые же пара картинок с этим самым отношением.

K>>Не нужно сравнивать модули паскаля. Сравните лучше модули хаскеля — чем вас такая инкапсуляция не устраивает по сравнению с той, что есть в ООЯ — вы претензии озвучить можете?

_>Ну например как у нас там обстоят дела с массивом модулей?

Зачем для инкапсуляции нужен массив модулей? Это примерно как спросить "а можно в Java сделать массив атрибутов private?".

_>Типа снова переходим к троллизму? )))


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

K>>Вполне возможно и появится. Сейчас, когда планеты сравнивают, на графиках в координатах период — масса, например, оси обычно логарифмические строят. Так что когда сформируется классификация планет вроде той, что уже для звезд есть — посмотрим какие там будут "рейтинги".


_>У вас похоже наблюдается по этому вопросу чёткое недопонимание. Повторюсь ещё раз: надо очень чётко разделять наличие логарифмических масштабов на графиках (которые делаются грубо говоря для красоты и соответственно встречаются очень часто) и наличие логарифмов в формулах (которые несут конкретный аналитических смысл и кстати не очень распространены в физике).


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

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


Естественно. Но в чем выражается это заметное отличие объективно? В показаниях множества "градусников". Эти градусники — число вопросов на одном сайте, число найденных ссылок по запросу на втором сайте, число репозиториев на третьем сайте, число предложений работы на четвертом сайте и т.д. При этом относительные показания для языков у всех "градусников" будут различаться. При этом один рейтинг, который вы называете "нормальным" усредняет показания части "градусников" с некими поправочными к-тами и этот метод усреднения постоянно меняется. Т.е. это некий черный ящик, который что-то показывает, вдруг начинает показывать что-то другое и т.д. Тот же рейтинг, который позволяет оценить корреляцию между показаниями "градусников" и критически оценить точность оценки для разных групп по разбросу точек на графике вы почему-то считаете "ненормальным".

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


Т.е. адекватный рейтинг должен поддерживать сравнение только между популярными языками? Почему? Мне не нравится вот что:
1) Нельзя сравнивать непопулярные языки. 2) Нельзя адекватно оценивать разницу между популярными, потому что из-за экспоненциального роста показанного в нелогарифмических координатах создается ощущение непреодолимых пропастей между популярными языками, которые на самом деле достаточно быстро преодолеваются (динамика популярности у языков с высокой популярностью тоже может быть очень высокой).

_>Я вижу проблему в том, что вы ищите путь подогнать результаты под заранее придуманную картину, а не попытаться понять объективную реальность.


Непонятно, на чем вы основываете свое наблюдение. Что подо что я хочу подогнать, критикуя TIOBE? B в том и в другом рейтинге разницы между теми языками которые мы сравнивали (Haskell и Go) нет, так что и куда я подгоняю?

_>вот допустим у нас есть область "функции иммутабельных параметров". Данная область имеется и в Хаскеле (собственно там только она и есть) и в D. И в этой области у нас могут существовать как чистые функции, так и нет. Так вот в этой области определение чистой функции Хаскеля и D будут полностью совпадать. Далее, расширим нашу область, добавив в неё ещё и функции мутабельных параметров (правда такое уже только в D возможно) и снова получим как чистые функции (в значение D) так и нет.


Нет, дело обстоит вот так: есть функции чистые в математическом и хаскельном смысле. А есть процедуры, которые под это определение не попадают. И в D компилятор проверяет некую "дишную чистоту", при этом функции и соответствующие мат. определению и не соответствующие ему в ди могут считаться чистыми. При этом функции, которые соответствуют мат. определению чистоты также могут не соответствовать дишному определению чистоты. Потому, что дишная чистота — это проверка на принадлежность данных потоку, никакого отношения к чистоте и функциям она не имеет, просто так называется. Одно другое никак не расширяет и не сужает.
Про "область "функции иммутабельных параметров"" вообще что-то странное. В хаскеле есть чистые функции, которые работают с "мутабельными параметрами" они там отличаются тем же, чем в ди отличаются "функции целочисленных параметров" от, например, "функций строковых параметров".

K>>Ну вот у вас есть функция map, которая принимает какую-то функцию p или q. Как можно проконтролировать эффекты, чтоб выполнялось

K>>
K>>map (p . q) = map p . map q
K>>


_>Определения чистоты из D для функций p и q как раз уже достаточно для верности данного утверждения.


Нет, недостаточно.

_>Причём оно позволяет ещё и производить подобное преобразование по месту, а не только с генерацией новых данных.


Ничего не понятно.

_>Ну так а причём тут иммутабельность, комбинаторы и т.п.? )

_>Вы похоже совсем не понимаете откуда появляется разница в быстродействие в тех двух случаях. Или же вам действительно надо пояснять почему такой код
_>
_>for(c: col) f(c);
_>for(c: col) g(c);
_>
и такой код

_>
_>for(c: col){
_>    f(c);
_>    g(c);
_>}
_>

_>будут отличаться по быстродействию на современных компьютерах? Причём это не будет зависеть от языка программирования...

Вот причем:
Упрощенно говоря, когда вы используете иммутабельные структуры данных и комбинировать комбинаторы вы при наивной реализации чаще будете получать код первого типа. Поэтому, "поддержкой иммутабельности и комбинаторов" я называю способность того, что поддерживает сводить код первого типа к коду второго типа, т.е. уменьшать число проходов, улучшать локальность и т.д. И от языка программирования, а точнее от степени наивности реализации его компилятора и рантайма тут будет зависеть все.
Понятно теперь что тут причем?

_>Ээээм, вы серьёзно не понимаете что я хочу сказать? )


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

_>Разве не очевидно, что можно поделить используемые данные на мутабельные и иммутабельные уже просто условию задачи, а не по каким-то религиозным или же скоростным причинам? Т.е. грубо говоря ещё даже до выбора языка программирования можно обсуждать иммутабельность разных данных для конкретной задачи...


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

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

_>У массивов D определены два разных оператора добавления ~ и ~=. Первый возвращает новую версию данных (новый массив), а второй соответственно производит добавление по месту и возвращает старый.


Проблема не в массиве. Я же вам объясняю, да — в единственно месте вы меняете мутабельность данных — в случае как раз этого массива. Все остальные промежуточные данные у вас диапазоны-итераторы, которые всегда мутабельны.

_>И как раз благодаря этому я мог легко продемонстрировать обе версии кода (с мутабельными данными и с иммутабельными) путём изменения всего одного символа в нём.


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

_>Все последующие возражения на тему этих наших тестов я пропустил...


... так как ответить по теме нечего, потому вы слезаете с темы и начинаете объяснять понятные всем вещи.
В следующем ответе не пропускайте то, что я вам пишу, а наоборот, отвечайте на вопросы и комментируйте, так выйдет гораздо лучше.
'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[77]: Есть ли вещи, которые вы прницпиально не понимаете...
От: alex_public  
Дата: 27.05.14 22:29
Оценка:
Здравствуйте, Klapaucius, Вы писали:

K>Как же нет? Ну, я не любитель UML, но вот прямо сейчас набрал запрос https://www.google.ru/search?q=inner+class+uml и первые же пара картинок с этим самым отношением.


Нет, значит нет. Можно посмотреть подробнее например тут http://www.uml-diagrams.org/nested-classifier.html. Ну и главное (из-за чего мы собственно обсуждали эти нюансы) — в трёх используемых мною uml инструментах (кстати одних из самых известных) нет ничего подобного.

Кстати, ещё по ассоциации появился вопрос на близкую тему: есть ли аналог doxygen'a для хаскеля? И если есть, то умеет ли он генерировать какие-то диаграммы? И если умеет, то какие?

K>Зачем для инкапсуляции нужен массив модулей? Это примерно как спросить "а можно в Java сделать массив атрибутов private?".


Именно "массив модулей" не требуется. Требуется (и очень часто) массив неких сущностей, которые при этом умеют инкапсулировать некие внутренние нюансы. Вы говорите, что инкаспсуляция в хаскеле реализована через модули. Соответственно сразу возникает вопрос: как у нас обстоят дела с массивами модулями и т.п?

K>Естественно. Но в чем выражается это заметное отличие объективно? В показаниях множества "градусников". Эти градусники — число вопросов на одном сайте, число найденных ссылок по запросу на втором сайте, число репозиториев на третьем сайте, число предложений работы на четвертом сайте и т.д. При этом относительные показания для языков у всех "градусников" будут различаться. При этом один рейтинг, который вы называете "нормальным" усредняет показания части "градусников" с некими поправочными к-тами и этот метод усреднения постоянно меняется. Т.е. это некий черный ящик, который что-то показывает, вдруг начинает показывать что-то другое и т.д. Тот же рейтинг, который позволяет оценить корреляцию между показаниями "градусников" и критически оценить точность оценки для разных групп по разбросу точек на графике вы почему-то считаете "ненормальным".


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

K>Т.е. адекватный рейтинг должен поддерживать сравнение только между популярными языками? Почему? Мне не нравится вот что:

K>1) Нельзя сравнивать непопулярные языки. 2) Нельзя адекватно оценивать разницу между популярными, потому что из-за экспоненциального роста показанного в нелогарифмических координатах создается ощущение непреодолимых пропастей между популярными языками, которые на самом деле достаточно быстро преодолеваются (динамика популярности у языков с высокой популярностью тоже может быть очень высокой).

Ну почему же. Тот же tiobe вполне себе позволяет сравнивать и непопулярные. Да и существенная разница в значениях для популярных очень даже нормально интуитивно ощущается.

K>Нет, дело обстоит вот так: есть функции чистые в математическом и хаскельном смысле. А есть процедуры, которые под это определение не попадают. И в D компилятор проверяет некую "дишную чистоту", при этом функции и соответствующие мат. определению и не соответствующие ему в ди могут считаться чистыми.


Это верно. Только надо добавить, что сочетание модификаторов pure и immutable (для параметров) даст как раз в точности хаскельное определение. Т.е. всё же имеем однозначное подмножество.

K>При этом функции, которые соответствуют мат. определению чистоты также могут не соответствовать дишному определению чистоты.


Жду пример такой функции... )

K>>>Ну вот у вас есть функция map, которая принимает какую-то функцию p или q. Как можно проконтролировать эффекты, чтоб выполнялось

K>>>
K>>>map (p . q) = map p . map q
K>>>

_>>Определения чистоты из D для функций p и q как раз уже достаточно для верности данного утверждения.
K>Нет, недостаточно.

Жду пример функций p и q, имеющих модификатор pure и для которых данное равенство не выполняется.

K>Вот причем:

K>Упрощенно говоря, когда вы используете иммутабельные структуры данных и комбинировать комбинаторы вы при наивной реализации чаще будете получать код первого типа. Поэтому, "поддержкой иммутабельности и комбинаторов" я называю способность того, что поддерживает сводить код первого типа к коду второго типа, т.е. уменьшать число проходов, улучшать локальность и т.д. И от языка программирования, а точнее от степени наивности реализации его компилятора и рантайма тут будет зависеть все.
K>Понятно теперь что тут причем?

Ага, ага... Осталось только продемонстрировать, что Хаскель реализует такую оптимизацию... )

K>Т.е. вы делите данные на иммутабельные и мутабельные не по причине удобства работы и "скоростных соображений", а по некоим "простоусловиям задачи". Похоже, что религия как раз у вас.


Что значит "неким условиям"? ) Если мы точно знаем, что определённый кусок данных является неизменным (при программирование в обычном императивном стиле) на протяжение всей своей жизни, то перевод его в иммутабельный статус гарантированно не понизит быстродействие. А возможно и повысит его. И в любом случае повысит надёжность кода.

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

K>Проблема не в массиве. Я же вам объясняю, да — в единственно месте вы меняете мутабельность данных — в случае как раз этого массива. Все остальные промежуточные данные у вас диапазоны-итераторы, которые всегда мутабельны.


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

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


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

А во-вторых (и это главное) в данном коде вообще ровно одна точка модификации нашего массива (которую уже обсудили), так что никаких мутирующих промежуточных данных нет. Или вы всё про индексы используемые для пробега по массиву где-то внутри библиотечных функций? )
Re[78]: Есть ли вещи, которые вы прницпиально не понимаете...
От: Klapaucius  
Дата: 28.05.14 12:42
Оценка:
Здравствуйте, alex_public, Вы писали:

_>Нет, значит нет. Можно посмотреть подробнее например тут http://www.uml-diagrams.org/nested-classifier.html. Ну и главное (из-за чего мы собственно обсуждали эти нюансы) — в трёх используемых мною uml инструментах (кстати одних из самых известных) нет ничего подобного.


Ну значит есть что-то другое для обозначения вложенных классов. В конце концов, можно доступные в инструменте и близкие по смыслу отношения использовать. Или языки со вложенными классами для использования UML тоже не подходят?

_>Кстати, ещё по ассоциации появился вопрос на близкую тему: есть ли аналог doxygen'a для хаскеля?


Есть.

_>И если есть, то умеет ли он генерировать какие-то диаграммы? И если умеет, то какие?


Думаю, что нет. По крайней мере, я никогда никакие диаграммы для кода на хаскеле не генерировал (но я этого и для кода на других языках обычно не делаю).

K>>Зачем для инкапсуляции нужен массив модулей? Это примерно как спросить "а можно в Java сделать массив атрибутов private?".


_>Именно "массив модулей" не требуется. Требуется (и очень часто) массив неких сущностей, которые при этом умеют инкапсулировать некие внутренние нюансы. Вы говорите, что инкаспсуляция в хаскеле реализована через модули. Соответственно сразу возникает вопрос: как у нас обстоят дела с массивами модулями и т.п?


Ну вот, а в Java инкапсуляция "реализована через атрибуты private". Ну так вот, когда вам "Требуется массив неких сущностей, которые при этом умеют инкапсулировать некие внутренние нюансы" вам при этом требуется массив атрибутов private или нет?

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


Мы это уже обсуждали. Вы вот это http://rsdn.ru/forum/philosophy/5559447.1
Автор: Klapaucius
Дата: 15.04.14
сообщение читали?

_>Тот же tiobe вполне себе позволяет сравнивать и непопулярные.


Как же позволяет, если они все примерно одинаковые получаются?

_>Это верно. Только надо добавить, что сочетание модификаторов pure и immutable (для параметров) даст как раз в точности хаскельное определение.


Конечно нет, потому что хаскельная чистая функция иммутабельности параметров не требует.

K>>При этом функции, которые соответствуют мат. определению чистоты также могут не соответствовать дишному определению чистоты.

_>Жду пример такой функции... )

putStrLn

_>Жду пример функций p и q, имеющих модификатор pure и для которых данное равенство не выполняется.


Чем вас пример D.Mon не устраивает?

_>Ага, ага... Осталось только продемонстрировать, что Хаскель реализует такую оптимизацию... )


Это в этом разговоре уже было продемонстрировано здесь http://rsdn.ru/forum/philosophy/5441040.1
Автор: Klapaucius
Дата: 23.01.14


Мои сообщения по теме
http://rsdn.ru/forum/decl/4237532.1
Автор: Klapaucius
Дата: 17.04.11

http://rsdn.ru/forum/decl/4519667.1
Автор: Klapaucius
Дата: 30.11.11


_>Что значит "неким условиям"? ) Если мы точно знаем, что определённый кусок данных является неизменным (при программирование в обычном императивном стиле) на протяжение всей своей жизни, то перевод его в иммутабельный статус гарантированно не понизит быстродействие. А возможно и повысит его. И в любом случае повысит надёжность кода.


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

_>Кстати, только сейчас, при написание предыдущей фазы, понял ещё один минус подхода с иммутабельностью как в Хаскеле — он не помогает явно декларировать в коде инварианты задачи.


Можете вот это расшифровать?

_>Ээээм. Вообще то тут нет никаких промежуточных данных.


Замечательно! Т.е. вы сами же считаете, что поставленную задачу вы не выполнили. Читаем задачу "Задача заключается в проверке "поддержки иммутабельности" в языке, посредством создания как можно большего числа промежуточных значений в виде иммутабельных структур данных..." здесь http://rsdn.ru/forum/philosophy/5559447.1
Автор: Klapaucius
Дата: 15.04.14


На самом деле промежуточные данные конечно есть — только они мутабельные, что впрочем тоже условию задачи не соответствует.

_>Если же вы подразумеваете под промежуточными данными индексы, используемые при пробеге по массиву внутри функций работы с диапазонами,


Да, именно их я и имею в виду.

_>то это абсолютно равносильно утверждению, что ваш хаскельный код работает с мутабельными данными, т.к. в итоге компилятор Хаскеля преобразовывает все пробеги по массивам (да и вообще все нужные рекурсии) в циклы, внутри которых используется мутабельный индекс.


Разумеется это не равносильно. В первом случае есть код на D, который содержит работу с мутабельными данными. И преобразуется потом в некий промежуточный результат (уже не 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[79]: Есть ли вещи, которые вы прницпиально не понимаете...
От: alex_public  
Дата: 28.05.14 17:04
Оценка:
Здравствуйте, Klapaucius, Вы писали:

K>Ну значит есть что-то другое для обозначения вложенных классов. В конце концов, можно доступные в инструменте и близкие по смыслу отношения использовать. Или языки со вложенными классами для использования UML тоже не подходят?


В этих язык оно обычно имеет смысл просто пространства имён и соответственно отображается на диаграммах. Но вы то наоборот хотите на базе этого создать всю свою диаграмму. )))

_>>И если есть, то умеет ли он генерировать какие-то диаграммы? И если умеет, то какие?

K>Думаю, что нет. По крайней мере, я никогда никакие диаграммы для кода на хаскеле не генерировал (но я этого и для кода на других языках обычно не делаю).

Печально, печально. Это весьма удобный инструмент для изучения кода. Можно глянуть пример скажем здесь http://docs.wxwidgets.org/3.0/classwx_evt_handler.html — с учётом возможности навигации по классам с помощью клику по нему на диаграммке получается крайне удобный инструмент.

K>Ну вот, а в Java инкапсуляция "реализована через атрибуты private". Ну так вот, когда вам "Требуется массив неких сущностей, которые при этом умеют инкапсулировать некие внутренние нюансы" вам при этом требуется массив атрибутов private или нет?


В Java мне предоставляют массив объектов, каждый из которых обладает атрибутом private. А массив каких сущностей, обладающих возможностью инкапсуляции, может предложить Хаскель?

_>>Тот же tiobe вполне себе позволяет сравнивать и непопулярные.

K>Как же позволяет, если они все примерно одинаковые получаются?

В смысле примерно одинаковые? Там полсотни языков с довольно равномерным распределением не популярных.

K>putStrLn


И с каких пор эта функция стала чистой? )

K>Чем вас пример D.Mon не устраивает?


У D.Mon где-то был пример в котором map (p . q) != map p . map q для чистых p и q? )

K>Это в этом разговоре уже было продемонстрировано здесь http://rsdn.ru/forum/philosophy/5441040.1
Автор: Klapaucius
Дата: 23.01.14


K>Мои сообщения по теме

K>http://rsdn.ru/forum/decl/4237532.1
Автор: Klapaucius
Дата: 17.04.11

K>http://rsdn.ru/forum/decl/4519667.1
Автор: Klapaucius
Дата: 30.11.11


Это даже близко не имеет никакого отношения к обсуждаемой проблеме. В данном случае мы изначально имели код вида
is_prime= v=> primes.until(p^^2>v).all(v%p!=0);
и заменили его для оптимизации (и это довело быстродействие до равного явному циклу) на код вида:
is_prime= v=> primes.find(v%p==0||p^^2>v)^^2>v;

С удовольствием посмотрю как реализована автоматизация подобной оптимизации в Хаскеле...

K>А то, какой "кусок данных" окажется неизменным, как раз из озвученных мной соображений и определяется. Т.е. из баланса удобства деланья его неизменным и штрафов, которые мы за эту неизменность получаем по времени и памяти.


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

_>>Кстати, только сейчас, при написание предыдущей фазы, понял ещё один минус подхода с иммутабельностью как в Хаскеле — он не помогает явно декларировать в коде инварианты задачи.

K>Можете вот это расшифровать?

Судя по предыдущему абзацу это бесполезно.

K>Замечательно! Т.е. вы сами же считаете, что поставленную задачу вы не выполнили. Читаем задачу "Задача заключается в проверке "поддержки иммутабельности" в языке, посредством создания как можно большего числа промежуточных значений в виде иммутабельных структур данных..." здесь http://rsdn.ru/forum/philosophy/5559447.1
Автор: Klapaucius
Дата: 15.04.14


Потому как в D они просто не нужны. Кстати говоря, в конкретно этой задачке в принципе можно было и на Хаскеле организовать такое же (и без мутабельных структур при этом). Достаточно реализовать некое подобие диапазонов, но соответственно через рекурсии и т.п.


_>>Если же вы подразумеваете под промежуточными данными индексы, используемые при пробеге по массиву внутри функций работы с диапазонами,

K>Да, именно их я и имею в виду.
_>>то это абсолютно равносильно утверждению, что ваш хаскельный код работает с мутабельными данными, т.к. в итоге компилятор Хаскеля преобразовывает все пробеги по массивам (да и вообще все нужные рекурсии) в циклы, внутри которых используется мутабельный индекс.

K>Разумеется это не равносильно. В первом случае есть код на D, который содержит работу с мутабельными данными. И преобразуется потом в некий промежуточный результат (уже не D) в ходе кодогенерации который тоже содержит работу с мутабельными данными. Во втором случае есть код на хаскеле, который содержит работу с иммутабельными данными, и преобразуется потом в некий промежуточный результат (уже не хаскель) в ходе кодогенерации который содержит работу с мутабельными данными. Т.е. кода на хаскеле, работающего с мутабельными данными нет, а на D такой код есть. Разница понятна?


В таком случае, если я перепишу в стандартной библиотеке D внутренности реализации диапазонов и алгоритмов через рекурсии (при этом скорее всего ни код моего примера в этой задачке, ни итоговый бинарник не изменятся), то всё резко станет в точности как в Хаскеле?
Re[80]: Есть ли вещи, которые вы прницпиально не понимаете...
От: Klapaucius  
Дата: 29.05.14 11:37
Оценка:
Здравствуйте, alex_public, Вы писали:

_>В этих язык оно обычно имеет смысл просто пространства имён и соответственно отображается на диаграммах.


Не обязательно. Ну а если в случае хаскеля будет "смысл просто пространства имён"?

_>Но вы то наоборот хотите на базе этого создать всю свою диаграмму.


С чего бы это? Мне показалось просто, что вы видите какую-то проблему с вложенными сущностями. Если нет — вообще не понятно, в чем претензии-то? Если можно на диаграмме классов показывать стат.классы, интерфейсы, классы — почему нельзя модули, классы типов, АлгТД?

_>Печально, печально. Это весьма удобный инструмент для изучения кода. Можно глянуть пример скажем здесь http://docs.wxwidgets.org/3.0/classwx_evt_handler.html — с учётом возможности навигации по классам с помощью клику по нему на диаграммке получается крайне удобный инструмент.


Какие-то построители таких схем есть и для хаскеля — http://code.haskell.org/~ivanm/Sample_SourceGraph/graphviz/graphviz.html — но я ими никогда не пользовался, как не пользовался такими средствами и для других языков, так что ничего подробно о них рассказать не могу.

_>В Java мне предоставляют массив объектов, каждый из которых обладает атрибутом private. А массив каких сущностей, обладающих возможностью инкапсуляции, может предложить Хаскель?


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

_>В смысле примерно одинаковые? Там полсотни языков с довольно равномерным распределением не популярных.


Со всеми перечисленными мной в предыдущих постах недостатками.

_>И с каких пор эта функция стала чистой? )


Она чистая по построению (с объяснения этого все мое участие в этой ветке и начинается), так что с момента ее написания.

_>У D.Mon где-то был пример в котором map (p . q) != map p . map q для чистых p и q? )


У него был пример "чистой" функции, которая изменяет передаваемые ей объекты, без всякой системы упорядочивания этих действий. Это значит, что обсуждаемый закон для такой функции не выполняется.

_>Это даже близко не имеет никакого отношения к обсуждаемой проблеме.


Конечно имеет.

_>В данном случае мы изначально имели код вида

_>
_>is_prime= v=> primes.until(p^^2>v).all(v%p!=0);
_>
и заменили его для оптимизации (и это довело быстродействие до равного явному циклу) на код вида:

_>
_>is_prime= v=> primes.find(v%p==0||p^^2>v)^^2>v;
_>

_>С удовольствием посмотрю как реализована автоматизация подобной оптимизации в Хаскеле...

Такой код на хаскеле:
is_prime :: Int -> Vector Int -> Bool
is_prime v primes = all (\p -> v `mod` p /= 0) . takeWhile (\p -> p^2 <= v) $ primes

преобразуется вот в такой:
is_prime :: Int -> Vector Int -> Bool
is_prime v (Vector start len vec) =
  case len < 0 of
    False ->
      let x0 = vec ! start in
      case x0*x0 <= v of
        False -> True
        True ->
          case v `mod` x0 of
              0 -> False
              _ -> let loop sc =
                      case len < sc of
                        False ->
                          let x = vec ! (start + sc) in
                          case x*x <= v of
                            False -> True
                            True ->
                              case v `mod` x of
                                0 -> False
                                _ -> loop (sc + 1)
                        True -> True
                   in loop 1;
    True -> True

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

_>Понятно... Т.е. видеть реальную неизменность данных в условиях задачи вы не умеете...


Никакой "реальной неизменности данных" не существует, потому что память изменяема. Даже если мы храним какую-нибудь предвычисленную таблицу синусов, которую менять нет смысла — пи четырем даже в военное время равняться не станет — все равно вопрос изменяемости этих данных решается исходя из баланса удобства и вычислительных возможностей: например, у нас мало памяти, и часть таблицы, которая больше использоваться не будет можно переписать чем-то другим.

_>Судя по предыдущему абзацу это бесполезно.


Т.е. не можете (что можно было ожидать из опыта предыдущего рзговора).

K>>Замечательно! Т.е. вы сами же считаете, что поставленную задачу вы не выполнили. Читаем задачу "Задача заключается в проверке "поддержки иммутабельности" в языке, посредством создания как можно большего числа промежуточных значений в виде иммутабельных структур данных..." здесь http://rsdn.ru/forum/philosophy/5559447.1
Автор: Klapaucius
Дата: 15.04.14


_>Потому как в 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[81]: Есть ли вещи, которые вы прницпиально не понимаете...
От: alex_public  
Дата: 29.05.14 16:02
Оценка:
Здравствуйте, Klapaucius, Вы писали:

K>Не обязательно. Ну а если в случае хаскеля будет "смысл просто пространства имён"?


Так на диаграмме это просто отображается как некий префикс к имени класса. Типа std::string. Т.е. не получится строить из этого нормальную диаграмму (где есть всякие отношения и т.п.).

K>С чего бы это? Мне показалось просто, что вы видите какую-то проблему с вложенными сущностями. Если нет — вообще не понятно, в чем претензии-то? Если можно на диаграмме классов показывать стат.классы, интерфейсы, классы — почему нельзя модули, классы типов, АлгТД?


Напомню мою основную претензию, на которую так и не было ответа: как у нас отображаются функции (которые в отличие от ООП могут нести основную смысловую нагрузку программы) на диаграмме? У вас была попытка ответить через размещение модулей на диаграмме классов, но как мы видим это получается бредово.

K>Какие-то построители таких схем есть и для хаскеля — http://code.haskell.org/~ivanm/Sample_SourceGraph/graphviz/graphviz.html — но я ими никогда не пользовался, как не пользовался такими средствами и для других языков, так что ничего подробно о них рассказать не могу.


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

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


Воот, это уже ближе к делу... И как мы видим, уже никаких модулей — они резко отступают на роль модулей Паскаля или вообще h/c файлов в C. И инкапсуляция того уже уровня выходит. )))

K>Она чистая по построению (с объяснения этого все мое участие в этой ветке и начинается), так что с момента ее написания.


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

K>У него был пример "чистой" функции, которая изменяет передаваемые ей объекты, без всякой системы упорядочивания этих действий. Это значит, что обсуждаемый закон для такой функции не выполняется.


Ну так покажите где он там не выполняется... Я вот вижу другое:
auto p(ref int v) pure {return ++v+1;}
auto q(int v) pure {return v*2;}

//проверяем, что p действительно модифицирующая
auto data=[1, 2, 3, 4, 5];
data.writeln;//выводит: [1, 2, 3, 4, 5]
data.map!p.writeln;//выводит: [3, 4, 5, 6, 7]
data.writeln;//выводит: [2, 3, 4, 5, 6]

//и собственно проверка нашего равенства
[1, 2, 3, 4, 5].map!p.map!q.writeln;//выводит: [6, 8, 10, 12, 14]
[1, 2, 3, 4, 5].map!(x=>x.p.q).writeln;//выводит: [6, 8, 10, 12, 14]


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

K>Такой код на хаскеле:

K>
K>is_prime :: Int -> Vector Int -> Bool
K>is_prime v primes = all (\p -> v `mod` p /= 0) . takeWhile (\p -> p^2 <= v) $ primes
K>

K>преобразуется вот в такой:
K>...
K>с точностью до преобразования между хаскелем и одним из промежуточных представлений кода в кодогенераторе.

Весьма сомнительно, т.к. иначе с чего бы это ваш вариант вычислений с мутабельными данными на Хаскеле в несколько раз более тормознутый, чем вариант на D? ) Да и к тому же вы не показали собственно с помощью чего производятся подобные оптимизации или это магия? )))

K>Никакой "реальной неизменности данных" не существует, потому что память изменяема. Даже если мы храним какую-нибудь предвычисленную таблицу синусов, которую менять нет смысла — пи четырем даже в военное время равняться не станет — все равно вопрос изменяемости этих данных решается исходя из баланса удобства и вычислительных возможностей: например, у нас мало памяти, и часть таблицы, которая больше использоваться не будет можно переписать чем-то другим.


Ооо, наконец то начинает появляться понимание... Кстати, замечу, что неизменяемое значение должно быть таким только на протяжение своей жизни. Так что immutable табличку вполне можно стереть после использования и заменить ту же самую ячейку памяти новыми данными (возможно тоже неизменяемыми).

_>>ни итоговый бинарник не изменятся)

K>Если он не изменится, то значит задание опять не выполнено. Потому что по заданию нужно создавать как устранимые аллокации (чтоб дать возможность продемонстрировать оптимизатор), так и неустранимые, чтоб создать работу для менеджера памяти.

То, что тестирование работы с иммутабельными данными равносильно насилованию менеджера памяти — это исключительно ваш тезис. Причём в D (в котором есть множество различных способов размещения данных) это вообще выглядит крайне смешно.

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


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