#prog #haskell
Говорят, что в Haskell нет циклов. Это, конечно же, не так, просто циклы там являются не конструкциями языка, а библиотечными функциями.
Говорят, что в Haskell нет циклов. Это, конечно же, не так, просто циклы там являются не конструкциями языка, а библиотечными функциями.
Вы, наверное, слышали бородатую историю про семь перпендикулярных красных линий. Мало кто знает оригинал. Вот он.
Livejournal
Совещание
Петров пришел во вторник на совещание. Ему там вынули мозг, разложили по блюдечкам и стали есть, причмокивая и вообще выражая всяческое одобрение. Начальник Петрова, Недозайцев, предусмотрительно раздал присутствующим десертные ложечки. И началось. — Коллеги…
Forwarded from илья optozorax
когда цитируешь кого-то в канале своём, имхо лучше скидывать ссылку на чат, откуда ты это взял, чем пересылать сообщение, так можно хотя бы контекст отследить
#prog #parsing #article
Поверить не могу, что не выкладывал это раньше. JSON — недостаточно точно определённый формат.
habr.com/company/mailru/blog/314014/
Поверить не могу, что не выкладывал это раньше. JSON — недостаточно точно определённый формат.
habr.com/company/mailru/blog/314014/
Хабр
Парсинг JSON — это минное поле
JSON — это стандарт де-факто, когда заходит речь о (де)сериализации, обмене данными в сети и мобильной разработке. Но насколько хорошо вы знакомы с JSON? Все м...
#video #music
Eye of the tiger, сыгранная на матричном принтере. То, что по праву можно называть "техно".
youtube.com/watch?v=u8I6qt_Z0Cg
Eye of the tiger, сыгранная на матричном принтере. То, что по праву можно называть "техно".
youtube.com/watch?v=u8I6qt_Z0Cg
YouTube
Rocky's Printer - Eye of the tiger on a dot matrix printer [HD]
How would rocky's printer be? Like this!
Hear "Eye of the Tiger" from Survivor on a dot matrix printer!
Eye of the Tiger by Survivor published in 1981 was part of the Rocky III soundtrack.
Hear "Eye of the Tiger" from Survivor on a dot matrix printer!
Eye of the Tiger by Survivor published in 1981 was part of the Rocky III soundtrack.
Forwarded from oleg_log (Oleg Kovalov)
К P A C U B 0
https://www.youtube.com/watch?v=DuB8VUICGqc // will occasionally show ads
https://www.youtube.com./watch?v=DuB8VUICGqc // will not show ads
тред https://www.reddit.com/r/webdev/comments/gzr3cq/fyi_you_can_bypass_youtube_ads_by_adding_a_dot/
https://www.youtube.com/watch?v=DuB8VUICGqc // will occasionally show ads
https://www.youtube.com./watch?v=DuB8VUICGqc // will not show ads
тред https://www.reddit.com/r/webdev/comments/gzr3cq/fyi_you_can_bypass_youtube_ads_by_adding_a_dot/
#prog #amazingopensource
Аллокатор памяти snmalloc, написанный в рамках разработки рантайма для исследовательского языка программирования от MIcrosoft Verona. Кажется, первый аллокатор, основанный на обмене сообщениями: операция освобождения памяти посылает сообщение об освобождении потоку, в котором память изначально была выделена. Уверяется, что эта пересылка задействует минимум атомарных операций и потому имеет небольшой оверхед. Также освобождение памяти в том же потоке, в котором она была выделена, не требует синхронизации вовсе.
Аллокатор памяти snmalloc, написанный в рамках разработки рантайма для исследовательского языка программирования от MIcrosoft Verona. Кажется, первый аллокатор, основанный на обмене сообщениями: операция освобождения памяти посылает сообщение об освобождении потоку, в котором память изначально была выделена. Уверяется, что эта пересылка задействует минимум атомарных операций и потому имеет небольшой оверхед. Также освобождение памяти в том же потоке, в котором она была выделена, не требует синхронизации вовсе.
GitHub
GitHub - microsoft/snmalloc: Message passing based allocator
Message passing based allocator. Contribute to microsoft/snmalloc development by creating an account on GitHub.
#prog
Tckb ds rjulf-yb,elm gbcfkb d nthvbyfkt
github.com/danakt/pshe
Tckb ds rjulf-yb,elm gbcfkb d nthvbyfkt
git
dvtcnj пше
, nj, djpvj;yj, dfv ghbujlbncz 'nf ghjuhfvvf, rjnjhfz fdnjvfnbxtcrb bcghfdkztn zpsr yf ghfdbkmysq.github.com/danakt/pshe
GitHub
GitHub - danakt/pshe: Незаменимый помощник для работы с git
Незаменимый помощник для работы с git. Contribute to danakt/pshe development by creating an account on GitHub.
Блог*
Аналогичной полезности вещь: перевод текста из одной раскладки в другую. raskladki.net.ru
А если вам нужно понять, в какой же, блин, кодировке этот текст в кракозябрах, то есть расшифровщик от студии Лебедева (да, того самого).
artlebedev.ru/decoder
artlebedev.ru/decoder
#prog #rust #rustlib #serde #amazingopensource
Хозяйке на заметку
Подборка библиотек для работы с serde от замечательногоТоляна dtolnay.
erased-serde — трейты из serde со стёртыми типами. Позволяют сделать из (де)сериализаторов трейт-объекты. Обычно это запрещено правилами object safety из-за наличия обобщённых типов.
typetag — сериализация и десериализация трейт-объектов. Работает на костылях.
serde-repr — делегирует (де)сериализацию C-like enum его числовому значению.
serde-stacker — позволяет десериализовывать глубоко вложенные структуры, динамически выделяя память под стек. Работает, увы, не на всех OS: нормально работает на linux и MacOS и течёт на Windows.
serde-ignored — позволяет обернуть десериализатор с кастомный коллбеком, который будет вызываться на всех проигнорированных в процессе десериализации ключах.
Хозяйке на заметку
Подборка библиотек для работы с serde от замечательного
erased-serde — трейты из serde со стёртыми типами. Позволяют сделать из (де)сериализаторов трейт-объекты. Обычно это запрещено правилами object safety из-за наличия обобщённых типов.
typetag — сериализация и десериализация трейт-объектов. Работает на костылях.
serde-repr — делегирует (де)сериализацию C-like enum его числовому значению.
serde-stacker — позволяет десериализовывать глубоко вложенные структуры, динамически выделяя память под стек. Работает, увы, не на всех OS: нормально работает на linux и MacOS и течёт на Windows.
serde-ignored — позволяет обернуть десериализатор с кастомный коллбеком, который будет вызываться на всех проигнорированных в процессе десериализации ключах.
GitHub
GitHub - dtolnay/erased-serde: Type-erased Serialize, Serializer and Deserializer traits
Type-erased Serialize, Serializer and Deserializer traits - dtolnay/erased-serde
Forwarded from Идеи неинтересных фильмов
"Призрачный гонщик".
Участковый во время сухого закона пытается обнаружить в Череповце производителя сивухи.
Участковый во время сухого закона пытается обнаружить в Череповце производителя сивухи.
Блог*
Так, а что тут не так? И почему не совпадают типы? Дело в том, что у каждой функции — не только у замыканий — в Rust свой собственный уникальный тип. Здесь мы попытались сохранить значения двух разных типов в паре одинаковых типов, поэтому наш код не компилируется.…
#prog #rust #моё
Хроники замыканий
Как я уже говорил, для каждого литерала замыкания компилятор Rust создаёт свой собственный анонимный тип, в котором содержатся захваченные замыканием переменные. Эти сгенерированные типы объединяет одно: они реализуют один или несколько Fn-трейтов:
А почему их три? Разве нельзя обойтись одним?
Можно, но это серьёзно ограничило бы возможности замыканий. Трейтов три из-за того, что замыкания могут иметь различные возможности. Как ты помнишь, методы в Rust принимают первым параметром
Метод
Окей, а что с другими трейтами?
Они дают возможность для более интересных замыканий.
Понятно, а
Именно так. Более того,
Хроники замыканий
Как я уже говорил, для каждого литерала замыкания компилятор Rust создаёт свой собственный анонимный тип, в котором содержатся захваченные замыканием переменные. Эти сгенерированные типы объединяет одно: они реализуют один или несколько Fn-трейтов:
core::ops::{
FnOnce, FnMut, Fn}
.А почему их три? Разве нельзя обойтись одним?
Можно, но это серьёзно ограничило бы возможности замыканий. Трейтов три из-за того, что замыкания могут иметь различные возможности. Как ты помнишь, методы в Rust принимают первым параметром
self
, &mut self
или &self
(пошёл нафиг, arbitrary self types!). Соответственно и определения у Fn*-трейтов отличаются. Вот как они выглядят:trait FnOnce<Args> {
type Output;
extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
}
trait FnMut<Args>: FnOnce<Args> {
extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
}
pub trait Fn<Args>: FnMut<Args> {
extern "rust-call" fn call(&self, args: Args) -> Self::Output;
}
Ти́повый параметр Args
в сгенерированных реализациях — это кортеж, элементы которого — типы аргументов, по одному на каждый аргумент. Ассоциированный тип Output
— это тип значения, возвращаемого при вызове замыкания. Методы трейтов объявлены с соглашением о вызове rust-call
. Это, в частности, означает, что их нельзя сохранить или передать там, где ожидаются обычные функции.Метод
call
трейта FnOnce
принимает замыкание по значению, т. е. при вызове замыкание перемещается и его после этого нельзя использовать. Этот трейт не имеет никаких ограничений, что логично: если у нас есть замыкание, то его всегда можно вызвать как минимум один раз. В принципе, замыкание может не реализовывать другие трейты:struct A;
let a = A;
let closure = || a;
closure();
// closure(); // use of moved value: closure
Здесь мы объявляем тип значение a
типа A
, которое не является копируемым, и замыкание, которое это значение захватывает и возвращает при вызове. Замыкания в Rust, если не указано ключевое слово move
, захватывают значение по ссылке (возможно, мутабельной). Здесь a
возвращается, поэтому его можно захватить только по значению. Так как это значение не копируемо, после вызова это значение перемещается из структуры данных, реализующей замыкание, и более замыкание вызвать нельзя. Собственно, это нам и скажет компилятор, если мы расскомментируем последную строку.Окей, а что с другими трейтами?
Они дают возможность для более интересных замыканий.
FnMut
имеет в качестве супертрейта FnOnce
— как я уже сказал, любое замыкание можно вызвать как минимум раз. Метод этого трейта call_mut
принимает &mut self
, а потому замыкание, во-первых, можно вызвать несколько раз, а во-вторых, может менять захваченные значения. Вот пример:let mut n = 0;
let mut counter = || {
n += 1;
n
};
println!("{}", counter()); // 1
println!("{}", counter()); // 2
println!("{}", counter()); // 3
Здесь мы сделали переменную счётчик n
и замыкание, которое его инкрементирует при каждом вызовом перед тем, как вернуть. Что тут важно — в силу того, что call_mut
требует &mut self
, а мутабельную ссылку можно взять только от мутабельного значения, нам пришлось объявить само замыкание как мутабельное. Если этот mut
опустить, то компилятор резонно откажется компилировать код.Понятно, а
call
принимает значение по ссылке и потому замыкание можно вызывать несколько раз, но оно не может менять захваченные значения?Именно так. Более того,
Fn
является субтрейтом FnMut
, и это тоже логично: если мы можем вызвать метод по разделяемой ссылке, то можем вызвать и по уникальной. Надо только иметь в виду, что &mut
в Rust вообще-то означает не изменяемость, а уникальность, поэтому из-за interior mutability пример со счётчиком можно переделать и с "иммутабельным" замыканием.doc.rust-lang.org
FnOnce in core::ops - Rust
The version of the call operator that takes a by-value receiver.
Блог*
#prog #rust #моё Хроники замыканий Как я уже говорил, для каждого литерала замыкания компилятор Rust создаёт свой собственный анонимный тип, в котором содержатся захваченные замыканием переменные. Эти сгенерированные типы объединяет одно: они реализуют один…
Ох, постараюсь уложить это в голове. Есть ещё что-то, что нужно знать о замыканиях?
Да. Иногда требуется одно и тоже замыкание передать в качестве аргумента в несколько функций. Клонировать в этом случае не получится, потому что замыкание является клонируемым не всегда (а именно — начиная с версии 1.26.0, тогда, когда все захваченные значения клонируемы). Именно поэтому в стандартной библиотеке есть несколько blanket impl-ов, которые реализуют Fn*-трейты для ссылок на замыкания (например, вот). Поэтому, если, скажем, в двух функциях требуется замыкание, реализующее
Видимо, на этом всё?
Отнюдь, о замыканиях можно рассказать ещё кое-что... Но это уже, видимо, тема для следующего поста.И будем надеяться, что его не придётся ждать ещё пару месяцев.
Да. Иногда требуется одно и тоже замыкание передать в качестве аргумента в несколько функций. Клонировать в этом случае не получится, потому что замыкание является клонируемым не всегда (а именно — начиная с версии 1.26.0, тогда, когда все захваченные значения клонируемы). Именно поэтому в стандартной библиотеке есть несколько blanket impl-ов, которые реализуют Fn*-трейты для ссылок на замыкания (например, вот). Поэтому, если, скажем, в двух функциях требуется замыкание, реализующее
Fn(i32) -> i32
, то можно сделать замыкание и передавать в качестве аргумента ссылку на него. В некоторых случаях сама функция требует ссылку на замыкание (хотя это, вообще говоря, странно). В таком случае можно взять ссылку непосредственно от литерала замыкания. Выглядит это несколько странно, но работает.Видимо, на этом всё?
Отнюдь, о замыканиях можно рассказать ещё кое-что... Но это уже, видимо, тема для следующего поста.
GitHub
Stabilize the copy_closures and clone_closures features by SimonSapin · Pull Request #49299 · rust-lang/rust
In addition to the Fn* family of traits, closures now implement Copy (and similarly Clone) if all of the captures do.
Tracking issue: #44490
Tracking issue: #44490