【问题标题】:F# Function The 'if' expression needs to have type 'unit' to satisfy context type requirementF# 函数 'if' 表达式需要具有类型 'unit' 以满足上下文类型要求
【发布时间】:2021-10-23 05:58:59
【问题描述】:

在下面的函数 doTransfer 中出现错误:

'if' 表达式需要具有类型 'unit' 以满足上下文类型要求。它目前的类型为'bool.此错误出现在以以下结尾的每一行:

if xxxxxresult  = false then return false 

注意 - 分配给 clickTransferResult 的变量应始终 = 布尔值。我不确定我做错了什么。如果结果在任何时候为假,它应该退出函数

    let clickTransferTab (page: IPage, dataId: string) = async {
        try 
            // Click Transfer tab
            let! selector = Async.AwaitTask(page.WaitForSelectorAsync("div[data-id='"+dataId+"'] a.t3"))
            do! Async.AwaitTask(selector.ClickAsync())
            return true
        with ex ->
            return false
    }

    let doTransfer (page: IPage,
                    dataId: string,
                    transferAmount: string,
                    bankAccountText: string) = async {
        try
            let! clickTransferResult = clickTransferTab(page,dataId) 
            if clickTransferResult = false then return false 
            
            let! selectBankresult = clickTransferTab(page,dataId) 
            if selectBankresult = false then return false 

            let! enterTransferResult = clickTransferTab(page,dataId) 
            if enterTransferResult = false then return false 

            let! reconcilResult = clickTransferTab(page,dataId) 
            if reconcilResult = false then return false 

            return true
        with ex ->
            return false
    }

【问题讨论】:

  • 请注意,return 在 F# 中的含义与在 C# 中的含义不同。它确实会返回一个值,但不会阻止函数的其余部分运行,这就是您需要else 的原因。只需要它,因为您在 async 计算表达式中。

标签: f#


【解决方案1】:

if 在 F# 中是一个表达式,而不是像其他语言那样的语句。例如,你可以写:

let x = if x > 5 then true else false

if 计算为一个值,并分配给x。在这种情况下,它将是 truefalse。但必须有一个价值。假设你会写。

let x = if x > 5 then true

如果 x 小于 5,x 应该有什么值?这根本不是有效的代码。您始终必须为这两种情况提供一个值。这里你可能想要false,但你必须明确写出来

let x = if x > 5 then true else false

或者在这种情况下你可以写:

let x = x > 5

此规则的唯一例外是then 案例返回unit 值。在这种情况下,只有一个值,所以它也会在else分支中返回unit

F# 中的if 类似于其他语言中的Ternary Operator

所以你必须写这样的东西

let! clickTransferResult = clickTransferTab(page,dataId) 
if clickTransferResult = false then 
    return false 
else
    let! selectBankresult = clickTransferTab(page,dataId) 
    if selectBankresult = false then 
        return false 
    else
        let! enterTransferResult = clickTransferTab(page,dataId) 
        if enterTransferResult = false then 
            return false 
        else
            let! reconcilResult = clickTransferTab(page,dataId) 
            if reconcilResult = false then 
                return false
            else
                return true

【讨论】:

  • 好吧,我没想到它必须返回一个 true 和一个 false 。我想这就是 C# 和 F# 之间的区别(或其中之一。我只是在每个错误行中添加了 else ,发现它更容易阅读
【解决方案2】:

FWIW,您可以使用一点计算表达式来避免嵌套的if-then-else 表达式:

type AsyncBoolBuilder() =
    member _.Return(flag : bool) =
        async { return flag }
    member _.Bind(aflag, f) =
        async {
            let! flag = aflag
            if flag then
                return! f flag
            else
                return false
        }

let asyncBool = new AsyncBoolBuilder()

示例用法:

let isEvenAsync n =
    async {
        let isEven = (n % 2 = 0)
        printfn "isEven %A: %A" n isEven
        return isEven
    }

[<EntryPoint>]
let main args =
    let final =
        asyncBool {
            let! flag4 = isEvenAsync 4
            let! flag5 = isEvenAsync 5
            let! flag6 = isEvenAsync 6
            return true
        } |> Async.RunSynchronously
    printfn "Final flag: %A" final
    0

输出:

isEven 4: true
isEven 5: false
Final flag: false

注意isEvenAsync 6 永远不会被执行,因为isEvenAsync 5false

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-04-14
    • 1970-01-01
    • 1970-01-01
    • 2011-07-24
    • 2019-04-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多