imz*_*hev 15 recursion functional-programming list non-deterministic curry
考虑一个函数choose
在库里的编程语言与"规范(choose xs)
的非确定性选择一个元素从列表中xs
".
我将通过两个替代的非确定性规则直接实现它:
choose :: [a] -> a
choose x:_ = x
choose _:xs = choose xs
Run Code Online (Sandbox Code Playgroud)
但是在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
Run Code Online (Sandbox Code Playgroud)
编译器提供的模块定义的优点(如果有的话)是什么?2个定义是否完全等价(即使在一些非确定性和未定义值的棘手情况下)?在某些情况下,其中一个更有效吗?
cthom06(谢谢!)已经正确地指出我的定义会导致在更多情况下达到未定义的值(因为我们会尝试使用一个空列表参数调用此函数,每次我们的"顶级"调用一次非空列表参数).(嗯,为什么我没有立刻注意到这个考虑因素?..)效率较低.
但我想知道:有任何语义差异吗?可能在一些棘手的情况下,差异是否重要?
我们看到两个定义之间的差异 - 在非空列表的情况下 - 基本上归结为两个潜在定义之间的差异id
:
我的定义就像定义id
为:
id x = x
id _ = undefined
Run Code Online (Sandbox Code Playgroud)
他们的定义就像定义id
正常的方式:
id x = x
Run Code Online (Sandbox Code Playgroud)
(所以,这里的直截了当还原.)
在哪些情况下它很重要?
我相信没有语义差异,但具有辅助函数的效率更高,特别是在具有一个元素的列表的常见情况(在某些编程风格中)。在这种情况下,避免了一个选择点,您的版本需要将其设置为使用 [] 递归调用,然后必然会失败。
更聪明的优化器可能会自己解决这个问题,但处理各种类似的情况可能具有挑战性 - 编译器需要尝试为数据类型中的每个可能的构造函数专门化应用程序,删除那些总是发生失败的构造函数,并且当只剩下一种可能性时,删除选择点。