我试图在F#中获得此vb.net代码的完全等效(不起作用):
Function FastPow(ByVal num As Double, ByVal exp As Integer) As Double Dim res As Double = 1 If exp < 1 Then If exp = 0 Then Return res exp = -exp num = 1 / num End If Do While exp > 1 If exp Mod 2 = 1 Then res = res * num num = num * num exp = exp >> 1 Loop Return res * num End Function
我写了这个:
let FastPow num exp = let mutable ex = exp let mutable res = 1 let mutable n = num if ex < 1 then if ex = 0 then res ex <- -ex n <- 1 / n while ex > 1 do if (ex % 2 = 1) then res <- res * n n <- n * n exp >>> 1 res * n
但在"如果ex = 0然后res"行中我得到一个错误:
"这个表达式有类型int但是在这里用于类型单位".我无法理解为什么它会给我这个错误.
编辑:我实际上也收到了一个警告:
"这个表达式应该有'unit'类型,但是类型为'int'."
at"if(ex%2 = 1)then"
在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
好多了!还有一些空间来美化这个功能,但你明白了:)