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

I>Вообще говоря нормальный вариант. Я тут рядом дал ссылку от Gaperton, посмотри, убедись.


Угу, я уже глянул. Как раз хороший пример того, как плохо живётся без ООП. И каких монстров приходится из-за этого плодить.
Re[104]: Есть ли вещи, которые вы прницпиально не понимаете...
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 19.06.14 04:03
Оценка:
Здравствуйте, alex_public, Вы писали:

I>>И что с того ? А в джаваскрипте в языке вообще нет наследования. И что ?


Ну конечно)))

Прототипное ООП это громкий баззворд для простой идеи — поддержка ООП на уровне библиотеки. Сама поддержка ООП в языке сводится примерно к трем или четырем словами навроде constructor, prototype, instanceof

Отсюда ясно, что JS на уровне библиотеки поддерживает все мыслимые и не мыслимые варианты наследования.

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


В разных языках все по разному. Синтаксическая поддержка ООП есть только в ООП языках. Вот эрланг динамический язык, однако ООП как тебе хочется,в ём нет,даже прототипного. А ООП вообще вполне реализуется, на уровне библиотеки разумеется.
Re[94]: Есть ли вещи, которые вы прницпиально не понимаете...
От: D. Mon Великобритания http://thedeemon.livejournal.com
Дата: 19.06.14 09:06
Оценка:
Здравствуйте, alex_public, Вы писали:

_>А вообще в императивных языках это всё выглядит надуманными проблемами — если мы передаём в map не готовую библиотечную функцию, а какую-то лямбду (чаще всего), то обычно гораздо удобнее использовать явный цикл (тем более, если есть foreach).


Не-не-не, цикл это фу, с ним нельзя однострочники делать, где кроме map'а всякие другие штуки, да и самих map'ов может быть несколько. Циклы не композятся.
Re[94]: Есть ли вещи, которые вы прницпиально не понимаете...
От: Klapaucius  
Дата: 19.06.14 09:15
Оценка:
Здравствуйте, alex_public, Вы писали:

_>Ну так на ней и нарисованы по сути некие виртуальные объекты в стиле ООП, как вы и предлагали ниже...


Нет, объекты в стиле ООП на ней не нарисованы. На ней нарисованы функции в стиле ФП и определенные на множествах этих функций другие функции. Ничего дальше от ООП чем это просто не бывает, но UML с отображением этого вполне справился. Отсюда вывод, что необходимости что-то в него добавлять для этой цели нет.

_>А там речь про другое была. Нет в uml стрелочки "инкапсулированы"... )


И что с того?

_>И эти общие вещи напрямую отображаются в код ООП программы. А в случае Хаскеля нам потребуется специальный перевод.


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

_>Собственно если мы говорим про диаграмму классов, то хаскель тут не одинок — тому же ассемблеру будет ещё хуже на ней.


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

_>Потому как предлагаете рисовать виртуальные объекты именно на базе АлгТД, а не на базе модулей. )


Причем тут инкапсуляция?

_>Ну в общем то это и очевидно (мысль о массиве модулей сразу всё проясняет), хотя вы почему-то долго упирались. )))


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

_>Так я не понял зачем запрещать то? )


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

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


Как автор библиотеки может полагаться на то, что будет в его функции посылать пользователь его библиотеки, если не выразит это в системе типов?

_>Во-первых это только в вашем мире функция map и понятие функторов жёстко связаны. )))


Да, конечно, именно в моем мире. Он же и ваш мир. Мир вообще-то один. Если кто-то не знает, например, о форме земли, это же не значит, что он в каком-то другом мире живет, где земля плоская и на трех слонах стоит — просто он этого еще не знает.

_>А во-вторых это правило будет сохраняться в D даже и для не чистых функций.


Конечно не будет. Потому, что в одном случае все эффекты будут объеденены в две группы, а в другом — чередоваться.

_>Ещё раз: это будут свойства не map'а, а того, что мы подаём ей в качестве аргументов.


Это свойства map-а. Вы не заметили, разве, что в них map фигурирует? Разумеется, эти свойства выполняются для функций.

_>Не помню что за F# код (я кстати не особо в курсе этого языка, хотя говорят там почти точная копия ocaml'а).


> let f (i : int ref) a = a + !i;;
val f : i:int ref -> a:int -> int

> let g (i : int ref) b = i := b; b;;
val g : i:int ref -> b:int -> int

> let i = ref 0 in List.map (f i) << List.map (g i) <| [1..10];;
val it : int list = [11; 12; 13; 14; 15; 16; 17; 18; 19; 20]

> let i = ref 0 in List.map (f i << g i) <| [1..10];;
val it : int list = [2; 4; 6; 8; 10; 12; 14; 16; 18; 20]


_>Нет, в вашей "части кода" присутствует "Vector Int" в роли primes. А в том мутабельном варианте было нечто жуткое вида "data Buffer m a = Buffer { len :: !Int, buf :: !(Vector.Unboxed.Mutable.MVector m a) }". Так вот меня терзают сомнения, справится ли компилятор с оптимизацией для такой штуки... )


Ну правильно. Я MVector m Int "замораживаю" и получаю иммутабельный Vector Int.

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


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

_>Ну конечно. ))) А код в моём соседнем сообщение оказывается из иной реальности. )))


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

_>Пока что по всем тестам ваше "средство оптимизации" болтается среди отстающих по быстродействию... )))


Непонятно только, с чем оно при этом соревнуется, потому что решение моей задачи пока одно — мое, от вас его получить так и не удалось.
'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[96]: Есть ли вещи, которые вы прницпиально не понимаете...
От: Klapaucius  
Дата: 19.06.14 09:44
Оценка:
Здравствуйте, alex_public, Вы писали:

_>Напомню нашу дискуссию:


_>K: В D иммутабельные структуры использовать нельзя, т.к. сборщик мусора не оптимизирован под это.

_>A: В языках типа D есть много других эффективных способов работы с памятью, помимо сборщика мусора.
_>K: Все другие способы тормозные и неудобные.
_>A: Стек и пул будут побыстрее любого сборщика мусора и вполне удобны, в том числе и для иммутабельных данных.
_>K: Ну покажите реализацию того нашего примера с иммутабельными данными на базе стека, пулов или чего угодно.
_>A: Вот код. В нём иммутабельнные данные на стеке и пуле. Работает быстрее всех наших предыдущих примеров.
_>K: Этот код не подходит, т.к. не размещает много объектов в куче.

