F#两个递归函数定义在行为上的奇怪差异

时间:2018-07-18 19:23:31

标签: recursion f#

我正在尝试定义一个幂函数来计算x ^ y。

let rec powFunA  (x,y) = 
  match (x,y) with
  | (_,0) -> 1
  | (x,y) -> x * powFunA (x,y-1);;

let rec powFunB  x y =
  match y with
  | 0 -> 1
  | y -> x * powFunB x y-1;;

呼叫powFunA (2,5)可以正常工作,并且得到预期的结果是32。但是不知何故,我不明白为什么,第二个呼叫powFunB 2 5会导致一个StackOverflowException

我还遇到了一个定义:

let rec power = function
    | (_,0) -> 1.0 (* 1 *)
    | (x,n) -> x * power(x,n-1) (* 2 *) 

能否请您在定义的第一行说明参数的缺失以及 function 的用法。

谢谢。

1 个答案:

答案 0 :(得分:4)

此堆栈溢出错误与F#的优先级规则有关。考虑以下表达式:

powFunB x y-1

此表达式具有一些功能应用程序和减号运算符。在F#中(与所有ML语言一样),函数应用程序具有最高的优先级。没有什么比绑定更具约束力了。

因此,编译器将上述表达式理解为:

(powFunB x y) - 1

也就是说,函数应用程序powFunB x y首先,减去运算符。现在,我希望很容易看出为什么会导致无限递归。

要解决此问题,只需应用括号即可覆盖优先级规则:

powFunB x (y-1)

“无参数”定义使用F#语法定义多案例函数。这只是允许写= function而不是x = match x with的快捷方式。因此,例如,以下两个功能是等效的:

let f a = match a with | Some x -> [x] | None -> []
let g = function | Some x -> [x] | None -> []

就是一些语法糖,仅此而已。因此,您发现的定义与第一个代码段完全相同。