Как нормализовать аргументы функций Perl для мемоизации?

Как я могу нормализовать список аргументов функции к строке, чтобы два списка аргументов преобразовывались в одну и ту же строку, если они фактически эквивалентны? Алгоритм должен

  1. Глубоко сравнивать встроенные хэши и списки, а не по ссылке
  2. Игнорировать порядок ключей хэша
  3. Игнорировать разницу между 3 и «3»
  4. Генерировать относительно удобочитаемую строку (не обязательно, но приятно) to-have для отладки)
  5. Работать хорошо (XS предпочтительнее Perl)

Это необходимо для мемоизации, т.е. кэширования результата функции на основе ее аргументов.

В качестве соломенного примера, Memoizeиспользует его как нормализатор по умолчанию, который не работает #1 и #3:

$argstr = join chr(28),@_;  

Некоторое время моим обычным нормализатором был

JSON::XS->new->utf8->canonical

3 и строка "3" по-разному, в зависимости от того, как недавно использовался скаляр. Это может генерировать разные строки для по существу эквивалентных списков аргументов и уменьшать преимущества запоминания. (Подавляющему большинству функций все равно, получат ли они 3 или «3».)

Ради забавы я просмотрел кучу сериализаторов, чтобы увидеть, какие из них различают 3 и «3»:

Data::Dump   : equal - [3] vs [3]
Data::Dumper : not equal - [3] vs ['3']
FreezeThaw   : equal - FrT;@1|@1|$1|3 vs FrT;@1|@1|$1|3
JSON::PP     : not equal - [3] vs ["3"]
JSON::XS     : not equal - [3] vs ["3"]
Storable     : not equal - 
YAML         : equal - ---\n- 3\n vs ---\n- 3\n
YAML::Syck   : equal - --- \n- 3\n vs --- \n- 3\n
YAML::XS     : not equal - ---\n- 3\n vs ---\n- '3'\n

те, которые сообщают «равно», не уверены, как заставить их игнорировать порядок хеш-ключей.

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

Спасибо!

9
задан Jonathan Swartz 31 May 2012 в 14:11
поделиться