【问题标题】:How to normalize Perl function arguments for memoization?如何规范化 Perl 函数参数以进行记忆化?
【发布时间】:2012-06-01 00:19:18
【问题描述】:

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

  1. 深入比较嵌入式哈希和列表,而不是通过引用来比较
  2. 忽略哈希键顺序
  3. 忽略 3 和“3”之间的区别
  4. 生成一个相对易读的字符串(不是必需的,但很好用于调试)
  5. 表现良好(XS 优于 Perl)

这对于memoization 是必要的,即根据函数的参数缓存函数的结果。

作为一个稻草人示例,Memoize 将其用作默认规范化器,但 #1 和 #3 失败:

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

有一段时间我的首选规范化器是

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

但是,它会根据最近使用标量的方式来处理数字 3 和字符串“3”differently。这可以为本质上等效的参数列表生成不同的字符串,并降低记忆的好处。 (绝大多数函数不会知道或关心它们是否得到 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。

谢谢!

【问题讨论】:

标签: perl


【解决方案1】:

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

对于输入,深度扫描将任何字符串化数字替换为其值+0 即可。如果您知道确切的数字可能在哪里输入,您可以大大缩短此扫描时间。

对于输出,一些简单的状态机甚至正则表达式(是的,我知道输出不规则)很可能足以将纯数字字符串值剥离为数字。

【讨论】:

  • 嗯,不,我在上面列出了一些没有的序列化程序(如 Data::Dump 和 FreezeThaw)。 :) 也许您的意思是“任何好的序列化程序应该区别对待 3 和“3””。我不太确定,考虑到 Perl 值可以轻松和任意地在字符串和数字之间翻转。
  • 重新扫描,我提到输入扫描出于性能考虑是不可取的。如果必须完成,我希望它在 XS 中。但是,如果序列化程序可以选择关闭区分,那么效率会高得多。
  • 我刚才提到的输出扫描怎么样?这应该足够快。与依赖于未记录的怪癖相比,一个重要的优点是您始终可以确保手动剥离的值确实会被剥离。
  • @JonathanSwartz,好吧,我个人认为这是一个错误,如果我不太懒惰,我会填写一份报告。 :) 到目前为止,我认为 JSON::XS 和 YAML::XS 是最合乎逻辑的。
  • @JonathanSwartz Oleg 的观点是 your function 可以轻松地以与 JSON::XS 和 Storable 完全相同的方式区别对待 3'3' — 因此, 当记忆实际上有可能使函数发生故障时,删除区别,除非包装的函数是根据某些规则来执行字符串化/数字化的合同。
【解决方案2】:

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

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


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

【讨论】:

  • 抱歉,不,YAML::XS 的行为与任何序列化程序一样。试试perl -MYAML::XS -e 'my $v = "0333"; print YAML::XS::Dump $v; $v + 0; print YAML::XS::Dump $v; print "$v\n";'
  • @Oleg V. Volkov - 感谢您的评论,我更多地了解了 $YAML::XS::QuoteNumericStrings 的用途并编辑了我的答案。但我认为"0333""333"0333(即219)应该被OP 视为不同的输入。
  • 关于其余部分,YAML 只是剥离了字符串,而不管 ::Stringify 和对于 YAML 和 Dumper,我发现取决于未记录的行为是一个令人不安的想法。
猜你喜欢
  • 2018-09-18
  • 2014-08-10
  • 2020-07-31
  • 2018-01-27
  • 1970-01-01
  • 2015-03-20
  • 2010-10-22
  • 1970-01-01
  • 2016-05-17
相关资源
最近更新 更多