Нет, я же согласился с тем, что размещать объекты вы можете где угодно. Хоть на стеке (правда, если вы хотите нормальную поддержку иммутабельности в языке, вам и стек в куче скорее всего придется делать), хоть в куче, хоть в подпространстве. Главное чтоб были иммутабельные структуры, их было много и они где-то размещались.

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

_>Ну покажите мне в моём последнем примере хоть одну не иммутабельную структуру данных.

Смотрим мой пример, видим:
[5,7..] производит иммутабельную структуру данных список
filter' isPrime принимает иммутабельную структуру данных список и возвращает иммутабельную структуру данных список
(3: ) принимает иммутабельную структуру данных список и возвращает иммутабельную структуру данных список
(2: ) принимает иммутабельную структуру данных список и возвращает иммутабельную структуру данных список
takeWhile' ((<= x) . (^2)) принимает иммутабельную структуру данных список и возвращает иммутабельную структуру данных список
map (x `rem`) принимает иммутабельную структуру данных список и возвращает иммутабельную структуру данных список
map (/= 0) принимает иммутабельную структуру данных список и возвращает иммутабельную структуру данных список
foldr (&&) True принимает иммутабельную структуру данных список
takeWhile' (<= 2^24) принимает иммутабельную структуру данных список и возвращает иммутабельную структуру данных список
length принимает иммутабельную структуру данных список

Длинный конвейер, промежуточные данные — иммутабельные структуры данных. Все по условию задачи.
Смотрим ваш код — ничего этого нет. Конвейера нет, контейнер мутабельный (если вы такое за иммутабельность считаете — то и мой пример с буфером полностью "иммутабельный" тогда), рейндж, который из слайса [] получается — тоже мутабельный.
'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[95]: Есть ли вещи, которые вы прницпиально не понимаете...
От: alex_public  
Дата: 19.06.14 19:38
Оценка:
Здравствуйте, Klapaucius, Вы писали:

K>Нет, объекты в стиле ООП на ней не нарисованы. На ней нарисованы функции в стиле ФП и определенные на множествах этих функций другие функции. Ничего дальше от ООП чем это просто не бывает, но UML с отображением этого вполне справился. Отсюда вывод, что необходимости что-то в него добавлять для этой цели нет.


Ерунда какая. Большинство нормальных GUI библиотек работают через делегаты (в роли обработчиков сообщений) и при этом полностью базируются на ООП. Т.е. для современного ООП абсолютно привычно иметь у объектов поля, являющиеся указателями на функции, и соответственно методы, работающие с этими полями.

_>>А там речь про другое была. Нет в uml стрелочки "инкапсулированы"... )

K>И что с того?

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

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


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

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


Для начала поясните как код map'а может зависеть от того допускаем мы чистые функции в него или нет.

K>Да, конечно, именно в моем мире. Он же и ваш мир. Мир вообще-то один. Если кто-то не знает, например, о форме земли, это же не значит, что он в каком-то другом мире живет, где земля плоская и на трех слонах стоит — просто он этого еще не знает.


Угу, угу. ))) В Хаскеле само понятие функтора определено через функцию map (ну точнее fmap, но не суть). А в других языках map — это просто одна из функций библиотеки алгоритмов и всё! Да, кстати, а слово функтор в современном промышленном программирование чаще всего обозначает "функциональный объект", а не особый вид отображений из теории категорий. )))

_>>А во-вторых это правило будет сохраняться в D даже и для не чистых функций.

K>Конечно не будет. Потому, что в одном случае все эффекты будут объеденены в две группы, а в другом — чередоваться.

Я же вроде как явно подсказал в предыдущем сообщение, что map в D работает на базе диапазонов. Т.е. в любом случае будет чередоваться. Более того, это касается не только map'а, но и большинства функций из библиотеки алгоритмов D (и соответственно они тоже не будут портить цепочку). Так что то равенство прямо в таком виде не получится испортить в D даже не чистыми функциями.

K>Это свойства map-а. Вы не заметили, разве, что в них map фигурирует? Разумеется, эти свойства выполняются для функций.


Ну как только вы покажете мне отличие кода map'а принимающего только чистые функции от кода map'a принимающего любые, то я тут же с вами соглашусь. )))

K>
>> let f (i : int ref) a = a + !i;;
K>val f : i:int ref -> a:int -> int

>> let g (i : int ref) b = i := b; b;;
K>val g : i:int ref -> b:int -> int

>> let i = ref 0 in List.map (f i) << List.map (g i) <| [1..10];;
K>val it : int list = [11; 12; 13; 14; 15; 16; 17; 18; 19; 20]

>> let i = ref 0 in List.map (f i << g i) <| [1..10];;
K>val it : int list = [2; 4; 6; 8; 10; 12; 14; 16; 18; 20]
K>


Ааа этот помню. ) Просто не заметил, что оно было на F#. Ну так я же уже говорил, что в этом примере в map передаются не чистые функции даже в терминологии D. Но самое забавное, что с такими не чистыми функциями map из D всё равно будет работать корректно:
int i;
auto f(int v) {return v+i++;}
auto g(int v) {return i=v;}
i=0; iota(1, 11).map!g.map!f.writeln;//выводит [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
i=0; iota(1, 11).map!(x=>x.g.f).writeln;//выводит [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]

Я же говорю, диапазоны!)))

K>Ну правильно. Я MVector m Int "замораживаю" и получаю иммутабельный Vector Int.


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

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

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

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

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


Тогда осталось показать не иммутабельные структуры там. )

K>Непонятно только, с чем оно при этом соревнуется, потому что решение моей задачи пока одно — мое, от вас его получить так и не удалось.


Да, я уже понял, что результатом того вашего примера было не вычисление нужного числа и даже не демонстрация работы с иммутабельными данными, а просто выделение побольше объёма в куче. Ну с такими тестами вы явно не по адресу. )))
Re[97]: Есть ли вещи, которые вы прницпиально не понимаете...
От: alex_public  
Дата: 19.06.14 19:57
Оценка:
Здравствуйте, Klapaucius, Вы писали:

K>Нет, я же согласился с тем, что размещать объекты вы можете где угодно. Хоть на стеке (правда, если вы хотите нормальную поддержку иммутабельности в языке, вам и стек в куче скорее всего придется делать), хоть в куче, хоть в подпространстве. Главное чтоб были иммутабельные структуры, их было много и они где-то размещались.


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

