List 为什么Curry';s std lib不是直接定义的,而是使用辅助2参数函数?

List 为什么Curry';s std lib不是直接定义的,而是使用辅助2参数函数?,list,recursion,functional-programming,non-deterministic,curry,List,Recursion,Functional Programming,Non Deterministic,Curry,考虑一个函数choosein,其规范为“(choose xs)从列表xs中非确定性地选择一个元素” 我将通过两个可选的非确定性规则来实现它: 但是在/usr/lib/curry-0.9.11/Success.curry-from中,它是用一个helper函数定义的: 编译器提供的模块定义的优点(如果有的话)是什么? 这两个定义是否完全等效(即使在某些不确定和未定义值的棘手情况下)?。。在某些情况下,其中一个更有效吗 补充:更深入的考虑 cthom06(谢谢!)正确地指出,我的定义会导致在更多

考虑一个函数
choose
in,其规范为“
(choose xs)
从列表
xs
中非确定性地选择一个元素”

我将通过两个可选的非确定性规则来实现它:

但是在/usr/lib/curry-0.9.11/Success.curry-from中,它是用一个helper函数定义的:

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

补充:更深入的考虑 cthom06(谢谢!)正确地指出,我的定义会导致在更多的情况下命中未定义的值(因为我们将尝试使用空列表参数调用此函数,每次使用最初的非空列表参数调用“顶级”函数一次)。(嗯,为什么我没有立即注意到这种考虑?)效率较低

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

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

我的定义类似于将
id
定义为:

它们的定义类似于按常规方式定义id:

(因此,这里恢复了直线性。)


在哪些上下文中它会很重要?

我相信没有语义上的差异,但是带有helper函数的函数更有效,特别是在带有一个元素的列表的常见情况下(在某些编程样式中)。在这种情况下,避免了一个选择点,您的版本需要将该选择点设置为使用[]递归调用,然后[]将注定失败


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

我可能理解不正确,但在您的实现中,即使您最初向空列表传递了一个非空列表,尝试从空列表中选择一个值也可能会被卡住。@cthom06:“卡住”以这种方式并没有改变AFAIU的语义:然后简单地丢弃计算的变体。但这可能会稍微影响效率。因此,问题归结为:用一条规则定义
id x=x
或用一条额外的伪规则定义
id x=x
id x=x
id\ux=undefined
定义
id
的最大区别是什么?我想知道:语义会发生变化吗?@cthom06,为什么不回答这个问题呢?@Ben,我只是根据我所看到的猜测,我从来没有用过咖喱,只做过一点Haskell。顺便说一句,我的另一个评论也适用于此:不同之处在于中间解决方案的数量,以及解释器的工作方式,可能存在副作用(将“错误”视为副作用),但可能不存在完全计算的结果,除非存在一些封装的搜索。此外,懒惰也起到了一定作用,如果我们只取表达式的“head”而不点击“undefined”/error,那么输出解决方案的数量可能会有所不同。
choose :: [a] -> a
choose x:_ = x
choose _:xs = choose xs
choose (x:xs) = choosep x xs
  where choosep x [] = x
        choosep x (_:_) = x
        choosep _ (x:xs) = choosep x xs
id x = x
id _ = undefined
id x = x