该表达式应具有布尔类型,但此处具有类型单元错误

时间:2019-04-18 04:01:40

标签: f#

在尝试运行此行代码时出现错误,但我不知道为什么

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

3 个答案:

答案 0 :(得分:2)

正如泰勒·哈特维格(Tyler Hartwig)所说,for循环无法返回除unit之外的值。

另一方面,在列表推导或seq计算表达式中,您可以使用foryield值,然后测试您要查找的值是否存在:< / p>

let validCol column value : bool = 
    seq { for i in 0..8 do yield sudokuBoard.[i,column] }
    |> Seq.exists value
    |> not

答案 1 :(得分:1)

在F#中,最后一次调用是返回的内容,您已明确声明要返回布尔值。

for循环无法返回或聚合多个值,而用bun则返回unit

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

在这里,您需要弄清楚如何汇总所有bool以获得最终结果。我不太确定这应该返回什么,或者我举个例子。

答案 2 :(得分:1)

似乎您正在寻找循环的捷径,就像在C#中,您可以使用continuebreakreturn退出循环一样。

在F#中,通过性能实现此目的的方法是使用尾递归。您可以使用while循环来实现它,但是它需要可变的变量,而尾部递归不需要可变的变量(尽管有时我们会使用它)。

tail-recursive函数是一个在最后调用自己而不看结果的函数:

所以这是尾递归的

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数组慢,仅是FYI。不确定使用dotnet core是否可以改善。