K>Смотрим мой пример, видим:

K>[5,7..] производит иммутабельную структуру данных список
K>filter' isPrime принимает иммутабельную структуру данных список и возвращает иммутабельную структуру данных список
K>(3: ) принимает иммутабельную структуру данных список и возвращает иммутабельную структуру данных список
K>(2: ) принимает иммутабельную структуру данных список и возвращает иммутабельную структуру данных список
K>takeWhile' ((<= x) . (^2)) принимает иммутабельную структуру данных список и возвращает иммутабельную структуру данных список
K>map (x `rem`) принимает иммутабельную структуру данных список и возвращает иммутабельную структуру данных список
K>map (/= 0) принимает иммутабельную структуру данных список и возвращает иммутабельную структуру данных список
K>foldr (&&) True принимает иммутабельную структуру данных список
K>takeWhile' (<= 2^24) принимает иммутабельную структуру данных список и возвращает иммутабельную структуру данных список
K>length принимает иммутабельную структуру данных список

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

K>Смотрим ваш код — ничего этого нет. Конвейера нет,


А откуда взялось требование на конвейер? ) Вроде бы был разговор только про иммутабельные структуры и всё. Снова задним числом меняем условия? )))

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


Ну так покажите в какой точке контейнер меняется то... )

K>рейндж, который из слайса [] получается — тоже мутабельный.


Хы, при таком подходе и map в Хаскеле мутабельный, т.к. там счётчик бегает в итоге, а не рекурсия.
Re[96]: Есть ли вещи, которые вы прницпиально не понимаете...
От: Klapaucius  
Дата: 20.06.14 10:12
Оценка:
Здравствуйте, alex_public, Вы писали:

_>Ерунда какая. Большинство нормальных GUI библиотек работают через делегаты (в роли обработчиков сообщений) и при этом полностью базируются на ООП. Т.е. для современного ООП абсолютно привычно иметь у объектов поля, являющиеся указателями на функции, и соответственно методы, работающие с этими полями.


Да какие поля. Там именно функции.

_>Ну так из-за этого и приходится придумывать виртуальные сущности типа классов ООП, вместо того чтобы честно нарисовать типы (одним значком со своими свойствами, тут в принципе значок класса пойдёт), модули с функциями (другим значком, с другими свойствами)


Зачем другим значком? Что вы можете предложить для этого принципиально отличное от "класса"? Это же просто разделенный на части список с заголовком. Для какой группировки сущностей его может не хватить? И механизм заведения своих "значков" уже готовый существует — стереотипы.

_>и как-то обозначить их связи (какой-то новой стрелочкой или как-то ещё).


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

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


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

_>Для начала поясните как код map'а может зависеть от того допускаем мы чистые функции в него или нет.


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

_>Угу, угу. ))) В Хаскеле само понятие функтора определено через функцию map (ну точнее fmap, но не суть).


Абракадабра какая-то.

_>А в других языках map — это просто одна из функций библиотеки алгоритмов и всё!


Проблемы "других языков". Что хорошего-то в том, что это "просто одна из функций"?

_>Да, кстати, а слово функтор в современном промышленном программирование чаще всего обозначает "функциональный объект", а не особый вид отображений из теории категорий. )))


Функтор еще много чего означает в разных контекстах, к примеру, параметризованный модуль в ML. Ну так что?

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


Ну так map можно не только для диапазонов написать, а для любого контейнера. В моем примере на ml не итераторы использованы, а списки.

_>Более того, это касается не только map'а, но и большинства функций из библиотеки алгоритмов D (и соответственно они тоже не будут портить цепочку). Так что то равенство прямо в таком виде не получится испортить в D даже не чистыми функциями.


Почему не получится-то?
Для этого достаточно вставить в конвейер "форсирование" или "кеширование" которое постоянно приходиться при работе с итераторами и аналогами то тут то там вставлять:
> let f a = printf "f"; a;;
val f : a:'a -> 'a
> let g a = printf "g"; a;;
val g : a:'a -> 'a
> Seq.map f << Seq.map g <| [1..5];;
gfgfgfgfgfval it : seq<int> = seq [1; 2; 3; 4; ...]
> Seq.map (f << g) <| [1..5];;
gfgfgfgfgfval it : seq<int> = seq [1; 2; 3; 4; ...]
(* пока все хорошо *)
> Seq.map f << Seq.toList << Seq.map g <| [1..5];;
gggggfffffval it : seq<int> = seq [1; 2; 3; 4; ...]


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


Сначала я вырезал и скомпилировал отдельно, но когда вы попросили промежуточный результат компиляции всего кода, я и его вам предоставил. Вот вам фрагмент из него:
Код
t <- over (U.all ((/= 0) . (rem x)) . U.takeWhile ((<= x) . (^2))) primes 
if t then ...

преобразуется в
letrec {
    $s$wand_loop1
    $s$wand_loop1 =
      \ sc5 ->
        case >=# sc5 tpl1 of _ {
          False ->
            let { __DEFAULT ~ wild12
            <- indexIntArray# ipv3 (+# rb3 sc5)
            } in
            case <=# (*# wild12 wild12) sc4
            of _ {
              False -> True;
              True ->
                case wild12 of wild14 {
                  __DEFAULT ->
                    case remInt# sc4 wild14
                    of _ {
                      __DEFAULT ->
                        $s$wand_loop1
                          (+# sc5 1);
                      0 -> False
                    };
                  (-1) -> False;
                  0 ->
                    case divZeroError
                    of wild15 {
                    }
                }
            };
          True -> True
        }; } in
  case $s$wand_loop1 0 of _ { ...


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


Конечно способен: выбираю наиболее удобный инструмент из тех, что могу себе позволить.

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


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

_>Тогда осталось показать не иммутабельные структуры там. )


Так я и показал.

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


Это прямо в описании задачи и сказано. Я рад, конечно, что после n повторений на разные лады одного и того же вы наконец поняли.

_> Ну с такими тестами вы явно не по адресу.


Конечно не по адресу. Я с самого начала и об этом говорил: нормальной поддержки иммутабельности в 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[98]: Есть ли вещи, которые вы прницпиально не понимаете...
От: Klapaucius  
Дата: 20.06.14 10:45
Оценка:
Здравствуйте, alex_public, Вы писали:

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


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

