如何规范化Perl函数参数以进行memoization?

时间:2012-05-31 13:58:19

标签: perl

如何规范化字符串的函数参数列表,以便两个参数列表转换为相同的字符串iff它们实际上是等效的?算法

  1. 深入比较嵌入式哈希和列表,而不是通过引用
  2. 忽略哈希键顺序
  3. 忽略3和“3”之间的差异
  4. 生成一个相对可读的字符串(不是必需的,但很适合调试)
  5. 表现良好(XS优于Perl)
  6. 这对于memoization是必要的,即根据其参数缓存函数的结果。

    作为一个稻草人的例子,Memoize使用它作为默认规范化器,它失败了#1和#3:

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

    有一段时间我的首选标准化器是

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

    然而,它根据最近使用标量的方式处理数字3和字符串“3”differently。这可以为基本等效的参数列表生成不同的字符串,并降低memoization的好处。 (绝大多数职能部门不知道或不关心他们是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 - <unprintable>
    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。

    谢谢!

2 个答案:

答案 0 :(得分:2)

几乎任何序列化程序都会以不同的方式处理3和“3”,因为它不知道数字和字符串化数字对您来说是相同的,并且这种假设对于一般数据是错误的。您必须自己标准化输入或输出。

对于输入,深度扫描将替换任何带字符串的数字,其值为+ 0。如果你知道输入的确切数字在哪里,你可以大大缩短这个扫描。

对于输出,一些简单的状态机甚至regexp(是的,我知道输出不是常规的)很可能足以将只有数字的字符串值去掉数字。

答案 1 :(得分:2)

默认情况下,

YAML及其后代排序哈希键。设置$YAML::SortKeys = 2以对深度哈希进行排序。

$YAML::Stringify设置为真值并将$YAML::XS::QuoteNumericStrings设置为false值可帮助您规范化数值。后一种设置将“取消引用”一个看起来像数字的字符串值。


此外,您可以使用$Data::Dumper::Sortkeys = 1使用Data::Dumper规范化输出顺序。设置$Data::Dumper::Useqq = 1将取消引用看起来像数字的字符串。