В 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
Намного лучше! Есть еще немного места, чтобы украсить эту функцию, но вы поняли:)