#f#
#f#
Вопрос:
получение ошибки при попытке запустить эту строку кода, и я не могу понять, почему
let validCol column value : bool =
for i in 0..8 do
if sudokuBoard.[i,column] = value then
false
else true
Ответ №1:
Как говорит Тайлер Хартвиг for
, цикл не может возвращать значение, кроме unit
.
С другой стороны, внутри понимания списка или seq
выражения вычисления вы можете использовать for
yield
значения, а затем проверить, существует ли то, что вы ищете:
let validCol column value : bool =
seq { for i in 0..8 do yield sudokuBoard.[i,column] }
|> Seq.exists value
|> not
Ответ №2:
В F # возвращается последний выполненный вызов, вы явно объявили, что возвращаете bool .
for
Цикл не может вернуть или объединить несколько значений, вместо этого возвращается bun unit
.
let validCol column value : bool =
for i in 0..8 do
if sudokuBoard.[i,column] = value then
false
else
true
Здесь вам нужно выяснить, как объединить все bool
, чтобы получить конечный результат. Я не совсем уверен, что это должно возвращать, или я бы привел пример.
Ответ №3:
Похоже, вы ищете короткий выход из цикла, как в 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.