此表达式应具有 xxxx 类型,但此处具有类型 unit

This expression was expected to have type xxxx but here has type unit

以下代码对于两个 printfn 都有类型错误。

我该如何解决?即使其中一项失败,我也希望 Seq.map 循环继续。

// files should be a Seq of record 
let files = seqOfStrs |> Seq.map(fun s ->
    match s with
    | Helper.ParseRegex "(\w+) xxxxx" month ->
        let currentMonth =  .....
        if currentMonth = month.[0] then
            doc.Load(shelf)
            // parse doc and return record type. Omitted
        else
            printfn "Expect %s found %s." currentMonth month.[0] //Error
    | _ ->
        printfn "No '(Month) Payment Data On Line' prompt." //Error

问题是你的逻辑的不同分支产生不同的东西。在 "omitted" 部分中,您显然 returning 类型为 xxxx 的值(例如 string),但在具有 printfn 调用的其他分支中,您是 returning 没有值,在 F# 中表示为 unit,在其他语言中通常称为 void.

如果您不希望循环继续,最简单的答案就是在这些情况下抛出异常,例如:

failwithf "Expect %s found %s." currentMonth month.[0]

failwithf 的静态 return 类型可以是任何类型,包括 string,因为它实际上从未 returns 所以实际上不必产生该类型的值。

鉴于您确实希望代码继续,您可以 return 一个空字符串或某种失败值,例如:

printfn "Expect %s found %s." currentMonth month.[0] //Error
"failed"

现在所有分支都具有相同的类型,因此您的代码可以编译,但您必须小心调用者不要意外地将此值解释为一些有效结果,这就是为什么抛出异常通常更清晰。

更简洁的方法是使用 option 值来表示成功或失败,即 return Some "..." 表示正确的情况,None 表示错误的情况。当失败是调用代码想要处理的常见情况而不是仅仅向用户报告问题并中止时,这种方法更好:

// files should be a Seq of record 
let files = seqOfStrs |> Seq.map(fun s ->
    match s with
    | Helper.ParseRegex "(\w+) xxxxx" month ->
        let currentMonth =  .....
        if currentMonth = month.[0] then
            doc.Load(shelf)
            // parse doc and produce record type.
            Some record
        else
            printfn "Expect %s found %s." currentMonth month.[0] //Error
            None
    | _ ->
        printfn "No '(Month) Payment Data On Line' prompt." //Error
        None

您现在需要决定您希望 files 在该点包含什么 - 您是希望显式 None 值显示某事失败,还是只希望序列包含正确的值并完全忽略失败?

如果您想要明确的值,那么您可以只保留 option 值,您将得到 seq<string option> 结果。请注意,此类型只是 seq<option<string>> 的语法糖,反映了 F# 的 O'Caml 传统。

如果您只想省略它们,请将您的 Seq.map 调用替换为 Seq.choose,这将删除所有 None 值并剥离 Some 包装器, 留给您 seq<string> 因为您当前的代码正在尝试生成。