_>А откуда взялось требование на конвейер? ) Вроде бы был разговор только про иммутабельные структуры и всё. Снова задним числом меняем условия? )))


Читаем условия:

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

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

_>Ну так покажите в какой точке контейнер меняется то... )


Там где ~ используется.

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


Конечно нет. Мап описан на хаскеле как функция работающая с иммутабельной структурой данных. Правила перезаписи для map и прочих функций не переписывают их в функции, которые с мутабельными данными работают.
В случае 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[97]: Есть ли вещи, которые вы прницпиально не понимаете...
От: alex_public  
Дата: 20.06.14 14:32
Оценка:
Здравствуйте, Klapaucius, Вы писали:

K>Зачем другим значком? Что вы можете предложить для этого принципиально отличное от "класса"? Это же просто разделенный на части список с заголовком. Для какой группировки сущностей его может не хватить? И механизм заведения своих "значков" уже готовый существует — стереотипы.


Смысл в том, что значок класса у вас уже занят на другую сущность. Причём с принципиально отличными свойствами. Более того, модули было логично рисовать с визуальным размещением типов и функций внутри. Даже не знаю, что тут лучше предложить. Возможно большой такой прямоугольник, в котором одна часть отделена для списка функций, а в другой свободно располагаются типы (в виде значков классов).

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

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


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

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


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

Кстати, генерация кода по диаграммам — это не особо популярная функция. А вот генерация диаграмм по коду используется очень часто.

K>Код мапа не будет, а код его использующий — тоже в этой же библиотеке — будет.

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

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

_>>А в других языках map — это просто одна из функций библиотеки алгоритмов и всё!

K>Проблемы "других языков". Что хорошего-то в том, что это "просто одна из функций"?

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

K>Ну так map можно не только для диапазонов написать, а для любого контейнера. В моем примере на ml не итераторы использованы, а списки.


Дело не в том что передаём в map, а в том, что возвращаем из него. В D map всегда возвращает диапазон.

K>Почему не получится-то?

K>Для этого достаточно вставить в конвейер "форсирование" или "кеширование" которое постоянно приходиться при работе с итераторами и аналогами то тут то там вставлять:
K>
>> let f a = printf "f"; a;;
K>val f : a:'a -> 'a
>> let g a = printf "g"; a;;
K>val g : a:'a -> 'a
>> Seq.map f << Seq.map g <| [1..5];;
K>gfgfgfgfgfval it : seq<int> = seq [1; 2; 3; 4; ...]
>> Seq.map (f << g) <| [1..5];;
K>gfgfgfgfgfval it : seq<int> = seq [1; 2; 3; 4; ...]
K>(* пока все хорошо *)
>> Seq.map f << Seq.toList << Seq.map g <| [1..5];;
K>gggggfffffval it : seq<int> = seq [1; 2; 3; 4; ...]
K>


Да, всё правильно. Только возвращаясь к нашему равенству... Вы здесь его переделали уже в вид map f.g = map f . h . map f, что собственно никто и не гарантировал даже для чистых функций. )

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

K>...

Спасибо, понятно. Тем более удивительно, что этот ваш пример целиком отстаёт в разы от вариантов на D.

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


Интересная формулировка. т.е. вот для того примера с обработкой видео вы бы лично при проектирование архитектуры приложения выбрали бы мутабельный буфер? )

K>Обычный ход. Выставляем отсутствие нормального сборщика мусора как собственную доблесть.


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

K>Конечно не по адресу. Я с самого начала и об этом говорил: нормальной поддержки иммутабельности в D нет.


Если вы про готовые библиотечные классы контейнеры и т.п., оптимизированные под такие игры, то в стандартной библиотеке их действительно нет. Однако, как вы видели по моему примеру, такие вещи легко пишутся в несколько строк. Вся необходимая поддержка для этого в языке имеется.
Re[99]: Есть ли вещи, которые вы прницпиально не понимаете...
От: alex_public  
Дата: 20.06.14 15:31
Оценка:
Здравствуйте, Klapaucius, Вы писали:

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


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

K>Читаем условия:

K>

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

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

При подобном условие абсолютно невозможно проводить сравнительное тестирование быстродействия. Реально протестировать такие варианты:
1. Код выдающий конкретный результат (например то самое число простых чисел) и использующий только иммутабельные данные. Способы оптимизации не ограничены. Как раз такое я и показал.
2. Код выделяющий N байт (виртуальных, до оптимизации) порциями по M (тут даже сама вычислительная задача не важна). Если есть желание потестировать такое, то я тоже не против.

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

_>>Ну так покажите в какой точке контейнер меняется то... )

K>Там где ~ используется.

У нас используется контейнер IArray, который абстрагирует в себе массив int'ов размером в size (поле в контейнере). Он абсолютно иммутабельный. Мы не можем поменять в нём ни значения в массиве, ни размер массива.

При операции a ~ v, создаётся новый иммутабельный объект типа IArray, размером a.size+1, заполненный данными из a, плюс v. Изначальный контейнер не меняется ни в чём.

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

K>Конечно нет. Мап описан на хаскеле как функция работающая с иммутабельной структурой данных. Правила перезаписи для map и прочих функций не переписывают их в функции, которые с мутабельными данными работают.

K>В случае D это не так. Функции работающие с рейнжем описаны как функции, работающие с мутабельными данными, соотвествующая рейнджу структура данных — мутабельная.

Вообще то range — это просто один бегающий индекс, точно такой же как и внутри map'a. Но если это всё вас так нервирует, то для меня не проблема написать свою функцию вместо find'а, работающую без диапазонов:
bool WhileAny(string P1, string P2, T)(immutable T[] a, T v, int i=0)
{
    if(i>=a.length||binaryFun!P1(a[i], v)) return false;
    if(binaryFun!P2(a[i], v)) return true;
    return WhileAny!(P1, P2)(a, v, i+1);
}

И я даже на всякий случай записал её в виде рекурсии, а не через foreach, а то же в нём тоже типа бегает мутабельный (о ужас!) индекс.

Имея такую библиотечную функцию, наш код для вычисления простых чисел станет выглядеть так:
T Primes(int M, T=immutable IArray!(M, int))(T primes=T.Make()~2~3, int v=5)
{
    if(v>=M) return primes;
    return Primes!M(!primes[].WhileAny!(q{a^^2>b}, q{b%a==0})(v)?primes~v:primes, v+1);
}

