F#编译器错误 "This expression was expected to have type unit but here has type bool." 在{if else}语句中的表达式

4

我用F#写了这样一个函数:

let TwistBasket (reverse: bool, quarters: int, overTwist: int byref) =
    overTwist <- 50
    WaitForBasketReady()
    waitBasket.Reset()
    let move = 135*quarters - 25 + overTwist
    let speed =
        match reverse with
            | true -> -75y
            | false -> 75y
    let waitHandle = motorBasket.SpeedProfile(speed, 15u, uint32 move, 10u, true)
    Task.Factory.StartNew(fun () ->
        waitHandle.WaitOne()
        if (overTwist <> 0) then
            motorBasket.SpeedProfile(sbyte -speed, 0u, uint32 overTwist, 0u, true).WaitOne()
        waitBasket.Set()

在这个if语句中;
    if (overTwist <> 0) then
         motorBasket.SpeedProfile(sbyte -speed, 0u, uint32 overTwist, 0u, true).WaitOne()

我遇到了这个错误:This expression was expected to have type unit but here has type bool.

实际上,motorBasket.SpeedProfile().WaitOne()返回一个布尔语句。我需要它。

因为我正在尝试将这个if else语句转换成C#:

        Task.Factory.StartNew(() =>
        {
            waitHandle.WaitOne();
            if (overTwist != 0)
            {
                motorBasket.SpeedProfile((sbyte) -speed, 0, (uint) overTwist, 0, true).WaitOne();
            }
            waitBasket.Set();
        });

我该如何修复我的错误?

1
你尝试过在表达式中添加 |> ignore 吗? - Gus
如果我添加 |> ignore,我仍然可以获取结果吗?因为这对我非常重要。 - yusuf
1
你想通过这个结果做什么?在C#的版本中,它只是忽略了它。 - Gus
谢谢你的帮助Gustavo。但实际上我将会再次遇到类似的问题,在接下来的语句中Petr的方法可能会更有用。 - yusuf
1
没问题。原则上我会坚持使用C#版本,然后一旦完成工作翻译,我可能会进行重构。由你决定! - Gus
是的,你说得对。我想我之后需要编辑我的问题。 :) - yusuf
2个回答

3

通过查看C#版本,其不会对结果进行任何操作。所以在F#中,我将调用ignore函数来“吃掉”结果:

if (overTwist <> 0) then
     motorBasket.SpeedProfile(sbyte -speed, 0u, uint32 overTwist, 0u, true).WaitOne() |> ignore

F# 在这些情况下比 C# 更加严格,如果你的 if .. then 没有 else 分支,它的结果应该是 unit,这是非常合理的。

你也可以创建一个带有(虚拟的)布尔值的 else 分支,并将其绑定到(虚拟的)值上,但在这种特定情况下,如果你真的不打算使用那个值,这样做有什么意义呢?实际上你正在创建一个副作用并忽略结果,F# 驱使你在代码中更加明确地表达这一点。


2
在 F# 中,if/else 表达式应该具有相同的类型。如果您使用没有 else 分支的 if 表达式,则 F# 编译器会隐式地认为 else 分支具有类型 unit,因此会出现错误。您可以更改代码以显式使用 else 分支:
if (overTwist <> 0) then
    motorBasket.SpeedProfile(sbyte -speed, 0u, uint32 overTwist, 0u, true).WaitOne()
else
    ... // Put here expression of the same type as if (I assume it's bool)

或者,你可以在if分支中使用Gustavo提到的ignore函数。


实际上,仅添加else分支无法解决问题。您需要将if .. then .. else ..表达式分配给let-bind值。如果该值未被使用,则可以执行let _ = if .. then .. else ..。在任何情况下,最好将表达式发送到ignore,但是这样您就不需要else ;) - Gus

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接