ой, кстати, да, как реализовать рейндж всех нечётных интов одним iota, без фильтра?
можно cделать трансформ из n в 2*n + 1
а то вы так долго напирали, что у меня немощно и плохо всё
так вы повоторите хоть то что в iota есть. Если бесконечный ренж неподдерживается то ладно, я вроде такое не просил.
Только в очередной раз не сделали их размер определяется наличием имени,
там проблема наверное в том что старые итераторы в уже существующем коде хотели продолжать поддерживать, в новом коде iterator_category определяется.
Хоспаде, ну наконец-то!
Я ничего сложного не просил. Просто есть вектор vec, r1 = vec | transform(f) известен размер и есть доступ к элементам, r2 = vec | filter(g) тут размера нету есть только forward итератор. Есть например
auto foo(range auto r) { return r | transform(h); }
Сохраняются свойства и при передаче r1 и r2, удобно.
На уровне реализации во всех этих рефах хранится указатель, поэтому атомарность бесплатная.
Если передаётся рефы всё равно вопрос как их менять. Либо копировать, либо менять инплейс.
В раст я не понял как этим пользоваться. Из статьи и кода бенчмарка непонятно. Как будет индексироваться Vector3<f32x4>, индексами от 0 до 3 или от 0 до 12?
Это ForeignPtr. GC знает, что и как финализировать.
Ок, получается имплементировать эту часть на языке не надо т.к. она встроена в язык. В джава или C# я такой штуки не знаю (но может есть).
Так за iota и рандомного доступа нет, поди пойми, что вам надо.
Для чисел есть
Зачем сюда Range? У нас тут отдельная ветвь дискуссии, где мы обсуждаем голые функции.
Вы почему-то продолжаете делать вид что не понимаете разницу между контейнерами, функциями и ренжами.
А если у меня там будет pair<width, height> size()?
Никто не запрещает в С++ делать именованные маркеры. А так да, подходы разные, и это уже другая тема. В расте с трейтами аналогичную проблему всё же как-то решают.
Ненене, вы саму zip_transform напишите. На плюсах же с шаблонами всё просто, так что как это будет выглядеть?
zip_transform принимает сколько угодно ренжей, жду для начала вариадиков в хаскеле.
а оно не sized_range
Это недоработка реализации. Бесконечный размер на уровне типов приравнен к неизвестному размеру. Ваш пример с zip кстати как раз неизвестный размер тоже не покрыл.
Если игнорировать нюансы со ссылками то можно повторить ваш искуственный пример как-то так
template<typename F>
struct Unbounded {
F f;
};
template<typename F>
struct Bounded {
F f;
size_t len;
};
template<typename T>
concept HasLen = requires(T x) {
x.len;
};
auto zipWith(auto f, HasLen auto a, HasLen auto b) {
return Bounded([=](size_t i) { return f(a.f(i), b.f(i)); }, std::min(a.len, b.len));
}
auto zipWith(auto f, HasLen auto a, auto b) {
return Bounded([=](size_t i) { return f(a.f(i), b.f(i)); }, a.len);
}
auto zipWith(auto f, auto a, HasLen auto b) {
return Bounded([=](size_t i) { return f(a.f(i), b.f(i)); }, b.len);
}
auto zipWith(auto f, auto a, auto b) {
return Unbounded([=](size_t i) { return f(a.f(i), b.f(i)); });
}
Так делать не надо потому что это не реализует нужных концептов для итераторов/ренжей.
Хотя я пока писал понял что смысла в таком Unbounded нету совсем. У нас либо рандом аксесс и тогда мы знаем границы, либо не знаем границ и достаём по-одному. Получается бестолковый пример обсуждаем :/
Мутируете, делаете freeze, кладёте в TVar или что-то подобное, в другой транзакции достаёте, делаете thaw, мутируете.
сложность thaw O(n), т.е. оно делает копию. Вообще продолажая тему про IORef я не понял как там атомарно поменять что-то размером больше инта.
В сложных примерах я не замечу, что два раза читаю из IORef
Если есть гарантия что владение переменной однопоточное, то в чём проблема?
Если можете как человек гарантировать, что это безопасно,
Посыл нашего обсуждения что гарантировать должен компилятор, а не человек.
запилят поддержку линейных типов.
Поэтому раст тут получается впереди, о чём изначально и говорилось по ссылке. Борроу чекер в паре с send/sync даёт больше выразлительности.
А как такое работает? ptr это что? Обычно массив это внтуренний примитив и ссылку на место где лежит элемент взять так просто нельзя. Или язык должен предоставлять специальный примитив для этого, который поидее и будет содержать ссылку на сам массив. Иначе как гц узнает связь между (ptr+i) и аллокацией c началом ptr?
Получается Vector это вью для последовательной аллокации? Тогда его всё равно нельзя использовать как параметр для ренжа с O(1) доступом, потому что за iota нету никакой аллокации. Зачем вы мне его предлагали?
Зачем для этого тайпкласс? Композицию функций уже отменили? transform :: (Int -> a) -> (a -> b) -> (Int -> b)
Не вижу как сюда передать объект типа Range, или какой вы там создали?
toList
В тот момент когда надо писать такие явные преобразования код перестаёт быть женерик.
А как вы там в типах отличаете ограниченные и неограниченные рейнджи?
По наличию перегрузки size()
auto x = zip_transform(std::plus{}, iota(3, 10), iota(3, 20));
static_assert(sized_range<decltype(x)>);
std::println("{}", x.size());
auto y = zip_transform(std::plus{}, iota(100), iota(200));
static_assert(!sized_range<decltype(y)>);
Потому что контейнер тегирован s, которая должна иметь возможность быть произвольной во всём скоупе runST (об этом говорит тип runST). Как только вы его куда-то кладёте, оно больше не может быть произвольным.
Т.е. у меня контейнер создаётся и умирает вместе с runST? Или создаётся мутабельный вью?
Я хочу взять например вектор, мутировать его в одном потоке, потом мувнуть его в другой поток и продолжить мутировать там.
А подёргать STM внутри runST тоже нельзя, потому что STM дёргается через atomically , которая живёт в IO, и которую нельзя поэтому дёргать внутри runST.
А как мне писать код который одновременно и читает что то из тред-сейф объекта расшареного и на основе этого модифицирует тред-локальный стейт?
Нет разницы между своей и чужой аллокацией. GC, все дела.
а как это тогда работает? Я представлял себе класс слайса как набор из (otherVector, begin, end) и оператор[i] который возвращает otherVector[begin+i]. Сам otherVector держится/очищается через GC, а не вручную.
Что не смог? Я вам миллион примеров уже привёл под каждую из ваших уточнённых задач согласно каждому из ваших пожеланий
Ну я же просил в самом начале, целостный пример который все задачи обобщенно решает, а не какие-то отрывки.
of — это кусок case, ; разделяет бранчи, чтобы написать в одну строчку в репле. Можно было бы
фух, в новом виде наконец хаскель можно прочитать. спасибо
Зачем отдельный тайпкласс для метода, когда можно, блин, просто передать метод?
Что бы трансформ сделать
transform :: Range k a -> a - > b -> Range k b
и сохранить operator[] после трансформа.
Можно сравнить со страхолюдием из плюсов в темплейтах, кстати.
Первая часть это же просто определение двух конструкторов структур которые ничего не делают. В С++ такое писать особо не надо. Что делает deriving Functor мне не понятно.
А хотя я немного подумал и понял, что скорее всего теперь это класс можно через fmap оттрансформировать но нельзя запихнуть в метод который ожидает [a]. Так что вопрос про transform отменяется.
Система типов запрещает и rank-2 polymorphism. Попробуйте, короче, сами.
Т.е. у нас контекст runSTM который берёт лок на все STM контейнеры? Всё еще не понял почему я не могу ST контейнер передать между потоками, как вообще что то в поток передать? Если через IORef будет уб то как без уб? Как с этим разобраться новичку.
Много компиляторов продублирует load из атомика после проверки?
Так если load() один то всё хорошо, я специально явно два раза его запросил в примере. В сложных примерах вы такую проблему не заметите сразу. Как раз дублировать лоад это будет баг компилятора.
его компиляторы и так не делают кучу оптимизаций, которые они могли бы делать, поэтому более безопасные языки в безопасности!
Оптимизаций которые они делают достаточно чтобы синхронизировать память через атомики и ставить мемори барьеры было обязательным.
А думать о том, куда надо get делать, вперёд или назад, не надо?
Не надо, это закрытое множество вариантов.
Вообще интуитивно у меня будет отдельно контроллер списка, и отдельно несколько способов его вызывать. Скорее всего из разных диалогов. Например, какой-то общий диалог поиска писем и спец кнопка перейти к следующиму непрочитаному во фрейме отображения письма. И тут иметь готовый findNext(pred), который я могу переиспользовать лучше чем findAndSelect.
Плюс, theorems for free и всё такое.
Во-перых это не имеет никакого отношения к С++. Во-вторых что тут это даёт?
Вариативность вперёд-назад уже достаточна, как по мне.
как по мне для того чтобы объединить две строчки (find_if + select) в новый метод этого не достаточно.
Читать одинаково нормально. Использовать getPrev() как одну сущность проще чем писать get, а потом думать какой итератор надо туда вставить. Решение с ренжем в качестве аргумента даёт большую гибкость тому кто будет использовать код, с другой стороны накладывает больше мыслительной работы. Абстрагировать надо в точках где ожидается вариативность. Если там prev/next/left/right/up/down/diagonal/whatever то это другое дело.
Читайте еще раз. Вы привели одну фразу про ГЦ, и пол фразы про другие языки. Одна цитата как раз про контроль качества зависимостей.
Даже если бы в ветке было бы в основном про гц, в чем проблема ответить на ту часть сообщение которую я считаю нужным прокоментировать?
Ага, бороться с зоопарком систем сборки, когда половина зависимостей настроена на динамическую линковку. Реально, но очень долго.
Не знаю о чём вы, у меня такого нету.
И все же что вы будете делать с dll от вендора?
Давайте начнём с того как вендор создаст dll на раст и что вы будете делать с ней?
Пробелмы поставки библиотек в бинарном формате это отдельная проблема. То что в расте это сделать нельзя говорит лишь об ограниченности раста и что он неприменим для вендоров блобов. Хотя скорее всего можно за сишным интерфейсом спрятать реализацию на расте, тогда возвращаемся к той же проблеме.
Будет ссылка на область памяти, которая будет удерживать GC от её удаления, даже если исходный вектор сдохнет
т.е. это таки некий тайпкласс у которого может быть несколько реализаций? Ссылка на другой вектор или ссылка на какую-то свою аллокацию?
У меня вопрос не про владение, можно как одну из реализаций сделать слайс который в отличие от std::span делает рефкаунт (например растовый hyper::Bytes).
Тогда юзайте списки и делайте по ним map, потому что ваш трансформатор, скорее всего, не random access
В цпп сделано, в раст сделано, а хаскель не смог поэтому ненужно. Понятно..
Так вам примитивы писать или целевой прикладной код, их использующий?
И то и то. Что мне запрещает расшарить ST вектор между потоками вместо STM? Как я для своего контейнера могу определить можно его шарить или нет?
Где здесь ub?
Значение поменяется из другого потока и в getUnchecked будет уже не тот индекс который прошёл проверку строчкой выше, n это например длина контейнера.
Это который ...
Да это тот самый ллвм который вы использовали чтобы хоть как то сравнятся по скорости с цпп в своих экспериментах. И тот самый который растеры взяли потому что сами сделать свой не смогли.
можете трансформать обычным fmap после этого
Распарсить что делает of и ; я не смог, но идею понял. Хотя вместо Functor нужно иметь тайпкласс который умеет как раз в метод который даёт Int -> a. Т.е. вот это вот всё надо спроектировать и т п. Не рокет сайнс конечно, но и выдавать однострочники за какие то решения это слишком.
По порядку величин то же самое. Я прочел ваше сообщение и подумал что вы противопоставляете полдюжины аспирантов с сотней разработчиков на зарпалтах у апл и гугла...
Имхо в таком примере это преждевременное создание абстракций, получается усложнение. getNext/getPrev выглядит проще и понятнее. К тому же это ближе к реальному функционалу юай - там есть кнопки prev/next и у вас в программе будут такие методы, a не какой-то findAndSelect(forward).
"Btw I use arch"
Мало кто знает что "r" в scrum не читается
можно cделать трансформ из n в 2*n + 1
так вы повоторите хоть то что в iota есть. Если бесконечный ренж неподдерживается то ладно, я вроде такое не просил.
там проблема наверное в том что старые итераторы в уже существующем коде хотели продолжать поддерживать, в новом коде iterator_category определяется.
Я ничего сложного не просил. Просто есть вектор vec,
r1 = vec | transform(f)
известен размер и есть доступ к элементам,r2 = vec | filter(g)
тут размера нету есть только forward итератор. Есть напримерСохраняются свойства и при передаче r1 и r2, удобно.
Если передаётся рефы всё равно вопрос как их менять. Либо копировать, либо менять инплейс.
Я не вижу как одна фича противоречит другой.
В раст я не понял как этим пользоваться. Из статьи и кода бенчмарка непонятно. Как будет индексироваться
Vector3<f32x4>
, индексами от 0 до 3 или от 0 до 12?Апд исправил форматирвание
Мне лень участвовать в демагогии что конструктивно а что нет.
Фичей eigen в nalgebra нету потому что их невозможно реализовать на расте.
Ок, получается имплементировать эту часть на языке не надо т.к. она встроена в язык. В джава или C# я такой штуки не знаю (но может есть).
Для чисел есть
Вы почему-то продолжаете делать вид что не понимаете разницу между контейнерами, функциями и ренжами.
Никто не запрещает в С++ делать именованные маркеры. А так да, подходы разные, и это уже другая тема. В расте с трейтами аналогичную проблему всё же как-то решают.
zip_transform
принимает сколько угодно ренжей, жду для начала вариадиков в хаскеле.Это недоработка реализации. Бесконечный размер на уровне типов приравнен к неизвестному размеру. Ваш пример с zip кстати как раз неизвестный размер тоже не покрыл.
Если игнорировать нюансы со ссылками то можно повторить ваш искуственный пример как-то так
Так делать не надо потому что это не реализует нужных концептов для итераторов/ренжей.
Хотя я пока писал понял что смысла в таком Unbounded нету совсем. У нас либо рандом аксесс и тогда мы знаем границы, либо не знаем границ и достаём по-одному. Получается бестолковый пример обсуждаем :/
сложность thaw O(n), т.е. оно делает копию. Вообще продолажая тему про IORef я не понял как там атомарно поменять что-то размером больше инта.
Если есть гарантия что владение переменной однопоточное, то в чём проблема?
Посыл нашего обсуждения что гарантировать должен компилятор, а не человек.
Поэтому раст тут получается впереди, о чём изначально и говорилось по ссылке. Борроу чекер в паре с send/sync даёт больше выразлительности.
В чем неконструктивность если я просто констатирую факты?
А так да, будем ждать ¯_(ツ)_/¯
А как такое работает? ptr это что? Обычно массив это внтуренний примитив и ссылку на место где лежит элемент взять так просто нельзя. Или язык должен предоставлять специальный примитив для этого, который поидее и будет содержать ссылку на сам массив. Иначе как гц узнает связь между (ptr+i) и аллокацией c началом ptr?
Получается Vector это вью для последовательной аллокации? Тогда его всё равно нельзя использовать как параметр для ренжа с O(1) доступом, потому что за iota нету никакой аллокации. Зачем вы мне его предлагали?
Не вижу как сюда передать объект типа
Range
, или какой вы там создали?В тот момент когда надо писать такие явные преобразования код перестаёт быть женерик.
По наличию перегрузки
size()
Т.е. у меня контейнер создаётся и умирает вместе с runST? Или создаётся мутабельный вью?
Я хочу взять например вектор, мутировать его в одном потоке, потом мувнуть его в другой поток и продолжить мутировать там.
А как мне писать код который одновременно и читает что то из тред-сейф объекта расшареного и на основе этого модифицирует тред-локальный стейт?
а как это тогда работает? Я представлял себе класс слайса как набор из (otherVector, begin, end) и оператор[i] который возвращает otherVector[begin+i]. Сам otherVector держится/очищается через GC, а не вручную.
Ну я же просил в самом начале, целостный пример который все задачи обобщенно решает, а не какие-то отрывки.
фух, в новом виде наконец хаскель можно прочитать. спасибо
Что бы трансформ сделать
и сохранить operator[] после трансформа.
Первая часть это же просто определение двух конструкторов структур которые ничего не делают. В С++ такое писать особо не надо. Что делает deriving Functor мне не понятно.
А хотя я немного подумал и понял, что скорее всего теперь это класс можно через fmap оттрансформировать но нельзя запихнуть в метод который ожидает
[a]
. Так что вопрос про transform отменяется.Т.е. у нас контекст runSTM который берёт лок на все STM контейнеры? Всё еще не понял почему я не могу ST контейнер передать между потоками, как вообще что то в поток передать? Если через IORef будет уб то как без уб? Как с этим разобраться новичку.
Так если load() один то всё хорошо, я специально явно два раза его запросил в примере. В сложных примерах вы такую проблему не заметите сразу. Как раз дублировать лоад это будет баг компилятора.
Оптимизаций которые они делают достаточно чтобы синхронизировать память через атомики и ставить мемори барьеры было обязательным.
А аргументация будет?
Не надо, это закрытое множество вариантов.
Вообще интуитивно у меня будет отдельно контроллер списка, и отдельно несколько способов его вызывать. Скорее всего из разных диалогов. Например, какой-то общий диалог поиска писем и спец кнопка перейти к следующиму непрочитаному во фрейме отображения письма. И тут иметь готовый findNext(pred), который я могу переиспользовать лучше чем findAndSelect.
Во-перых это не имеет никакого отношения к С++. Во-вторых что тут это даёт?
как по мне для того чтобы объединить две строчки (find_if + select) в новый метод этого не достаточно.
Читать одинаково нормально. Использовать getPrev() как одну сущность проще чем писать get, а потом думать какой итератор надо туда вставить. Решение с ренжем в качестве аргумента даёт большую гибкость тому кто будет использовать код, с другой стороны накладывает больше мыслительной работы. Абстрагировать надо в точках где ожидается вариативность. Если там prev/next/left/right/up/down/diagonal/whatever то это другое дело.
Читайте еще раз. Вы привели одну фразу про ГЦ, и пол фразы про другие языки. Одна цитата как раз про контроль качества зависимостей.
Даже если бы в ветке было бы в основном про гц, в чем проблема ответить на ту часть сообщение которую я считаю нужным прокоментировать?
Не знаю о чём вы, у меня такого нету.
Давайте начнём с того как вендор создаст dll на раст и что вы будете делать с ней?
Пробелмы поставки библиотек в бинарном формате это отдельная проблема. То что в расте это сделать нельзя говорит лишь об ограниченности раста и что он неприменим для вендоров блобов. Хотя скорее всего можно за сишным интерфейсом спрятать реализацию на расте, тогда возвращаемся к той же проблеме.
Люблю комментарии на Хабре за их точность )))
Лучше вы сами внимательно перечитайте. В ветке было про сборку раст и с++.
В чем проблема в С++ делать компиляцию всего дерева из исходников со статической линковкой и нужными флагами санитайзера?
А как в ней "грепнуть по unsafe" ?
т.е. это таки некий тайпкласс у которого может быть несколько реализаций? Ссылка на другой вектор или ссылка на какую-то свою аллокацию?
У меня вопрос не про владение, можно как одну из реализаций сделать слайс который в отличие от std::span делает рефкаунт (например растовый
hyper::Bytes
).В цпп сделано, в раст сделано, а хаскель не смог поэтому ненужно. Понятно..
И то и то. Что мне запрещает расшарить ST вектор между потоками вместо STM? Как я для своего контейнера могу определить можно его шарить или нет?
Значение поменяется из другого потока и в
getUnchecked
будет уже не тот индекс который прошёл проверку строчкой выше,n
это например длина контейнера.Да это тот самый ллвм который вы использовали чтобы хоть как то сравнятся по скорости с цпп в своих экспериментах. И тот самый который растеры взяли потому что сами сделать свой не смогли.
Распарсить что делает
of
и;
я не смог, но идею понял. Хотя вместо Functor нужно иметь тайпкласс который умеет как раз в метод который даётInt -> a
. Т.е. вот это вот всё надо спроектировать и т п. Не рокет сайнс конечно, но и выдавать однострочники за какие то решения это слишком.Но опять же вот этот Bounded/Unbounded флаг это рантайм флаг. Афаик в расте тоже было раньше
fn size_hint()
, а потом решили еще добавить специализацию https://doc.rust-lang.org/std/iter/trait.ExactSizeIterator.html.Кстати тут сразу возникает вопрос с ансейф, можно ли доверять хинту len() для создания аллокаций? В хаскель вопрос будет аналогичный.
По порядку величин то же самое. Я прочел ваше сообщение и подумал что вы противопоставляете полдюжины аспирантов с сотней разработчиков на зарпалтах у апл и гугла...
Имхо в таком примере это преждевременное создание абстракций, получается усложнение. getNext/getPrev выглядит проще и понятнее. К тому же это ближе к реальному функционалу юай - там есть кнопки prev/next и у вас в программе будут такие методы, a не какой-то findAndSelect(forward).
Лучше с такими не работать
Я же объяснил, потому что eigen не выразим на расте.