И кстати от такой переделки он стал работать ещё где-то на 3% быстрее... )))
Re[98]: Есть ли вещи, которые вы прницпиально не понимаете...
От: Klapaucius  
Дата: 21.06.14 14:09
Оценка:
Здравствуйте, alex_public, Вы писали:

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


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

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


Именно так визуализирует вложенные классы автоматический построитель диаграмм, который в составе Visual Studio.

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


Странно, стереотипы — рекомендованный инструмент для добавления вышеупомянутых интерфейсов, стат.классов и делегатов.

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


Можно обойтись пометкой, что отношение обозначает вложение.

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


Ложная альтернатива. Выше описано как все можно сделать ничего в UML не добавляя.

_>Ну так код, использующий map, знает какие параметры он в него передаёт.


Нет, если он сам их извне получает. Что он конечно и делает, если это обобщенная библиотека функций.

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


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

_>Дело не в том что передаём в map, а в том, что возвращаем из него. В D map всегда возвращает диапазон.


"Мап", который возвращает не тот контейнер, который в него передают — тем более никакого отношения к мапу не имеет.

_>Да, всё правильно. Только возвращаясь к нашему равенству... Вы здесь его переделали уже в вид map f.g = map f . h . map f, что собственно никто и не гарантировал даже для чистых функций. )


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

_>Спасибо, понятно. Тем более удивительно, что этот ваш пример целиком отстаёт в разы от вариантов на D.


Непонятно, откуда вы взяли это отставание "в разы".
Я сравнил производительность кода для нескольких примеров на Win 8.1 i7-3770. Чтоб снизить влияние бекенда я компилировал все компиляторами с одним и тем же бекендом LLVM 3.3 x86, это, соответственно GHC 7.6.3 (-O2) и LDC2 0.12.1 (-O3). Вот что у меня получилось.
Вариант на D без конвейера:
import std.stdio, std.algorithm, std.range;

void main() {
    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;
}

отрабатывает в среднем за 1.86 сек. Пусть это будет 1.
Мутабельный вариант на хаскеле (аналог которого на Ди вы почему-то считаете иммутабельным)
import Control.Applicative
import Control.Monad
import qualified Data.Vector.Unboxed as U
import qualified Data.Vector.Unboxed.Mutable as M

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

работает за 2.03 сек. Что будет 1.09. Менее чем на 10% медленнее, никаких разов. Обратите внимание, что конвейер есть и успешно оптимизирован.
Дальше я замерил скорость кода, похожего на мой первый пример, в котором я дал компилятору проделать больше работы, использовав библиотеку stream-fusion, она представляет функции работы со стандартными списками с другой техникой оптимизации, не той, что в стандартной библиотеке:
import qualified Data.List.Stream as S

primes = 2:3:filter isPrime [5,7..] :: [Int]
isPrime x = S.all (/= 0) . S.map (rem x) . S.takeWhile ((<= x) . (^2)) $ primes
main = print . S.length . S.takeWhile (<= 2^24) $ primes

Эта версия отработала за 2.40 сек. или 1.29 — менее чем 30% замедление относительно Ди-версии, при этом длинный конвейер, все иммутабельное, ленивое и т.д. Это хорошая демонстрация оптимизаций компилятора, но эта версия создает гораздо меньшую нагрузку на память (вместо десятков Гб вделяет сотни Мб) и плохо демонстрирует поддержку рантайма.
Дальше идет версия на Ди с конвейером:
import std.stdio, std.algorithm, std.range;

void main() {
    reduce!((primes, v)=>primes.until!(p=>p^^2>v).all!(p=>v%p)?primes~=v:primes)([3], iota(5, 2^^24, 2)).count.writeln;
}

Выполнилась за 3.78 сек. или 2.03. Т.е. добавление одной стадии в конвейер замедлило код в 2 раза. Печально. Что же будет при конвейере той же длины, что и на хаскеле?
Дальше идет первый пример на хаскеле, который создает нагрузку на менеджер памяти:
primes = 2:3:filter' isPrime [5,7..] :: [Int]
isPrime x = all' (/= 0) . map (x `rem`) . takeWhile' ((<= x) . (^2)) $ primes
main = print . length . takeWhile' (<= 2^24) $ primes

step p res x | p x = (x:) | otherwise = res
takeWhile' p = foldr (step p $ const []) []
all' f = foldr (&&) True . map f
filter' p = foldr (step p id) []

Это 6.99 сек. или 3.76. Тормозной, но для того и написан.

_>Интересная формулировка. т.е. вот для того примера с обработкой видео вы бы лично при проектирование архитектуры приложения выбрали бы мутабельный буфер? )


Да, конечно.

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


Может, конечно, за счет фрагментации/худшей локальности у пула, например.

_>А про стековые переменные я вообще молчу...


Стек покрывает всякие маргинальные сценарии выделения памяти, которые в высокоуровневом коде все равно почти не пригодятся.

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


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

_>Ну так это и есть результат оптимизации с помощью персистентной структуры.


Что еще за оптимизация с помощью персистентной структуры?

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


Что все равно очень мало.

_>При подобном условие абсолютно невозможно проводить сравнительное тестирование быстродействия.


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

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


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

__>У нас используется контейнер IArray, который абстрагирует в себе массив int'ов размером в size (поле в контейнере). Он абсолютно иммутабельный. Мы не можем поменять в нём ни значения в массиве, ни размер массива.

_>При операции a ~ v, создаётся новый иммутабельный объект типа IArray, размером a.size+1, заполненный данными из a, плюс v. Изначальный контейнер не меняется ни в чём.

Но в его реализации на Ди используется изменение массива на месте. Мой буфер из мутабельного примера аналогично реализован.

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


Мне не нравится явное изменение в коде.

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


Только она ручная, а не автоматическая — какое это отношение к поддержке в языке имеет?

_>Вообще то range — это просто один бегающий индекс, точно такой же как и внутри map'a. Но если это всё вас так нервирует, то для меня не проблема написать свою функцию вместо find'а, работающую без диапазонов:


Ну да, конечно. Что может быть дальше от задания "иммутабельные промежуточные данные", чем "мутабельные промежуточные данные"? Правильно: отсутствие промежуточных данных.
'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[99]: Есть ли вещи, которые вы прницпиально не понимаете...
От: alex_public  
Дата: 25.06.14 22:39
Оценка:
Здравствуйте, Klapaucius, Вы писали:

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


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

