15

考虑Curry 编程语言choose中的一个函数,其规范是“非确定性地从列表中选择一个元素”。(choose xs)xs

我将通过两个替代的非确定性规则直接实现它:

choose :: [a] -> a
choose x:_ = x
choose _:xs = choose xs

但是在Muenster Curry Compiler的 /usr/lib/curry-0.9.11/Success.curry 中,它是使用辅助函数定义的:

choose (x:xs) = choosep x xs
  where choosep x [] = x
        choosep x (_:_) = x
        choosep _ (x:xs) = choosep x xs

编译器提供的模块的定义有什么优点(如果有的话)?这两个定义是否完全等效(即使在一些具有不确定性和未定义值的棘手情况下)?..在某些情况下其中一个更有效吗?

补充:更深层次的考虑

cthom06(谢谢!)已正确指出我的定义会导致在更多情况下达到未定义的值(因为我们会尝试在每次“顶级”调用时使用空列表参数调用此函数一次非空列表参数)。(嗯,为什么我没有马上注意到这个考虑?..)那效率较低。

但我想知道:有任何语义差异吗?在某些棘手的情况下,差异可能很重要吗?

我们看到两个定义之间的差异——在非空列表的情况下——基本上归结为两个潜在定义之间的差异id

我的定义就像定义id为:

id x = x
id _ = undefined

他们的定义就像定义id正常的方式:

id x = x

(因此,这里的直截了当。)

在哪些情况下它可能很重要?

4

1 回答 1

2

我相信没有语义差异,但是具有辅助函数的那个​​更有效,特别是在具有一个元素的列表的常见情况下(在某些编程风格中)。在这种情况下,避免了选择点,您的版本需要设置为使用 [] 递归调用,然后必然会失败。

更聪明的优化器可能会自己解决这个问题,但处理各种类似情况可能具有挑战性——编译器需要尝试为数据类型中的每个可能的构造函数专门化应用程序,删除那些总是发生故障的构造函数,并且当只剩下一种可能性时,删除选择点。

于 2011-04-06T10:31:43.303 回答