> уезжаю на работу слишком рано, чтобы забрать доставку из пункта выдачи
> приезжаю с работы слишком поздно, чтобы забрать доставку из пункта выдачи
😒
> приезжаю с работы слишком поздно, чтобы забрать доставку из пункта выдачи
😒
> мне не нравится реальность
Как вообще можно не любить реальность, в которой есть Вафелька?
Как вообще можно не любить реальность, в которой есть Вафелька?
Как политкорректно сказать коллеге (бывшему сишнику), что он пишет лютый говнокод?
Правительство РФ завело свой канал в Telegram:
У меня всё.
t.iss.one/government_rus
.У меня всё.
Forwarded from мне не нравится реальность
Занимательная статья об оптимизации CRDT (Conflict-free replicated data type, один из многих вариантов реализации конкурентного редактирования).
5000x faster CRDTs: An Adventure in Optimization
Там есть немного раста, много js-а и всякие занимательные штуки, рекомендую к прочтению :p
5000x faster CRDTs: An Adventure in Optimization
Там есть немного раста, много js-а и всякие занимательные штуки, рекомендую к прочтению :p
#prog #rust #моё
Допустим, нам нужно проанализировать большой JSON, и нам нужно вытащить часть полей с конкретными типами, но по возможности оставить остальные. При этом этот наборы полей в разных местах немного разные, так что повторять себя не хочется. Можем ли мы сделать лучше, чем выписывать тип под каждую комбинацию полей? Оказывается, да!
И благодаря чуду serde для этого нам понадобится совсем немного кода. Один из атрибутов, который можно повесить на поле — это #[serde(flatten)]. Применение этого атрибута поднимает поля помеченного поля на уровень выше в (де)сериализованном представлении:
* Deserialize описывает общий интерфейс для десериализации типов (с поглощением исходных данных)
* Тип, реализующий Deserializer, описывает конкретный формат исходных данных
* Тип, реализующий Visitor, описывает, как десериализуется конкретный тип (и это описание в общем случае не поглощает вход напрямую и потому может быть скомпоновано с другими посетителями). Эти типы, как правило, являются типами нулевого размера и если и содержат поля, то только
Допустим, нам нужно проанализировать большой JSON, и нам нужно вытащить часть полей с конкретными типами, но по возможности оставить остальные. При этом этот наборы полей в разных местах немного разные, так что повторять себя не хочется. Можем ли мы сделать лучше, чем выписывать тип под каждую комбинацию полей? Оказывается, да!
И благодаря чуду serde для этого нам понадобится совсем немного кода. Один из атрибутов, который можно повесить на поле — это #[serde(flatten)]. Применение этого атрибута поднимает поля помеченного поля на уровень выше в (де)сериализованном представлении:
use serde::Deserialize;
#[derive(Deserialize)]
struct Inner {
items: Vec<u32>,
}
#[derive(Deserialize)]
struct Outer {
foo: String,
#[serde(flatten)]
inner: Inner,
}
fn main() {
let input = r#"{
"foo": "bar",
"items": [0, 1, 2]
}"#;
assert!(serde_json::from_str::<Outer>(input).is_ok());
}
Этот атрибут работает и для обобщённых типов. Конечно, мы можем сделать типы для пар, троек, четвёрок и так далее типов... Но мы не хотим повторять себя! А потому воспользуемся старым трюком из функционального программирования: гетерогенными списками.struct HNil;
#[derive(Deserialize)]
struct HCons<H, T> {
#[serde(flatten)]
head: H,
#[serde(flatten)]
tail: T,
}
Набор типов для десериализации мы будем конструировать при помощи вложенных HCons
-ов, а для удобства выписывания этого типа воспользуемся макросом:macro_rules! HList {
() => { HNil };
($head:ty $(, $rest:ty)* $(,)?) => { HCons<$head, HList![$($rest),*]> };
}
Как вы могли заметить, я не написал #[derive(Deserialize)]
для HNil
. Это сделано намерено, так как мы хотим для HNil
не семантику десериализации юнит-структуры, а семантики "десериализуй сюда, что угодно". Для этого надо немного углубиться в то, как в serde происходит десериализация. Вот как выглядит определение Deserialize:trait Deserialize<'de>: Sized {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>;
}
Здесь 'de
обозначает время жизни исходных данных. Этот параметр сделан для того, чтобы типы можно было десериализовывать из строки и при это хранить в них слайсы строк, а не String
, хранящий память в куче. Deserializer же — это трейт для типов, которые предоставляют набор ручек вида "дай мне число" или "дай мне строку". Именно эти типы хранят в себе исходные данные, и именно эти типы описывают в конечном счёте, в каком именно формате записаны данные. В процессе эти типы оперируют посетителем: типом, реализующим Visitor, которые вынимает данные из десериализатора и непосредственно конструирует из полученных значений значение того типа, для которого реализовывается трейт Deserialize
. Да, звучит немного запутанно, так что коротко повторим:* Deserialize описывает общий интерфейс для десериализации типов (с поглощением исходных данных)
* Тип, реализующий Deserializer, описывает конкретный формат исходных данных
* Тип, реализующий Visitor, описывает, как десериализуется конкретный тип (и это описание в общем случае не поглощает вход напрямую и потому может быть скомпоновано с другими посетителями). Эти типы, как правило, являются типами нулевого размера и если и содержат поля, то только
PhantomData
для захвата обобщённых параметров.docs.rs
Deserialize in serde - Rust
A data structure that can be deserialized from any data format supported by Serde.
Окей, но как же нам десериализовать
Теперь мы сделаем несколько структур для десериализации — и макрос для более удобной деконструкции
HNil
с нужной нам логикой? Так как JSON — самоописываемый формат в том смысле, что мы можем посмотреть на начало входа и решить, как парсить остаток — мы можем вызвать у десериализатора метод dezerialize_any
, что фактически означает "посмотри данные и реши сам, как их разбирать". Нам также потребуется посетитель, который для разбора подчастей JSON-документа будет вызывать вне зависимости от запрашиваемого типа deserialize_any
у десериализатора и не будет при это сохранять никаких данных. К счастью, в составе serde уже есть такой тип — IgnoredAny — так что мы можем просто использовать его:impl<'de> Deserialize<'de> for HNil {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>
{
deserializer.deserialize_any(serde::de::IgnoredAny)?;
Ok(Self)
}
}
Как видите, код проверяет, что формат корректен, но не вынимает реально из него никаких данных — ровно то, что нам и было нужно.Теперь мы сделаем несколько структур для десериализации — и макрос для более удобной деконструкции
HList
:macro_rules! hlist_pat {Сконструируем вход, содержащий все поля:
() => { HNil };
($head:pat $(, $rest:pat)* $(,)?) => { HCons { head: $head, tail: hlist_pat!($($rest),*) } };
}
#[derive(Deserialize)]
struct Items {
items: Vec<String>
}
#[derive(Deserialize)]
struct Version {
version: u32,
}
#[derive(Deserialize)]
struct User {
user_id: String,
}
let json = r#"{
"user_id": "john_doe",
"items": ["salad", "juice", "beer", "fork"],
"version": 0,
"bogus": [null, 0.3, 4, "nope", {}]
}"#;
И попробуем вытащить всё, что нас интересует:use serde_json::from_str as from_json;
let hlist_pat!(user, items, version) =
from_json::<HList![User, Items, Version]>(json).unwrap();
assert_eq!(user.user_id, "john_doe");
assert_eq!(items.items, ["salad", "juice", "beer", "fork"]);
assert_eq!(version.version, 0);
Теперь уберём, скажем, версию:let json = r#"{
"user_id": "john_doe",
"items": ["salad", "juice", "beer", "fork"],
"bogus": [null, 0.3, 4, "nope", {}]
}"#;
assert!(from_json::<HList![User, Items, Version]>(json).is_err());
assert!(from_json::<HList![User, Items ]>(json).is_ok());
Отсутствие user_id
и items
вызовет ошибку, но не в том случае, если требуемые наборы полей опциональны:let json = r#"{Ну и, разумеется, мы можем вытащить все остальные поля, что есть:
"version": 0,
"bogus": [null, 0.3, 4, "nope", {}]
}"#;
assert!(from_json::<HList![ User, Items, Version]>(json).is_err());
assert!(from_json::<HList![Option<User>, Option<Items>, Version]>(json).is_ok());
type Rest = serde_json::Map<String, serde_json::Value>;
let json = r#"{
"user_id": "john_doe",
"items": ["salad", "juice", "beer", "fork"],
"version": 0,
"bogus": [null, 0.3, 4, "nope", {}]
}"#;
let hlist_pat!(_, _, _, rest) = from_json::<HList![User, Items, Version, Rest]>(json).unwrap();
assert_eq!(
serde_json::Value::Object(rest),
serde_json::json!({
"bogus": [null, 0.3, 4, "nope", {}],
})
);
По моему, вышло красиво и изящно. Как всегда, весь код в гисте.docs.rs
IgnoredAny in serde::de - Rust
An efficient way of discarding data from a deserializer.
Forwarded from мне не нравится реальность
https://matklad.github.io/2021/09/04/fast-rust-builds.html
matklad как обычно дело говорит, на этот раз про скорость компиляции
matklad как обычно дело говорит, на этот раз про скорость компиляции
matklad.github.io
Fast Rust Builds
It's common knowledge that Rust code is slow to compile.
But I have a strong gut feeling that most Rust code out there compiles much slower than it could.
But I have a strong gut feeling that most Rust code out there compiles much slower than it could.
Итого за день:
* уронил телефон, разбив экран
* не смог поесть свой обед, поскольку не успел вчера его заказать...
* ...но воспользовался любезностью коллеги, который отдал свой (его сегодня не было в офисе)
* почитал хабр, нашёл ссылку на issue про unsound код в nalgebra, посмотрел, увидел, что и сейчас можно эксплуатировать, сделал MRE и открыл новое issue
* ещё немного посрался в том гигантском MR с тем упёртым сишником, который, в частности, считает, что писать вручную реализацию PartialEq для структуры на три десятка полей — это нормально
* ...но при этом всё же принимает некоторые из моих изменений
* взялся исправлять issue с нашим крейтом, нашёл проблему, но коллеги меня опередили и успели сделать MR
* 💅
Пожалуй, в целом тянет на 0 по шкале Оптозоракса
* уронил телефон, разбив экран
* не смог поесть свой обед, поскольку не успел вчера его заказать...
* ...но воспользовался любезностью коллеги, который отдал свой (его сегодня не было в офисе)
* почитал хабр, нашёл ссылку на issue про unsound код в nalgebra, посмотрел, увидел, что и сейчас можно эксплуатировать, сделал MRE и открыл новое issue
* ещё немного посрался в том гигантском MR с тем упёртым сишником, который, в частности, считает, что писать вручную реализацию PartialEq для структуры на три десятка полей — это нормально
* ...но при этом всё же принимает некоторые из моих изменений
* взялся исправлять issue с нашим крейтом, нашёл проблему, но коллеги меня опередили и успели сделать MR
* 💅
Пожалуй, в целом тянет на 0 по шкале Оптозоракса
Forwarded from мне не нравится реальность
Inside Rust: Splitting the const generics features
Маленькая заметка о прогрессе с расширением const generics.
Маленькая заметка о прогрессе с расширением const generics.
#prog #rust #rustlib
Библиотека для todo, которая валит компиляцию при специфических условиях.
lib.rs/todo-or-die
Библиотека для todo, которая валит компиляцию при специфических условиях.
lib.rs/todo-or-die
Lib.rs
todo-or-die — Rust dev tool
TODOs checked at compile time
Forwarded from iggisv9t channel
Нашёл тут любопытный список https://github.com/daviddao/awful-ai
Это один из примеров, почему мне не нравится сверхобобщающий термин AI. Но на самом деле, хоть у меня и бомбит от некоторых пунктов списка, ответственность за имидж области лежит на непосредственных её участниках. Так что давайте я попробую внести свой маленький вклад в просвещение.
Меня больше всего напряг самый первый раздел "Discrimination". Потому что примерно половина примеров — это не "they build a racist AI" а просто зеркало того, что люди делают в интернете. Ну научите попугая на твитах, он тоже будет выдавать вам довольно неприятные фразы. Это не расист-попугай, он же не понимает что говорит, он учит распределение данных, которые ему дали. Поэтому да, если в исходных данных белых больше чем people of color, или Dr. чаще стоит рядом с фамилией у мужчин, то чёрт возьми, не алгоритм имеет смещение, а данные. Алгоритмы машинного обучения не вносят никакой логики в данные, не интерпретируют их, грубо говоря, они учат только "как оно чаще бывает в примерах, которые им показали".
И такие работы, которые показывают смещение данных неизбежны и важны. И я бы их как раз пихал не в раздел "фу какие неправильные", а в раздел "смотрите, с этим надо быть осторожными".
И вот тут мы приходим к другой половине раздела и за одно к разделу "Surveillance" а заодно и к "Social credit systems". То есть мы видели на примерах, которые я пытался оправдать, что судить людей алгоритмами не стоит, потому что мы не сможем собрать честные репрезентативные данные, и тем более не сможем вложить в них какую-то этичную логику решений. Потому что они просто учатся правильно угадывать, а не разбираться. И тем не менее, много кто занимается созданием алгоритмов, чтобы прямо искать кого осудить.
С другой стороны, не нужно ограничиваться одними заголовками. Всегда есть тонна деталей, которые могут в корне менять дело, и может оказаться, что AI совсем не AI у них. Просто области, которые касаются отбора людей, разных скорингов и так далее, в принципе такие, что никакой чёрный ящик не допустим, будь то AI или что угодно другое.
Кстати, про переименование NIPS потому что кому-то это напомнило nipples, у меня тоже бомбит. Это напоминает мне ту историю, как за рисунки на рубашке затравили чувака, который посадил Розетту на комету Чурюмова-Герасименко. Какие блин соски? Никто о них и не думал.
Это один из примеров, почему мне не нравится сверхобобщающий термин AI. Но на самом деле, хоть у меня и бомбит от некоторых пунктов списка, ответственность за имидж области лежит на непосредственных её участниках. Так что давайте я попробую внести свой маленький вклад в просвещение.
Меня больше всего напряг самый первый раздел "Discrimination". Потому что примерно половина примеров — это не "they build a racist AI" а просто зеркало того, что люди делают в интернете. Ну научите попугая на твитах, он тоже будет выдавать вам довольно неприятные фразы. Это не расист-попугай, он же не понимает что говорит, он учит распределение данных, которые ему дали. Поэтому да, если в исходных данных белых больше чем people of color, или Dr. чаще стоит рядом с фамилией у мужчин, то чёрт возьми, не алгоритм имеет смещение, а данные. Алгоритмы машинного обучения не вносят никакой логики в данные, не интерпретируют их, грубо говоря, они учат только "как оно чаще бывает в примерах, которые им показали".
И такие работы, которые показывают смещение данных неизбежны и важны. И я бы их как раз пихал не в раздел "фу какие неправильные", а в раздел "смотрите, с этим надо быть осторожными".
И вот тут мы приходим к другой половине раздела и за одно к разделу "Surveillance" а заодно и к "Social credit systems". То есть мы видели на примерах, которые я пытался оправдать, что судить людей алгоритмами не стоит, потому что мы не сможем собрать честные репрезентативные данные, и тем более не сможем вложить в них какую-то этичную логику решений. Потому что они просто учатся правильно угадывать, а не разбираться. И тем не менее, много кто занимается созданием алгоритмов, чтобы прямо искать кого осудить.
С другой стороны, не нужно ограничиваться одними заголовками. Всегда есть тонна деталей, которые могут в корне менять дело, и может оказаться, что AI совсем не AI у них. Просто области, которые касаются отбора людей, разных скорингов и так далее, в принципе такие, что никакой чёрный ящик не допустим, будь то AI или что угодно другое.
Кстати, про переименование NIPS потому что кому-то это напомнило nipples, у меня тоже бомбит. Это напоминает мне ту историю, как за рисунки на рубашке затравили чувака, который посадил Розетту на комету Чурюмова-Герасименко. Какие блин соски? Никто о них и не думал.
GitHub
GitHub - daviddao/awful-ai: 😈Awful AI is a curated list to track current scary usages of AI - hoping to raise awareness
😈Awful AI is a curated list to track current scary usages of AI - hoping to raise awareness - daviddao/awful-ai