Чистота мемоизированных функций в D

Есть ли умные способы сохранения чистоты при запоминании функций в D?

Я хочу этого при кэшировании SHA1-расчетов больших наборов данных, хранящихся в оперативной памяти.


person Nordlöw    schedule 10.11.2013    source источник
comment
В каком смысле вы хотите, чтобы функция была чистой? Зачем тебе это нужно? -- Обычно требование наоборот; Функция должна быть чистой, чтобы разрешить запоминание.   -  person Markus Jarderot    schedule 11.11.2013
comment
@MarkusJarderot Да, функция должна быть pure для запоминания, но если вы запомните функцию, вы не сможете использовать этот запомненный результат внутри другой pure функции, потому что сохранение результата для запоминания требует нарушения чистоты. Итак, я предполагаю, что Нордлев пытается использовать мемоизацию внутри функции pure, и именно здесь у него возникают проблемы.   -  person Jonathan M Davis    schedule 11.11.2013


Ответы (2)


Короткий ответ: выберите запоминание или чистоту. Не пытайтесь иметь и то, и другое.

Длинный ответ: я не понимаю, как можно было бы сохранить чистоту с помощью мемоизации, если только вы не использовали приведения, чтобы солгать компилятору и заявить, что функция является 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, подумайте еще раз. Да, можно сделать некоторые вещи таким образом, которые вы не могли бы сделать иначе, но это очень рискованно. Лично я бы посоветовал вам решить, что важнее для вас — чистота или запоминание, и отказаться от другого. Все остальное очень рискованно.

person Jonathan M Davis    schedule 10.11.2013
comment
Разве не все было бы хорошо, если бы внутренняя таблица запоминания функции была локальной для потока, и я, конечно, правильно понял бы логику запоминания? - person Nordlöw; 11.11.2013
comment
@Nordlöw Независимо от того, находится ли он в TLS или нет, это не имеет ничего общего с чистотой. Конечно, если это не так, то вы подвергаете себя большим проблемам, когда делаете что-то вроде приведения функции к чистому, но проблема в том, что вы вынуждены приводить функцию к чистому, чтобы выполнить запоминание, а это открывая огромную банку червей. Если вы это сделаете, вы должны сделать это таким образом, чтобы он идеально имитировал то, что требуется системе типов для чистоты, и не нарушает ни одной из ее гарантий и не испортит ни одну из ее оптимизаций. Это требует, чтобы вы были очень хорошо осведомлены и очень осторожны. Я бы посоветовал даже не пытаться. - person Jonathan M Davis; 11.11.2013

То, что D позволяет выразить в системе типов, является нечистой функцией, которая запоминает чистую.

Концептуально мемоайзер также чист, но система типов недостаточно выразительна, чтобы допустить это. Вам нужно где-то схитрить.

person Andrei Alexandrescu    schedule 12.11.2013