K>Именно так визуализирует вложенные классы автоматический построитель диаграмм, который в составе Visual Studio.


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

Да, так а что у нас имеется на тему "автоматического построителя диаграмм" для Хаскеля? ) Это я в очередной раз подчёркиваю суть проблемы — не какие-то теоретические трудности, а текущее состояние на рынке.

_>>Ну так код, использующий map, знает какие параметры он в него передаёт.

K>Нет, если он сам их извне получает. Что он конечно и делает, если это обобщенная библиотека функций.

Ну так если получает извне, то именно в этой точке и можно ставить ограничение по типу. А map тут вообще ни при чём.

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


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

K>"Мап", который возвращает не тот контейнер, который в него передают — тем более никакого отношения к мапу не имеет.


Ну а вот в D оно именно такое и при этом носит имя map. Правда это всё равно просто функция из библиотеки, а не что-то большее....

K>Непонятно, откуда вы взяли это отставание "в разы".

K>Я сравнил производительность кода для нескольких примеров на Win 8.1 i7-3770. Чтоб снизить влияние бекенда я компилировал все компиляторами с одним и тем же бекендом LLVM 3.3 x86, это, соответственно GHC 7.6.3 (-O2) и LDC2 0.12.1 (-O3). Вот что у меня получилось.
K>...

Для проверки правильности ваших результатов осталось (ну точнее в идеале было бы мне снова поставить себе хаскель, но что-то лень из-за форумного спора) сделать следующее:

1. Замерить производительность моего полностью иммутабельного примера из соседней ветки. Напоминаю его код:
immutable struct IArray(int L, T){
    immutable auto opSlice() {return data[0..size];}
    immutable auto opBinary(string op)(in T v) if(op=="~")
    {
        auto d=cast(T*)(data);
        d[size]=v;
        return immutable IArray!(L, T)(data, size+1);
    }
    static auto Make()
    {
        return immutable IArray!(L, T)(cast(immutable T*)(GC.malloc(L*T.sizeof, GC.BlkAttr.NO_MOVE)), 0);
    }
    private T* data;
    private int size;
    invariant() {assert(data!=null, "Неинициализированный объект!"); assert(size<L, "Надо бы побольше пул!");}
};
bool WhileAny(string F1, string F2, T)(immutable T[] a, T v, int i=0)
{
    if(i>=a.length||binaryFun!F1(a[i], v)) return false;
    if(binaryFun!F2(a[i], v)) return true;
    return WhileAny!(F1, F2)(a, v, i+1);
}
T Primes(int M, T=immutable IArray!(M, int))(T primes=T.Make()~2~3, int v=5)
{
    if(v>=M) return primes;
    return Primes!M(!primes[].WhileAny!(q{a^^2>b}, q{b%a==0})(v)?primes~v:primes, v+1);
}
void main()
{
    Primes!(2^^24)[].length.writeln;
}

2. Замерить производительность этого http://files.rsdn.ru/98162/Test_D.exe бинарника. Это скопилированный обычным классическим dmd код выше. На случай если вы там что-то напутали с опциями компилятора...

_>>Интересная формулировка. т.е. вот для того примера с обработкой видео вы бы лично при проектирование архитектуры приложения выбрали бы мутабельный буфер? )

K>Да, конечно.

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

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


В сочетание с техникой RAII это даёт ооочень мощный инструмент...

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


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

Кстати, а если бы выделяемые на пуле массивы не пересекались в памяти, а выделялись бы каждый раз целиком рядышком (т.е. как делает обычный ~)... Это что-то изменило бы в вашем видение? ) Замечу, что код при этом не изменился бы ни на букву (была бы та же самая модификация), просто в конструктор передавали бы другой int...
Re[101]: Есть ли вещи, которые вы прницпиально не понимаете...
От: alex_public  
Дата: 25.06.14 22:48
Оценка:
Здравствуйте, Klapaucius, Вы писали:

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


Во-первых тогда надо однозначно договориться о количестве передаваемых данных и о количестве шагов конвейера. Т.е. в конкретных цифрах.

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

K>Но в его реализации на Ди используется изменение массива на месте. Мой буфер из мутабельного примера аналогично реализован.


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

K>Только она ручная, а не автоматическая — какое это отношение к поддержке в языке имеет?


Вот, тут вы правы. Но главное что язык позволяет легко делать подобные вещи. Как вы видите, всего несколько строк и гораздо более эффективный код, чем все ваши варианты.
Re[100]: Есть ли вещи, которые вы прницпиально не понимаете...
От: Klapaucius  
Дата: 27.06.14 10:39
Оценка:
Здравствуйте, alex_public, Вы писали:

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


Непонятно, к чему это упомянуто? Хотите сказать, что для использования с почти всеми остальными ОО-языками, где это не так, UML непригоден? Вот так сюрприз!

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


Много ли общих свойств у стат.класса и делегата? И тот и другой обозначаются одним значком с разными стереотипами.

_>Хы, а я это с ходу придумал.


Это просто показатель того как вы читаете мои ответы. Я такой вариант сразу и предложил.

_>Только при таком раскладе в Хаскеле (в отличие от ООП языков со вложенными классами) будет теряться отношение инкапсуляции между типами и их функциями. Надо или новый вид связи или ещё что-то...


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

_>Да, так а что у нас имеется на тему "автоматического построителя диаграмм" для Хаскеля? )


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

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


Мы вроде бы как раз теоретические трудности и обсуждали. Точнее существующую, якобы, необходимость расширить UML нестандартными средствами.

_>Ну так если получает извне, то именно в этой точке и можно ставить ограничение по типу. А map тут вообще ни при чём.


Т.е. полезность такой проверки вы все-таки не отрицаете, главное чтоб не для map-а?

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


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

_>Ну а вот в D оно именно такое и при этом носит имя map. Правда это всё равно просто функция из библиотеки, а не что-то большее....


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

_>Для проверки правильности ваших результатов осталось (ну точнее в идеале было бы мне снова поставить себе хаскель, но что-то лень из-за форумного спора) сделать следующее:


_>1. Замерить производительность моего полностью иммутабельного примера из соседней ветки. Напоминаю его код:


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

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


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

_>В сочетание с техникой RAII это даёт ооочень мощный инструмент...


