“这个表达式应该有类型单位”但我希望它是布尔值

时间:2014-03-15 18:44:06

标签: types f# tuples unit-type

我试图创建一个将元组与元组数组的值进行比较的函数。我需要这个返回一个布尔值,但VS2013一直告诉我: "这个表达式应该有' unit',但是有类型' bool'"

let compare (i,j,a,(x : (int*int*int) array)) =
    for q in 0 .. x.GetLength(0) do  
        match (i,j,a,x) with
        | (i,j,a,x) when (i,j,a) = x.[q] -> true
        |  _ -> false

还尝试将值作为两个参数给出,但它也不起作用:

let compare (i,j,a) (x : (int*int*int) array) =
    for q in 0 .. x.GetLength(0) do  
        match (i,j,a) with
        | x.[q] -> true
        |  _ -> false

任何帮助将不胜感激!

3 个答案:

答案 0 :(得分:7)

为了扩展一点Chris的答案,你的代码不起作用的主要原因是F#是一种基于表达式的语言,并且没有命令式的控制流你可能会在这里期待(如果你错误地将表达式的主体读作return关键字)。

由于F#是基于表达式的,因此所有内容都是一个计算结果为值的表达式。因此,true是一个计算结果为true(布尔值)的表达式。您的示例中的模式匹配:

match (i,j,a,x) with
| (i,j,a,x) when (i,j,a) = x.[q] -> true
|  _ -> false

...也是一个表达式,根据变量的值计算为truefalse(布尔值)。在这种情况下,条件会更简单:

if (i,j,a,x) = x.[q] then true else false

...或者您可以写出条件(i,j,a,x) = x.[q],这意味着完全相同的事情。现在,for循环很棘手,因为它会多次计算主体,因此它可能会获得多个返回值。出于这个原因,F#有一个特殊类型unit(在C#中认为是void),它代表一个不携带任何信息的值。因此,for循环期望unit - 返回正文:

for i in 1 .. 10 do 
  printfn "Foo"

您可以通过编写例如:

来检查printfn "Foo"是否实际返回单位值
for i in 1 .. 10 do 
  let nothing = printfn "Foo"
  nothing

如果将鼠标指针放在nothing上,则会看到它的类型为unit

因此,如果你想在中间打破迭代,for循环不是一个好方法(因为它不能在F#中完成)。正如Chris和Søren已经提到的,您可以使用Array模块中的函数轻松实现逻辑。或者,您必须使用递归或可变变量来编写它 - 但Array模块在​​这里工作得很好。

答案 1 :(得分:3)

短而甜蜜:

let compare triple x = Array.exists ((=) triple) x

无需解压缩元组(i, j, x)

符号(=)将相等比较运算符转换为两个curried参数的函数。当我们将(=)部分应用于triple时,也就是说,当我们写

(=) triple

我们得到一个带有一个参数的函数,并将该参数与triple进行比较,返回true或false。

答案 2 :(得分:2)

问题是for循环期望其中的表达式计算为unit。您将需要一种不同的方法,例如使用Array.exists