Как бы не получился комикс "брошу яваскрипт и стану проституткой". С вот этим вот преобразованием чисел в строки (или строк в числа). Потому что тут рядом тусуются проблемы локалей.
Кажется, что вопрос не по теме поста. Как это соотносится с бимапами?
И, собственно, в чём проблема? В мемоизации функции f? Зачем нужен словарь, на что должна влиять монотонность и, тем более, линейность? Какой прикладной смысл этого всего?
160 элементов - это всё ещё "мало". Были бы сотни тысяч, можно было бы подумать об эффективном хранении и из-за этого - об эффективном доступе. А тут...
Отдельный минус подхода - смешивание ключей туда-обратно. В языке со слабой типизацией можно накосячить с лёгкостью необычайной. Лучше соблюдать чистоту рук, однако!
Но кстати, быстрое-и-грязное решение - это напихать ключи в один словарь
def make_bimap(src): # src - dict
dst = {}
dst.update(src)
dst.update((v, k) for (k, v) in src.items())
return dst
Но при этом надо удостовериться, что нет конфликта ключей в обратном направлении.
Ну и не забываем про наследие предков. Бимапы люди делали издревле, и быстрый поиск даёт, например, PyPy.bidict.
Преимущества начинаются, когда у наследников есть полиморфные
статические члены: обычными виртуальными функциями их уже не пробросить, нужен механизм словарей/фабрик (в шарпе и яве это сделано на дженериках - ну или ручками, ручками всё)
свойства времени компиляции: типы, константы и всё такое - тут уже даже дженерики не спасут
template<class Impl> class Vehicle {
// пример статической функции
static Impl* create_road_train() {
if (!Impl::can_tow() || !Impl::can_be_towed()) return nullptr;
Impl* tow = Impl::create();
Impl* trailer = Impl::create();
return Impl::bind(tow, trailer);
// или, может быть
return tow->bind(trailer);
}
// пример свойств времени компиляции
Impl::WheelType wheels_[Impl::number_of_wheels];
};
Это уже отмазки пошли. Я сказал, зачем нужно делать new const T, вы сказали, что чаще бывает static T, я привёл сценарии - более чем рабочие! - а вы отделываетесь какой-то совершенно пустой фразой "главное, чтобы программист знал..."
Ну вот пусть программист и знает, что константы на куче размещать можно и нужно.
Если некий тип задуман как состоящий из константной (ключевой) и неконстантной частей, то лучше эти неконстантные части объявить как mutable.
Или вообще переделать дизайн программы, а то начинается "в этом контексте мы можем ломать константность только для этих полей, в другом контексте - только для тех полей, а в третьем ломать константность нельзя вовсе..." - и потом где-нибудь что-нибудь напутать и сломать.
const_cast, снимающий константность - это всегда звонкий колокол.
В ней просто названы несколько взятых наобум мусорных языков и показаны случайные примеры на них.
Что мы видим? Что это write-only языки, код на которых больно читать. И больше ничего не видим.
Какие идеи заложены в эти языки, помимо минимального синтаксиса и нечитаемости? Можете рассказать?
Давайте-ка я сделаю это за вас. Начну с "традиционных" вырвиглазок.
Старый добрый брейнфак. Это - разновидность машины Тьюринга. (В которую добавили бесконечное количество состояний ячеек и откуда убрали goto).
Unlambda. Комбинаторная логика на традиционном базисе SKI.
Йот. Довели КЛ до абсурда-и-предела, базис из единственного комбинатора i.
APL, J, K, Q. Это промышленные языки, которые работают с произвольными тензорами, а синтаксис упрощён в пользу тацитной (безымянной) нотации. Упор там сделан на очень быстрый парсер и очень быстрый интерпретатор.
Лисп. Лямбда-исчисление, код-как-данные, сам себя интерпретатор.
Форт. Стековая машина, ПОЛИЗ, и опять же сам себя интерпретатор.
А теперь посмотрим на то, что в статье.
Malbolge. Просто упоротая машина Тьюринга. (Но не брейнфак).
Whitespace. Брейнфакнутая версия форта.
Chef. Коболизированная версия форта с множеством стеков.
INTERCAL. Коболизированная версия бейсика.
Коболизированная версия брейнфака.
Скушно! Просто потрахать мозг. Никакой красивой математической идеи за ними не стоит.
Большое количество больших константных объектов в принципе не создают в статической памяти.
А если эти константы времени исполнения?
Например, строки. Например, содержимое конфиг-файла.
Или сообщения для обмена внутри одного процесса. Или даже сообщения для обмена между процессами через общую память (нужен соответствующий аллокатор, естественно).
1 клетка принимает 3 состояния и влезает в 2 разряда.
2 клетки - 3^2 = 9 состояний, 4 разряда.
3 клетки - 3^3 = 27 состояний, 5 разрядов.
Это значит, мы можем построить функции
using table = unsigned short; // 15 bit
using row = unsigned char; // 5 bit
using cell = unsigned char; // 2 bit
row encode_row(cell c0, cell c1, cell c2) {
return c0 + (c1 + c1*2) + (c2 + c2*8);
// на сдвигах, если хочется умножения экономить
}
const cell decode_row[27][3] = {
{0,0,0},{1,0,0},{2,0,0},
{0,1,0},...............,
...............,{2,2,2},
};
// что-то сходу лень думать, можно ли арифметическим колдовством
// обойтись без деления и при этом - без таблицы
В общем, дальше лень писать :)
Что будет быстрее работать, - деления или нудная работа с таблицами, - хз. Бенчмарки тоже лень писать.
Каждый раз, когда мне звонит робот-спамер, я оставляю заявку. Пусть холодный звонок превратится в горячий. В очень горячий для ушей живого оператора, который думал, что работать второй линией спамеров - это легко и приятно.
Кодировка UTF-16:он состоит издвух байтов (то есть 16 бит). Это означает что один символ весит 16 бит. В данную кодировку вмещается 2 ^ 16 = 65536 различных символов.
Ну вот нет. UTF-16 и UCS-2 - это разные кодировки. И та и другая используют двухбайтные слова, только у UCS-2 - на один символ ровно одно слово, поэтому она вмещает 65536 символов, а UTF-16 - это кодировка переменной длины! Почитайте про суррогатные пары самостоятельно, пожалуйста.
До кучи, ещё есть UTF-7.
Практический смысл разных UTF-n в том, что для ASCII (наиболее расхожий набор символов) UTF-8 кодируется 1 байтом, и для европейских алфавитов и всякой популярной графики UTF-16 кодируется одним словом (но китайцы уже страдают!), а UTF-32 хватит для всего UCS-4 - и вот это уже кодировка фиксированной длины.
Эффект сержанта уверенности.
Проблема не в том, что люди не знают, чего они не знают, а в том, что они это тоже не знают. (Хотя Сократ, например, знал).
Как говорится, "что мы знаем о лисе? - ничего! и то - не все!"
Кто вы, мастер упёртости или пофигист? Отвечайте честно.
Кликать на КАЖДУЮ засеренную строчку опросника - мотивирует вас, "вы узнаете что-то новое" или заставляет думать о личности автора?
Как бы не получился комикс "брошу яваскрипт и стану проституткой". С вот этим вот преобразованием чисел в строки (или строк в числа). Потому что тут рядом тусуются проблемы локалей.
Кажется, что вопрос не по теме поста. Как это соотносится с бимапами?
И, собственно, в чём проблема? В мемоизации функции f? Зачем нужен словарь, на что должна влиять монотонность и, тем более, линейность? Какой прикладной смысл этого всего?
Такую штуку делали в каком-то очень дремучем году, например, Microsoft ATL/WTL.
160 элементов - это всё ещё "мало". Были бы сотни тысяч, можно было бы подумать об эффективном хранении и из-за этого - об эффективном доступе. А тут...
Отдельный минус подхода - смешивание ключей туда-обратно. В языке со слабой типизацией можно накосячить с лёгкостью необычайной. Лучше соблюдать чистоту рук, однако!
Но кстати, быстрое-и-грязное решение - это напихать ключи в один словарь
Но при этом надо удостовериться, что нет конфликта ключей в обратном направлении.
Ну и не забываем про наследие предков. Бимапы люди делали издревле, и быстрый поиск даёт, например, PyPy.bidict.
Преимущества начинаются, когда у наследников есть полиморфные
статические члены: обычными виртуальными функциями их уже не пробросить, нужен механизм словарей/фабрик (в шарпе и яве это сделано на дженериках - ну или ручками, ручками всё)
свойства времени компиляции: типы, константы и всё такое - тут уже даже дженерики не спасут
Это уже отмазки пошли. Я сказал, зачем нужно делать new const T, вы сказали, что чаще бывает static T, я привёл сценарии - более чем рабочие! - а вы отделываетесь какой-то совершенно пустой фразой "главное, чтобы программист знал..."
Ну вот пусть программист и знает, что константы на куче размещать можно и нужно.
Это читерство и антипаттерны.
Если некий тип задуман как состоящий из константной (ключевой) и неконстантной частей, то лучше эти неконстантные части объявить как mutable.
Или вообще переделать дизайн программы, а то начинается "в этом контексте мы можем ломать константность только для этих полей, в другом контексте - только для тех полей, а в третьем ломать константность нельзя вовсе..." - и потом где-нибудь что-нибудь напутать и сломать.
const_cast, снимающий константность - это всегда звонкий колокол.
Плохая статья.
В ней просто названы несколько взятых наобум мусорных языков и показаны случайные примеры на них.
Что мы видим? Что это write-only языки, код на которых больно читать. И больше ничего не видим.
Какие идеи заложены в эти языки, помимо минимального синтаксиса и нечитаемости? Можете рассказать?
Давайте-ка я сделаю это за вас. Начну с "традиционных" вырвиглазок.
Старый добрый брейнфак. Это - разновидность машины Тьюринга. (В которую добавили бесконечное количество состояний ячеек и откуда убрали goto).
Unlambda. Комбинаторная логика на традиционном базисе SKI.
Йот. Довели КЛ до абсурда-и-предела, базис из единственного комбинатора i.
APL, J, K, Q. Это промышленные языки, которые работают с произвольными тензорами, а синтаксис упрощён в пользу тацитной (безымянной) нотации. Упор там сделан на очень быстрый парсер и очень быстрый интерпретатор.
Лисп. Лямбда-исчисление, код-как-данные, сам себя интерпретатор.
Форт. Стековая машина, ПОЛИЗ, и опять же сам себя интерпретатор.
А теперь посмотрим на то, что в статье.
Malbolge. Просто упоротая машина Тьюринга. (Но не брейнфак).
Whitespace. Брейнфакнутая версия форта.
Chef. Коболизированная версия форта с множеством стеков.
INTERCAL. Коболизированная версия бейсика.
Коболизированная версия брейнфака.
Скушно! Просто потрахать мозг. Никакой красивой математической идеи за ними не стоит.
А ещё есть const_cast и его помощники - функции std::move и std::as_const.
Большое количество больших константных объектов в принципе не создают в статической памяти.
А если эти константы времени исполнения?
Например, строки. Например, содержимое конфиг-файла.
Или сообщения для обмена внутри одного процесса. Или даже сообщения для обмена между процессами через общую память (нужен соответствующий аллокатор, естественно).
1 клетка принимает 3 состояния и влезает в 2 разряда.
2 клетки - 3^2 = 9 состояний, 4 разряда.
3 клетки - 3^3 = 27 состояний, 5 разрядов.
Это значит, мы можем построить функции
В общем, дальше лень писать :)
Что будет быстрее работать, - деления или нудная работа с таблицами, - хз. Бенчмарки тоже лень писать.
В функции set_cell ошибка, там сигнатура должна быть `void set_cell(state* s, .....)`
Элементарно! Если объект достаточно велик, чтобы жить на стеке.
Каждый раз, когда мне звонит робот-спамер, я оставляю заявку. Пусть холодный звонок превратится в горячий. В очень горячий для ушей живого оператора, который думал, что работать второй линией спамеров - это легко и приятно.
Интегральные схемы - это не совсем рассыпуха :))
У светодиодов нет инерции, надо бы её добавить - чтобы было какое-никакое послесвечение. Может быть, rc-цепочки на каждый столбец?
Ну вот нет. UTF-16 и UCS-2 - это разные кодировки. И та и другая используют двухбайтные слова, только у UCS-2 - на один символ ровно одно слово, поэтому она вмещает 65536 символов, а UTF-16 - это кодировка переменной длины! Почитайте про суррогатные пары самостоятельно, пожалуйста.
До кучи, ещё есть UTF-7.
Практический смысл разных UTF-n в том, что для ASCII (наиболее расхожий набор символов) UTF-8 кодируется 1 байтом, и для европейских алфавитов и всякой популярной графики UTF-16 кодируется одним словом (но китайцы уже страдают!), а UTF-32 хватит для всего UCS-4 - и вот это уже кодировка фиксированной длины.