10

在函数式编程中,将任何“循环”代码优化为尾递归通常很重要。然而,尾递归算法通常分为两个函数 - 一个设置基本情况,另一个实现实际循环。一个好的(尽管是学术的)例子是反向函数。

reverse :: [a] -> [a]
reverse = reverse_helper []

reverse_helper :: [a] -> [a] -> [a]
reverse_helper result [] = result
reverse_helper result (x:xs) = reverse_helper (x:result) xs

“reverse_helper”并不是一个很好的描述性名称。但是,“reverse_recursive_part”很尴尬。

对于这样的辅助函数,您会使用什么命名约定?

4

7 回答 7

23

您可以随心所欲地调用辅助函数,只要您不将辅助函数放在“全局”命名空间中,这无关紧要。简单地添加一个“素数”似乎是一种常见的做法。:) 例如,在 Haskell 中,

reverse :: [a] -> [a]
reverse = reverse' []
    where reverse' :: [a] -> [a] -> [a]
          reverse' result [] = result
          reverse' result (x:xs) = reverse' (x:result) xs
于 2009-01-06T22:43:15.243 回答
7

我总是使用do_,比如“do_compute”和“compute”。我发现它非常具有描述性,因为它实际上是执行操作的函数的一部分,而被调用的“计算”需要为外部世界提供一个简单的描述性名称。

于 2009-01-06T22:34:39.347 回答
7

我同意 ShreevatsaR 的观点,如果您不将辅助函数设为顶级(或者更糟,将其放在导出列表中),那么它的名称无关紧要。我倾向于调用辅助函数fg.

reverse :: [a] -> [a]
reverse = f []
  where
    f ys []     = xs
    f ys (x:xs) = f (x:ys) xs

我只是将这个命名方案用于小函数(否则我不知道f指的是什么)。再说一次,你为什么要写大函数?

但是,如果您确实想导出您的“助手”功能,因为它可能对其他人有用,我会称之为:

reverseAccumulator

像 HaskellzipzipWith. 但我不会调用那些“帮助”函数,zipWith它只是一个通用函数并且zip是默认实现(可能是使用最多的那个)。

于 2009-01-06T23:21:21.377 回答
3

我倾向于在末尾添加“_recurse”。所以“reverse_recurse”。不知道我从哪里得到的。我喜欢像您在示例中那样简单地保留基本案例功能。它往往是“公共”函数,并且它使用辅助函数来执行迭代的事实与调用者无关。在 javascript 中,我有时甚至会通过闭包隐藏迭代函数,以明确它不是直接调用的。

于 2009-01-06T21:01:51.780 回答
3

我使用auxor foo_aux(用于 main 函数foo),并嵌套定义,使其在外部不可见。

于 2009-01-07T01:31:28.507 回答
3

我也同意 ShreevatsaR 的观点,在这个例子中,我会将助手设为私有函数。

对于我需要帮助函数在整个模块中可见但不导出的其他情况,我倾向于在函数前加上'_'。当然,有明确的导出语句,但在开发过程中,我倾向于导出所有函数以简化交互式探索,例如在 ghci 中。稍后,我添加了导出函数的列表,并且下划线可以很容易地记住我是否打算将函数作为本地函数。

于 2009-01-07T09:19:39.453 回答
1

设置并执行

例子:

function whateverSetup() { ... }
function whateverExecute() { ... }
于 2009-01-06T20:59:50.490 回答