Size: a a a

2021 August 23
Блог*
Видео про самые дикие числа в математике. #repost

Если вы считаете что преисполнились в своём познании зная про i²=-1 и ε²=0 (дуальные числа), то приготовьте уран.

В данном видео показывается простая игра, в которой есть два игрока и граф, прикреплённый к полу с красными и синими палками. Суть игры в том чтобы последовательно ходить и отрезать ветки своего цвета. Выигрывает тот кто сделал ход последним. От графа зависит то кто гарантированно выиграет если будет следовать оптимальной стратегии. Поэтому математики захотели описать граф числом — положительные обозначают выигрыш синего игрока, а отрицательные — выигрыш красного. Определение величины числа производится через добавление другого графа сбоку, который может сбалансировать игру до невыигрышного состояния. Сначала мы приходим к целым числам: положительным, отрицательным и ноль. Затем приходим к дробям двойки. Затем добавляется зелёная палка, которую могут рубить оба и начинается жесть: появляются очень странные числа, которые меньше любого обычного числа, которые называют * (star), затем появляются числа (up) и (down), которые не равны *. Ну и потом математики упарываются по-полной и в попытках описать самые разные графы приходят к сюрреалистичным видам чисел: бесконечностям, самому маленькому возможному числу tiny и так далее. Самых различных чисел настолько много что математики уже стали рисовать зоопарки с животными и географические карты чисел. И в отличие от комплексных чисел, здесь всё _упорядочено_, то есть любое число можно сравнить с другим и сказать кто из них больше.

Знаете, одно дело выдумывать числа из воздуха, а другое — просто брать их из игры, то есть из своего рода реальности. И всё это так красиво выглядит, что я испытал математический оргазм во время просмотра. Теперь я хочу купить 1000-страничную книгу из которой взята эта тема и прочитать её. Кстати, одним из авторов этой книги является Джон Конвей.

Видео длится 57 минут, сделано через рисовалку от 3blue1brown и (я надеюсь) обязательно займёт призовое место в SoME1. Автор этого видео очень старался, делал видео суммарно 200 часов, и это его первый опыт. Но у видео на данный момент всего 800 просмотров, и оно не очень хайпит, поэтому СМОТРИТЕ, ЛАЙКАЙТЕ, РЕПОСТИТЕ ЧТО ЕСТЬ СИЛ.
источник
2021 August 24
Блог*
#prog #python
источник
Блог*
Today I learned: в pytest можно легко тестировать логирование. Не нужно самому возиться с моками для логгера, все уже готово - достаточно использовать дефолтную фикстуру caplog (пример использования для ленивых).

Очень удобно, если у вас бывает своеобразный код, где логи - это единственный side effect. С другой стороны, такой код может быть и звоночком - возможно, с дизайном что-то не так.
источник
Блог*
#prog #c #rust #successstory

И, кстати, пример, где может пригодиться константный Vec::new().

t.me/psauxww/543
Telegram
Segment@tion fault
Злые языки говорят, что Rust медленнее чем С - С же почти ассемблер, а Rust какие-то миллениалы придумали.

Хорошо. Вот решаю (пока простую) задачу. Нужно унифицированное SDK для драйверов системы. В данном примере каждый драйвер должен иметь три функции:

- get_bulk - формирует данные и возвращает количество результатов
- get_next_result() - итератор по данным, возвращает следующий датаблок
- free_result() - вызывается, чтобы очистить память и ресетнуть итератор

Датаблок - унифицированная структура с полями char port20, int status и char value256.

Пишем драйвер на сях. 37 строчек, всё маленькое, аккуратное, быстрее врядли можно придумать. Данные хранятся в поинтере, который ручками выделяем и очищаем сами, без абстракций сверху.

Пишем драйвер на Rust. Код в 2 раза больше, лень выделять память - используем std::vec::Vec, плюс дополнительно конвертируем нативные строки в сишные nil-ended (даже не используем для этого std:ffi, потому что его накроманы делали).

Задача - загрузиться как shared library, собрать…
источник
Блог*
К чёрту, мне это слишком нравится.

#music

youtube.com/watch?v=FP-lGq8BwtI
источник
2021 August 25
Блог*
Пора пить чай 🍮
источник
Блог*
#blogrecommendation не глядя
источник
Блог*
Итак, я всё-таки сделал себе блог! Теперь он доступен по адресу ihatereality.space.

И там уже есть моя статья  “Why null sucks, even if it's checked”!

Блог работает на Zola и GH pages. Все сорцы открытые, если вдруг кто-то хочет посмотреть/стырить мои настройки =)
источник
Блог*
#prog #rust

Rust и Вафель не перестают меня удивлять.

В Rust есть паттерны. Они есть (в том числе) для массивов и слайсов. Если у нас есть массив на пять элементов, то мы можем переместить из него первый и последний элементы вот так:

let [first, _, _, _, last] = arr5;

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

fn trim_ends<T>(arr: &[T]) -> Option<&[T]> {
   match arr {
       [_, rest @ .., _] => Some(rest),
       _ => None,
   }
}


Очевидно, имя, привязываемое к .. внутри паттерна слайса, имеет тип &[T]. Однако .. можно использовать и для паттернов массивов! В этом случае имя, привязываемое к этому паттерну, будет иметь тип массива, содержащего все остальные элементы:

struct Foo;

fn main() {
   let [_, rest @ .., _] = [Foo, Foo, Foo, Foo];
   let _: [Foo; 2] = rest; // тайпчекается
}


Вот тебе и арифметика на массивах!

(thanks @wafflelapkin)
источник
2021 August 26
Блог*
Хотите быстро инициализировать переменные в Rust? Просто используйте @!

let a @ b @ c @ d @ e = 0;

Это реально работает.
источник
Блог*
#rust be like:

for h in self.tcx.hir().parent_iter(param.hir_id) {
   break 'origin match h.1 {
       // несколько пропущенных веток
       _ => continue,
   };
}

Здесь
источник
Блог*
> уезжаю на работу слишком рано, чтобы забрать доставку из пункта выдачи
> приезжаю с работы слишком поздно, чтобы забрать доставку из пункта выдачи

😒
источник
2021 August 27
Блог*
источник
Блог*
источник
2021 August 28
Блог*
> мне не нравится реальность

Как вообще можно не любить реальность, в которой есть Вафелька?
источник
2021 August 30
Блог*
Как политкорректно сказать коллеге (бывшему сишнику), что он пишет лютый говнокод?
источник
2021 August 31
Блог*
Правительство РФ завело свой канал в Telegram: t.me/government_rus.

У меня всё.
источник
2021 September 01
Блог*
В СМЫСЛЕ УЖЕ СЕНТЯБРЬ
источник
2021 September 02
Блог*
Занимательная статья об оптимизации CRDT (Conflict-free replicated data type, один из многих вариантов реализации конкурентного редактирования).

5000x faster CRDTs: An Adventure in Optimization

Там есть немного раста, много js-а и всякие занимательные штуки, рекомендую к прочтению :p
источник
2021 September 03
Блог*
#prog #rust #моё

Допустим, нам нужно проанализировать большой 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 для захвата обобщённых параметров.
источник