为什么 Curry 的 std lib 中的非确定性选择函数没有直接定义,而是使用辅助 2 参数函数定义?
考虑 Curry 编程语言 中的一个函数 choose
,其规范为“< code>(choose xs) 非确定性地从列表 xs
中选择一个元素”。
我将通过两个替代的非确定性规则直接实现它:
choose :: [a] -> a
choose x:_ = x
choose _:xs = choose xs
但在 /usr/lib/curry-0.9.11/Success.curry 中来自 Muenster Curry 编译器< /a>,它是用辅助函数定义的:
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
(所以,这里又恢复了直截了当的态度。)
在哪些情况下它很重要?
Consider a function choose
in Curry programming language with the specification that "(choose xs)
non-deterministically chooses one element from the list xs
".
I'd implement it straighforwardly through two alternative non-deterministic rules:
choose :: [a] -> a
choose x:_ = x
choose _:xs = choose xs
But in /usr/lib/curry-0.9.11/Success.curry from Muenster Curry Compiler, it is defined with a helper function:
choose (x:xs) = choosep x xs
where choosep x [] = x
choosep x (_:_) = x
choosep _ (x:xs) = choosep x xs
What could be the advantages (if any) of the definition from the compiler supplied module?
Are the 2 definitions completely equivalent (even in some tricky cases with non-determinism and undefined values)?.. Is one of them more efficient in some cases?
ADDED: Deeper consideration
cthom06 (Thanks!) has correctly pointed out that my definition would cause hitting the undefined value in much more cases (because we would try to call this function with an empty-list argument once per each our "top-level" call with an initially non-empty list argument). (Hm, why haven't I noticed this consideration right away?..) That is less efficient.
But I wonder: are there any semantic differences? May the difference be important in some tricky contexts?
We see that the difference between the two definitions--in the case of non-empty lists--basically boils down to the difference between two potential definitions for id
:
my definition is like defining id
as:
id x = x
id _ = undefined
and their definition is like definig id
the normal way:
id x = x
(So, here the straightforwardness is reverted.)
In which contexts can it be important?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我相信没有语义差异,但具有辅助函数的效率更高,特别是在具有一个元素的列表的常见情况(在某些编程风格中)。在这种情况下,避免了一个选择点,您的版本需要将其设置为使用 [] 递归调用,然后必然会失败。
更聪明的优化器可能会自己解决这个问题,但是处理各种类似的情况可能具有挑战性 - 编译器需要尝试为数据类型中的每个可能的构造函数专门化应用程序,删除那些总是发生失败的构造函数,并且当只剩下一种可能性时,删除选择点。
I believe there are no semantic differences, but the one with the helper function is more efficient, particularly in the common case (in certain styles of programming) of a list with one element. In this case a choice point is avoided which with your version would need to be set up to call recursively with [] which is then bound to fail.
A smarter optimizer might figure this out for itself, but handling all kinds of similar situations is likely to be challenging - the compiler would need to try to specialize applications for each of the possible constructors in a datatype, remove those where failure always occurs, and remove choice points when only one possibility remains.