Мощный по сравнению с чем? Для высокоуровневых языков он недостаточно мощный, и даже его существенно более мощное развитие — вывод регионов — тоже, как показали эксперименты с MLKit и JHC, недостаточно мощное. Никакой практичной альтернативы ГЦ для высокоуровневых языков все еще не существует.

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

_>Кстати, а если бы выделяемые на пуле массивы не пересекались в памяти, а выделялись бы каждый раз целиком рядышком (т.е. как делает обычный ~)... Это что-то изменило бы в вашем видение? ) Замечу, что код при этом не изменился бы ни на букву (была бы та же самая модификация), просто в конструктор передавали бы другой int...

Нет, это не изменило бы мое виденье. Потому что вы измеряете производительность работы с мутабельным массивом, а не иммутабельными структурами данных. То, что вы его называете "пулом" после того, как я сказал о том, что размещать иммутабельные структуры можно где угодно — ничего не меняет.
'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[102]: Есть ли вещи, которые вы прницпиально не понимаете...
От: Klapaucius  
Дата: 27.06.14 11:06
Оценка:
Здравствуйте, alex_public, Вы писали:

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


_>Во-первых тогда надо однозначно договориться о количестве передаваемых данных и о количестве шагов конвейера. Т.е. в конкретных цифрах.


Так в чем проблема? Число стадий конвейера видно в коде, объемы размещаемых данных без и с оптимизациями я дал. Какие еще цифры нужны?

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


Заключающейся в том, что они мутабельные. Действительно, нелепая придирка: говорим о поддержке иммутабельности и измеряем производительность работы с мутабельными структурами. Казалось бы, какая разница: иммутабельные или мутабельные, дядька или бузина, Киев или огород?

_>А переписывать все циклы в рекурсии (чтобы компилятор сделал обратное потом) во всей библиотеке мне как-то лень...


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

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


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

K>>Только она ручная, а не автоматическая — какое это отношение к поддержке в языке имеет?

_>Вот, тут вы правы.

Если вы сами признаете это, то тогда о чем разговор вообще? См. выделенное.

_>Но главное что язык позволяет легко делать подобные вещи.


Позволяет с мутабельными данными работать? Тоже мне бином Ньютона! И при чем тут поддержка иммутабельности-то?

_>Как вы видите, всего несколько строк и гораздо более эффективный код, чем все ваши варианты.


Т.е. есть код состоящий из изменения массива на месте на Ди, и он на 30% быстрее чем высокоуровневый код, работающий с иммутабельными списками и с длинным конвейером на хаскеле. Также известно, что если добавить в код на ди конвейер хотя-бы из 2-х стадий — он уже в полтора раза медленнее хаскельного примера станет. Какой можно вывод сделать из этого? Ну, какой-то вывод о поддержке иммутабельности в хаскеле можно сделать. Можно также сделать вывод о том, насколько хорошо компилятор ди оптимизирует код с рейнджами. А вот что можно сказать о поддержке иммутабельности в Ди? Ничего, если только не интерпретировать вашу неспособность/нежелание написать на ди релевантный пример как какие-то проблемы с ди.
'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[101]: Есть ли вещи, которые вы прницпиально не понимаете...
От: alex_public  
Дата: 30.06.14 18:27
Оценка:
Здравствуйте, Klapaucius, Вы писали:

K>Много ли общих свойств у стат.класса и делегата? И тот и другой обозначаются одним значком с разными стереотипами.


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

K>Отношения инкапсуляции между типами и определенными на них функциями не существует. На практике диаграмма для хаскеля будет отличатся от диаграммы для Явы тем, что Разделение на блоки по видимостям будет только у знаков класса первого уровня. У всех вложенных разделения членов по видимости не будет.


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

K>Мы вроде бы как раз теоретические трудности и обсуждали. Точнее существующую, якобы, необходимость расширить UML нестандартными средствами.


Расширение стандарта — это как раз практическая трудность, а не непреодолимое теоретическое препятствие.

_>>Ну так если получает извне, то именно в этой точке и можно ставить ограничение по типу. А map тут вообще ни при чём.

K>Т.е. полезность такой проверки вы все-таки не отрицаете, главное чтоб не для map-а?

Я вообще люблю всяческие виды проверок. Поэтому как раз и не очень люблю динамические языки. Нюанс в том, что я хочу ими управлять, а не получать их свыше (как в случае Хаскеля). Т.е. на мой вкус и большинство динамических языков и решения типа Хаскеля являются ограниченными (в сравнение с языками типа C++, D и т.п.), просто противоположными способами. Как в динамических языках мы обычно просто не можем добавить нужные ограничения на нужной стадии, так в Хаскеле мы не можем написать код без следования множеству уже введённых ограничений. А вот в нормальных языках у нас полная свобода для самовыражения. Хотим ограничить аргументы нашей функции иммутабельными параметрами или чистыми функциями — легко. Хотим работать с произвольными данными — не проблема (и без всякого изменения/усложнения кода).

K>Явление известное. Взять что-то, назвать "лямбда", "мап" или, еще лучше, "все_есть", а потом заявлять на форумах: "вот вы говорите, что у нас ничего нет, а у нас "все_есть" — вот она, эта функция".


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

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


Возможно оптимизация не работает. Что вполне характеризует выбранные вами для тестирования инструменты. ))) Что-то мешало поставить себе dmd? )

Да, а что помешало протестировать мой бинарник? )

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

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

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

K>Мощный по сравнению с чем? Для высокоуровневых языков он недостаточно мощный, и даже его существенно более мощное развитие — вывод регионов — тоже, как показали эксперименты с MLKit и JHC, недостаточно мощное. Никакой практичной альтернативы ГЦ для высокоуровневых языков все еще не существует.


Как раз в последние дни работаю с языком общего назначения, после которого Хаскель кажется очень низкоуровневым... И там вполне себе есть опция "С GC или без". )

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


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

К примеру если мы возьмём многие реализации сборщиков мусора или даже куч (типа как в C++), то там частенько выделяется один большой блок каким-нибудь VirtualAlloc'ом и потом уже нарезается для конкретных данных. Соответственно если считать, что выделение памяти происходит в VirtualAlloc (прямо по вашей логике в нашем примере), то окажется что у нас есть один мутабельный блок памяти, который постоянно модифицируется, и ничего иммутабельного быть не может (хотя на самом деле возможно выделяются только такие данные), в том числе и в Хаскеле. Соответственно если вы всё же не считаете подобное выделением памяти, то тогда почему не позволяете применить ту же самую логику к моему коду? ) Ведь с этой точки зрения отличие моего iarray от библиотечного new исключительно в том, что мой класс не входит в стандартную библиотеку языка.
Re[103]: Есть ли вещи, которые вы прницпиально не понимаете...
От: alex_public  
Дата: 30.06.14 18:59
Оценка:
Здравствуйте, Klapaucius, Вы писали:

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


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

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


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

