在 F# 中,函数的返回值是函数中计算的最后一个表达式。那么,让我们重点关注以下几点:
if ex < 1 then
if ex = 0 then res (* <--- this is not an early return *)
ex <- -ex (* <--- F# evaluates this code after the *)
n <- 1 / n (* if statement *)
此外,if 语句具有返回值,该返回值也恰好是 if 语句中执行的最后一个值。如果 if 语句不是函数的返回值,则它应该具有返回类型unit
。请注意,变量赋值的返回类型为unit
.
我们需要重写您的代码以适应您的提前返回,因此我们可以这样做:
let FastPow2 num exp =
if exp = 0 then 1
else
let mutable ex = exp
let mutable res = 1
let mutable n = num
if ex < 1 then
ex <- -ex
n <- 1 / n
while ex > 1 do
if (ex % 2 = 1) then (* still have a bug here *)
res <- res * n
n <- n * n
exp >>> 1 (* <--- this is not a variable assignment *)
res * n
尽管我认为 F# 在错误的位置报告了错误,但我们仍然存在一个错误。表达方式exp >>> 1
返回一个 int,它不分配任何变量,因此它不等同于原始 C# 代码。我认为你的意思是使用ex
变量代替。我们可以按如下方式修复您的代码:
let FastPow2 num exp =
if exp = 0 then 1
else
let mutable ex = exp
let mutable res = 1
let mutable n = num
if ex < 1 then
ex <- -ex
n <- 1 / n
while ex > 1 do
if (ex % 2 = 1) then
res <- res * n
n <- n * n
ex <- ex >>> 1
res * n
现在你的功能已经固定了,但它真的很难看。让我们将其转换为更惯用的 F#。您可以用模式匹配替换 if 语句,并用递归替换 while 循环:
let FastPow2 num exp =
match exp with
| 0 -> 1
| _ ->
let rec loop ex res n =
if ex > 1 then
let newRes = if ex % 2 = 1 then res * n else res
loop (ex >>> 1) newRes (n * n)
else res * n
let ex, n = if exp < 1 then (-exp, 1 / num) else (exp, num)
loop ex 1 n
好多了!还有一些空间可以美化这个功能,但你明白了:)