Похоже, что вы ищете ярлык из цикла, как в C #, вы можете использовать continue
, break
или return
для выхода из цикла.
В F # способчтобы добиться этого с производительностью, нужно использовать хвостовую рекурсию.Этого можно добиться с помощью циклов while, но для этого требуются изменяемые переменные, в которых хвостовая рекурсия не нужна (хотя мы иногда ее используем).
Хвосто-рекурсивная функция - это та, которая вызывает себя в самом конце и не выполняетне смотрите на результат:
Так что это хвостовая рекурсия
let rec loop acc i = if i > 0 then loop (acc + i) (i - 1) else acc
Где это не
let rec loop fib i = if i < 1 then 1 else fib (i - 1) + fib (i - 2)
Если компилятор F # определяет, что функция - это хвост-рекурсивный компилятор применяет к функции оптимизацию хвостовой рекурсии (TCO), в основном он разворачивает ее в эффективный цикл for, который очень похож на цикл в C #.
Так что вот один из способов написатьvalidCol
с использованием хвостовой рекурсии:
let validCol column value : bool =
// loops is tail-recursive
let rec loop column value i =
if i < 9 then
if sudokuBoard.[i,column] = value then
false // The value already exists in the column, not valid
else
loop column value (i + 1) // Check next row.
else
true // Reach the end, the value is valid
loop column value 0
К сожалению;Компилятор F # не имеет атрибута для принудительного использования TCO (как в Scala или kotlin), и поэтому, если вы допустите небольшую ошибку, вы можете получить функцию, которая не является TCO.Я думаю, что я видел проблему GitHub о добавлении такого атрибута.
PS.seq
Понимания хороши во многих случаях, но для решателя судоку я предполагаю, что вы ищете что-то настолько быстрое, насколько это возможно.seq
понимания (и LINQ) Я думаю, что добавляет слишком много накладных расходов для решателя судоку, в то время как хвостовая рекурсия примерно так же быстро, как вы можете получить в F #.
PS.В .NET 2D массивы работают медленнее, чем 1D, просто к сведению.Не уверен, улучшилось ли оно с помощью dotnet core.