Есть ли умные способы сохранения чистоты при запоминании функций в D?
Я хочу этого при кэшировании SHA1-расчетов больших наборов данных, хранящихся в оперативной памяти.
Есть ли умные способы сохранения чистоты при запоминании функций в D?
Я хочу этого при кэшировании SHA1-расчетов больших наборов данных, хранящихся в оперативной памяти.
Короткий ответ: выберите запоминание или чистоту. Не пытайтесь иметь и то, и другое.
Длинный ответ: я не понимаю, как можно было бы сохранить чистоту с помощью мемоизации, если только вы не использовали приведения, чтобы солгать компилятору и заявить, что функция является pure
, когда это не так, потому что для того, чтобы чтобы запомнить, вы должны сохранить аргументы и результат, что нарушает чистоту, поскольку гарантия номер один для pure
функций заключается в том, что они не обращаются к изменяемым глобальным или статическим переменным (это единственный способ, которым вы могли бы запомнить что-либо).
Итак, если вы сделали что-то вроде
alias pure nothrow Foo function() FuncType;
auto result = (cast(FuncType)&theFunc)();
то вы можете обращаться с theFunc
так, как если бы это было pure
, когда это не так, но тогда вам нужно убедиться, что функция действует pure
извне, включая работу с тем фактом, что компилятор считает, что он может изменить изменчивость возвращаемый тип строго pure
функции, которая возвращает изменяемый тип. Например, этот код отлично скомпилируется
char[] makeString(size_t len) pure
{
return new char[](len);
}
void main()
{
char[] a = makeString(5);
const(char)[] b = makeString(5);
const(char[]) c = makeString(5);
immutable(char)[] d = makeString(5);
immutable(char[]) e = makeString(5);
}
хотя тип возвращаемого значения всегда изменчив. И это потому, что компилятор знает, что makeString
строго соответствует pure
, и возвращает значение, которое не могло быть ему передано — так что это гарантированно будет каждый раз новое значение — и, следовательно, изменение изменяемости возвращаемого типа на const
или immutable
не нарушает систему типов.
Если бы вы сделали что-то внутри makeString
, что включало бы приведение функции к pure
, когда это нарушало бы гарантию того, что makeString
всегда возвращает новое значение, то вы нарушили бы систему типов, и вы бы рисковали иметь очень ошибочный код в зависимости от о том, что вы сделали со значениями, возвращенными из makeString
.
Единственный известный мне способ получить чистоту, когда у вас ее нет, — это преобразовать указатель функции так, чтобы он был pure
, но если вы это сделаете, то вы должны полностью понять, что гарантирует pure
делает функция и что, по мнению компилятора, он может с ней сделать, чтобы вы полностью имитировали ее поведение. Это проще, если вы возвращаете immutable
данных или тип значения, потому что тогда у вас нет проблемы с компилятором, изменяющим изменчивость возвращаемого типа, но это все еще очень сложное дело.
Итак, если вы думаете о приведении чего-либо к pure
, подумайте еще раз. Да, можно сделать некоторые вещи таким образом, которые вы не могли бы сделать иначе, но это очень рискованно. Лично я бы посоветовал вам решить, что важнее для вас — чистота или запоминание, и отказаться от другого. Все остальное очень рискованно.
То, что D позволяет выразить в системе типов, является нечистой функцией, которая запоминает чистую.
Концептуально мемоайзер также чист, но система типов недостаточно выразительна, чтобы допустить это. Вам нужно где-то схитрить.
pure
для запоминания, но если вы запомните функцию, вы не сможете использовать этот запомненный результат внутри другойpure
функции, потому что сохранение результата для запоминания требует нарушения чистоты. Итак, я предполагаю, что Нордлев пытается использовать мемоизацию внутри функцииpure
, и именно здесь у него возникают проблемы. - person Jonathan M Davis   schedule 11.11.2013