1.83K subscribers
3.29K photos
130 videos
15 files
3.57K links
Блог со звёздочкой.

Много репостов, немножко программирования.

Небольшое прикольное комьюнити: @decltype_chat_ptr_t
Автор: @insert_reference_here
Download Telegram
Forwarded from Чылік
Забалтывание
20👍10🤮3🤬2
«У России три пути: вебкам, закладки и айти»

> OnlyFans приостанавливает работу аккаунтов из России
> полиция Германии ликвидирует Гидру
> Интел полностью останавливает работу в России

У России… нет путей?
🤔20👍9😢62
Forwarded from partially unsupervised
Существует известная проблема из области социологии: как получить более или менее честные данные в количественном исследовании, если респонденты не хотят/боятся/стыдятся отвечать честно.

И вот случайно наткнулся на простой и изящный подход в духе differential privacy. TL;DR - формируем список из N утверждений, делим респондентов на две группы, одной показываем все N утверждений, другой - все, кроме того самого чувствительного. Вопрос формулируется как "с каким количеством утверждений (неважно, каких именно) вы согласны", и по разнице между группами легко вывести истинную поддержку.

Должно подойти не только для опросов про войну, но и для user research.
🔥11
Блог*
#rust В сорцах rustc банят числа.
Ввиду последних событий, вероятно, будут банить числа 86 и 90
👍1😁1
Задал ребенку блестящее (не могу кривить душой!) задание.

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

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

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

— Вообще-то это можно даже назвать антропологическим исследованием! — важно сказал я.

Девочка округлила глаза и тут же записала такое важное и звучное выражение.

Буду держать вас в курсе.
👍4
Forwarded from Макс Силинг
cat вступил в профсоюз и его теперь нельзя уволить с его работы на первом месте в пайплайне
🔥7
#prog #rust #моё

Пусть у нас есть слайс из вот таких структур:

struct Data {
name: String,
whatever: u32,
bytes: Vec<u8>,
}

, и нам надо отсортировать слайс по полю name. Казалось бы, плёвое дело:

arr.sort_by_key(|d| &d.name);

Но компилятор ругается:

error: lifetime may not live long enough
--> src/lib.rs:8:21
|
8 | arr.sort_by_key(|d| &d.name);
| -- ^^^^^^^ returning this value requires that
'1 must outlive '2
| ||
| |return type of closure is &'2 String
| has type &'1 Data

В чём дело? Посмотрим на сигнатуру sort_by_key:

fn sort_by_key<K, F>(&mut self, f: F) where
F: FnMut(&T) -> K,
K: Ord,

Обратите внимание, параметр K не параметризован никакими временами жизни и потому считается независимым от переданной ссылки на T. Очевидно, в нашем случае это не так: ссылка на поле структуры не может жить дольше ссылки на структуру целиком.

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

arr.sort_by(|a, b| a.name.cmp(&b.name));

Окей, это работает, но выглядит уже не очень. Нам приходится повторять себя, да и идея "сравнить по name" уже не так хорошо читается. А если нам потребуется сравнивать сначала по name, а потом по bytes?

arr.sort_by(|a, b| (&a.name, &a.bytes).cmp(&(&b.name, &b.bytes)));

Ох, выглядит так себе, от обилия скобочек немного рябит в глазах. А если переписать на методах Ordering?

arr.sort_by(|a, b| a.name.cmp(&b.name).then_with(|| a.bytes.cmp(&b.bytes)));

Лучше особо не стало. И, кстати, что там, что там велик соблазн скопипастить выражения для a и заменить на b — великолепный способ, чтобы забыть в каком-то месте поменять. Мы можем сделать лучше! Упрячем sort_by в одном месте и выставим интерфейс, который принимает функцию для вынимания ключа:

trait SliceExt<T> {
fn sort_by_ref_key<K, F>(&mut self, f: F)
where
F: FnMut(&T) -> &K,
K: Ord + ?Sized; //
почему "?Sized"?
}

impl<T> SliceExt<T> for [T] {
fn sort_by_ref_key<K, F>(&mut self, mut f: F)
where
F: FnMut(&T) -> &K,
K: Ord + ?Sized,
{
self.sort_by(|a, b| f(a).cmp(&f(b)));
}
}

Теперь мы можем красиво отсортировать по имени:

arr.sort_by_ref_key(|d| &d.name);

