过滤并将`list option`转换为`list`?

ca9*_*3d9 3 f#

我有以下的代码,将返回seqDownloadLink这些网址,可以进行解析.

type DownloadLink = { Url: string; Period: DateTime }   

nodes |> Seq.map (fun n ->
    let url = n.Attributes.["href"].Value
    match url with
    | Helper.ParseRegex "[a-zA-Z](?<period>\d{4})\.txt" [period] ->
        { Url = url; Period = period }
    | _ ->
        printfn "Cannot parse %s" url // Error
        )
Run Code Online (Sandbox Code Playgroud)

但是,我收到了以下错误printfn.什么是正确的实施方式?我应该list option先制作它然后过滤掉这些None物品吗?

Error   1   Type mismatch. Expecting a
    string -> DownloadLink    
but given a
    string -> unit    
The type 'DownloadLink' does not match the type 'unit'  

Joh*_*mer 5

基本问题是,如果你有类似的东西

match x with
|true -> A
|false -> B
Run Code Online (Sandbox Code Playgroud)

的类型AB必须相同.

实际上有一个内置函数,它结合了Some你使用的地图和过滤器- Seq.choose就像这样使用

nodes |> Seq.choose (fun n ->
    let url = n.Attributes.["href"].Value
    match url with
    | Helper.ParseRegex "[a-zA-Z](?<period>\d{4})\.txt" [period] ->
        Some ({ Url = url; Period = period })
    | _ ->
        printfn "Cannot parse %s" url // Error
        None
        )
Run Code Online (Sandbox Code Playgroud)


Tom*_*cek 5

除了 之外Seq.choose,您还可以使用序列表达式很好地解决问题 - 您可以使用序列表达式yield在一个分支中返回结果,但不必在另一分支中生成值:

seq { for n in nodes do
        let url = n.Attributes.["href"].Value
        match url with
        | Helper.ParseRegex "[a-zA-Z](?<period>\d{4})\.txt" [period] ->
            yield { Url = url; Period = period }
        | _ ->
            printfn "Cannot parse %s" url }
Run Code Online (Sandbox Code Playgroud)

除此之外,我不建议将副作用(打印)作为处理代码的一部分。如果您想报告错误,最好返回一个选项(或定义一个类型,即SuccessError of string),以便将错误报告与处理分开。