Как стать автором
Обновить
16
0

Пользователь

Отправить сообщение

ой, кстати, да, как реализовать рейндж всех нечётных интов одним 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?

Апд исправил форматирвание

Мне лень участвовать в демагогии что конструктивно а что нет.

Фичей eigen в nalgebra нету потому что их невозможно реализовать на расте.

Это 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 даёт больше выразлительности.

В чем неконструктивность если я просто констатирую факты?

А так да, будем ждать ¯_(ツ)_/¯

otherVector + begin

А как такое работает? 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 на раст и что вы будете делать с ней?

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

Люблю комментарии на Хабре за их точность )))

Лучше вы сами внимательно перечитайте. В ветке было про сборку раст и с++.

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

Просто зависимость лежит в dll, которая предоставляется ОС, или хуже того вендором.

А как в ней "грепнуть по unsafe" ?

Будет ссылка на область памяти, которая будет удерживать GC от её удаления, даже если исходный вектор сдохнет

т.е. это таки некий тайпкласс у которого может быть несколько реализаций? Ссылка на другой вектор или ссылка на какую-то свою аллокацию?

У меня вопрос не про владение, можно как одну из реализаций сделать слайс который в отличие от std::span делает рефкаунт (например растовый hyper::Bytes).

Тогда юзайте списки и делайте по ним map, потому что ваш трансформатор, скорее всего, не random access

В цпп сделано, в раст сделано, а хаскель не смог поэтому ненужно. Понятно..

Так вам примитивы писать или целевой прикладной код, их использующий?

И то и то. Что мне запрещает расшарить ST вектор между потоками вместо STM? Как я для своего контейнера могу определить можно его шарить или нет?

Где здесь ub?

Значение поменяется из другого потока и в getUnchecked будет уже не тот индекс который прошёл проверку строчкой выше, n это например длина контейнера.

Это который ...

Да это тот самый ллвм который вы использовали чтобы хоть как то сравнятся по скорости с цпп в своих экспериментах. И тот самый который растеры взяли потому что сами сделать свой не смогли.

можете трансформать обычным fmap после этого

Распарсить что делает 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 не выразим на расте.

Такой задачи нету. For/while строго мощнее любого другого специального сахарка. А если хотите свое, то с++ это легко позваляет сделать, хоть for(auto i : iota(a,b)), хоть boost::irange хоть что угодно с какими захотите проверками и азертами.

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

И где тут решили шаг больше 1?

1
23 ...

Информация

В рейтинге
Не участвует
Зарегистрирован
Активность