Не менее красиво мы можем отсортировать по имени и по байтам... А нет, погодите, не можем — это потребует возвращать пару ссылок, а кортеж из ссылок ссылкой не является ауф. Так что до новых встреч.
👍2
...Или мы можем подрубить nightly и абстрагироваться от конкретной разновидности заимствующих ключей при помощи GAT-ов!

#![feature(generic_associated_types)]

Так как непосредственно конструктор типа мы передать не можем, мы передадим некий маркерный тип, к которому при помощи трейта прицепим ассоциированными типом нужный нам тип ключа:

trait BorrowedKeyFamily {
type Key<'a>: Ord + 'a;
}

Теперь нам нужен этот самый маркерный тип написать и связать его с кортежем ссылок:

struct PairRef<T, U: ?Sized>(std::marker::PhantomData<(T, U)>);

impl<T, U> BorrowedKeyFamily for PairRef<T, U>
where
T: Ord + 'static,
U: Ord + 'static + ?Sized,
{
type Key<'a> = (&'a T, &'a U);
}

Как обычно, типовые сигнатуры начинают занимать больше места, чем сам код. Что ж, используем всё это для нового метода в SliceExt:

trait SliceExt<T> {
// ...

fn sort_by_borrowed_key<K, F>(&mut self, f: F)
where
F: FnMut(&T) -> K::Key<'_>,
K: BorrowedKeyFamily;
}

impl<T> SliceExt<T> for [T] {
// ...

fn sort_by_borrowed_key<K, F>(&mut self, mut f: F)
where
F: FnMut(&T) -> K::Key<'_>,
K: BorrowedKeyFamily
{
self.sort_by(|a, b| f(a).cmp(&f(b)));
}
}

Кстати, благодаря анонимному лайфтайму нам не пришлось писать F: for<'a> FnMut(&'a T) -> K::Key<'a> (и, признаться честно, я удивлён, что для GAT это работает). Теперь напишем сортировку с только что сделанным методом:

arr.sort_by_borrowed_key(|d| (&d.name, &d.bytes));

Всем спасибо, все сво...

error[E0282]: type annotations needed
--> src/lib.rs:12:9
|
12 | arr.sort_by_borrowed_key(|d| (&d.name, &d.bytes));
| ^^^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `K` declared on the associated function `sort_by_borrowed_key`

А, компилятор не может понять, что за маркерный тип тут используется. Что ж, неприятно, но вполне логично — мы теоретически можем написать ещё один тип и реализовать для него BorrowedKeyFamily с парой ссылок (вот, кстати, место, где пригодился бы аналог FunctionalDependencies из GHC). Придётся воткнуть турборыбу:

arr.sort_by_borrowed_key::<PairRef<_, _>, _>(|d| (&d.name, &d.bytes));

Выглядит уже не так клёво. Вдобавок, у нашего кода есть одно досадное и неочевидное ограничение. Посмотрим ещё раз на ограничения на тип Key:

type Key<'a>: Ord + 'a;

То есть что бы ни лежало в Key<'a>, оно должно жить как минимум 'a. А у нас 'a может быть произвольным. Для T и U в составе пары это фактически выливается в ограничение for<'a> 'a, что эквивалентно 'static по определению. На практике это означает, что мы не сможем класть в ключ строковые слайсы, что резко ограничивает применимость подхода.

...Ну, зато мы выпендрились GAT-ами. Как всегда, весь код в гисте.
👍6
Forwarded from Санечка Ъысь
👍6🔥41
fn with_order<'o>(order: &'o Order) -> impl (for<'a> Fn(&'a str) -> (impl Iterator<Item = usize> + 'a + 'o)) + 'o

Real Rust code written by real programmers

(which doesn't actually work)
А для того, чтобы оно всё-таки работало, нужно, чтобы реализовали impl Fn() -> impl Trait in return position (привет, Вафель) и, желательно, синтаксис для явного написания замыкания с полиморфизмом высшего ранга.

И то, кстати, не факт, что сработает, поскольку в силу того, что возвращаемое замыкание содержит &'o Order, это замыкание, вообще говоря, должно принимать ссылку на строковой слайс не с произвольным временем жизни, а живущую не менее, чем 'o, а ограничение на времена жизни в higher-ranked trait bounds не работают даже для fn pointers.
#prog #tips

Не используйте для подписи коммитов на Github GPG-ключи, у которых указан e-mail, но не имя — Github почему-то считает, что к этим ключам не прикреплены e-mail (The email in this signature doesn’t match the committer email) и потому отказывается верифицировать коммиты, подписанные этим ключом.
Forwarded from Санечка Ъысь
🔥41