Ожидается, что это выражение будет иметь тип bool, но здесь есть ошибка типа - PullRequest
2 голосов
/ 18 апреля 2019

получаю сообщение об ошибке при попытке запустить эту строку кода, и я не могу понять, почему

    let validCol column value : bool = 
        for i in 0..8 do
            if sudokuBoard.[i,column] = value then 
                false
            else true

Ответы [ 3 ]

2 голосов
/ 18 апреля 2019

Как говорит Тайлер Хартвиг, цикл 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
1 голос
/ 18 апреля 2019

Похоже, что вы ищете ярлык из цикла, как в 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.

1 голос
/ 18 апреля 2019

В F # последний сделанный вызов - это то, что возвращается, вы явно объявили, что возвращаете bool.

Цикл for не может возвращать или агрегировать несколько значений, вместо этого возвращается unit.

let validCol column value : bool = 
    for i in 0..8 do
        if sudokuBoard.[i,column] = value then 
            false
        else 
            true

Здесь вам нужно выяснить, как агрегировать всеbool, чтобы получить ваш окончательный результат.Я не совсем уверен, что это должно вернуть, или я бы привел пример.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...