K>Впрочем, объем труда незначительный, объявить иммутабельный список нетрудно (это не finger-tree какой-нибудь), несколько функций написать — тоже. Правда зарание понятно, что производительность всего этого будет крайне низкой, и даже такого незначительного труда на подтверждение такого очевидного факта тратить жаль.


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

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


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

K>Т.е. есть код состоящий из изменения массива на месте на Ди, и он на 30% быстрее чем высокоуровневый код, работающий с иммутабельными списками и с длинным конвейером на хаскеле.


Код то есть, но вы отделываетесь отговорками о неспособности его запустить из-за использования маргинального (для D) компилятора.

K>Также известно, что если добавить в код на ди конвейер хотя-бы из 2-х стадий — он уже в полтора раза медленнее хаскельного примера станет. Какой можно вывод сделать из этого? Ну, какой-то вывод о поддержке иммутабельности в хаскеле можно сделать. Можно также сделать вывод о том, насколько хорошо компилятор ди оптимизирует код с рейнджами.


Ну вообще то диапазоны D как раз очень эффективно оптимизируют именно это дело. По примеру с map'и думаю было видно. Почему это не сработало в случае пары takeUntil.Any даже не представляю (а разбираться сейчас особо желания нет), но уверен что это какая-то недоработка реализации конкретно одного из этих алгоритмов, а не проблема самого принципа диапазонов. В большинстве, встреченных мною случаев, они оптимизировали конвейер любой длинны до одного цикла.
Re[102]: Есть ли вещи, которые вы прницпиально не понимаете...
От: Klapaucius  
Дата: 01.07.14 12:12
Оценка:
Здравствуйте, alex_public, Вы писали:

K>>Много ли общих свойств у стат.класса и делегата? И тот и другой обозначаются одним значком с разными стереотипами.

_>Естественно, оба же классы — могут содержать поля и методы, могут наследоваться и т.п.

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

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


И, следовательно, во вашей логике UML для C# использовать нельзя, правильно?

_>Причём тут вообще вложенные классы? ) Тем более при их забавной частоте использования в ООП...


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

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


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

_>Расширение стандарта — это как раз практическая трудность, а не непреодолимое теоретическое препятствие.


Ну допустим. И что?

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


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

_>Т.е. на мой вкус и большинство динамических языков и решения типа Хаскеля являются ограниченными (в сравнение с языками типа C++, D и т.п.), просто противоположными способами. Как в динамических языках мы обычно просто не можем добавить нужные ограничения на нужной стадии, так в Хаскеле мы не можем написать код без следования множеству уже введённых ограничений. А вот в нормальных языках у нас полная свобода для самовыражения. Хотим ограничить аргументы нашей функции иммутабельными параметрами или чистыми функциями — легко. Хотим работать с произвольными данными — не проблема (и без всякого изменения/усложнения кода).


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

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


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

_>Возможно оптимизация не работает. Что вполне характеризует выбранные вами для тестирования инструменты. ))) Что-то мешало поставить себе dmd? )


Я вроде написал, почему я использовал не dmd (хотя я тогда думал, что ldc2 — это и есть dmd, только с llvm-бэкендом). Для того, чтоб исключить из сравнения фактор бэкенда. Судя по всему, решение было верным.

Я поставил DMD32 D Compiler v2.065, правда уже на другой компьютер (3330), но все остальное (ghc, llvm, windows) осталось без изменений.
Компилировал с -O -inline
Результаты такие:
На первом месте теперь haskell.
Версия, аналогичная той, что вы называете иммутабельной работает за 2.52 сек. или 0.95
Дальше самая быстрая версия на Ди, та, что с find — 2.66 сек. или 1. (если не указывать -O и -inline — то 6.19 сек, так что оптимизатор что-то делает)
Дальше хаскель со stream-fusion — 3.00 или 1.13
Дальше та, что вы называете "иммутабельной". Без оптимизации она падает, кстати, и с dmd, но с оптимизацией работает выдает ответ за 3.57 сек. или 1.34. (если сравнивать с аналогом на хаскеле, в котором, кстати, конвейер и нет рукописной лапши — вообще 1.40)
Короче говоря, если для ди не использовать llvm, а для хаскеля наоборот использовать, то самая быстрая ваша мутабельная версия практически не отличается от высокоуровневой полностью иммутабельной хаскельной и медленнее хаскельной с мутабельным буфером.

Поэтому ваши претензии к тому, что я сравнивал честнее — вообще звучат странно. Судя по find-версии, кодогенератор у dmd не фонтан, а единственное, что ldc2 не соптимизировал — это рекурсия. Впрочем, рекурсивно-лапшевая версия все равно тормозная, не понятно, за что вы боролись написав столько адского кода со строковыми параметрами шаблонов вместо нормальной передачи функций, кастами иммутабельных массивов в мутабельные и прочими ужасами.

_>Да, а что помешало протестировать мой бинарник? )


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

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


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

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

_>Как раз в последние дни работаю с языком общего назначения, после которого Хаскель кажется очень низкоуровневым... И там вполне себе есть опция "С GC или без". )


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

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


Нет, вопрос не в том, когда выделяется память и выделяется ли вообще.

_>Ведь с этой точки зрения отличие моего iarray от библиотечного new исключительно в том, что мой класс не входит в стандартную библиотеку языка.


Нет, отличие не в этом. Иммутабельная структура данных или нет видно из ее описания в библиотеке.
К примеру, структуры данных которые участвуют в конкурсе со стороны хаскеля выглядят так:
data [] a = [] | a : [a]

-- и

data Stream a where
  Stream :: Unlifted s => !(s -> Step a s) -> !s -> Stream a

data Step a s = Yield a !s | Skip !s | Done

Как видите, никаких массивов и изменений их на месте тут не просматривается. Понятно, что размещается это все в конечном итоге в некоем "мутабельном массиве" — памяти, но это не повод пропустить этот этап и заявлять, что мутабельные массивы — это и есть иммутабельные структуры данных.
'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
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.