F#惯用尝试直到

Rom*_*eEE 6 error-handling f#

我有一个函数,它接受输入并成功并返回一些输入或返回None.我将举例说明拨打的电话号码列表,直到有人回答其中一个号码,然后应跳过其余的号码.最后会记录成功的号码或错误消息.

我认为我的第一个解决方案太复杂了,并且在第一次尝试时也使用了故障状态的播种,这似乎是不优雅的:

type PhoneNumber = int

let tryCallNumber phoneNumber = 
    if phoneNumber % 2 = 0 then Some phoneNumber
    else None

let nextCall phoneNumberOption nextNumber = 
    match phoneNumberOption with
    | Some num -> phoneNumberOption
    | None     -> tryCallNumber nextNumber

let logCall phoneNumberOption = 
    match phoneNumberOption with
    | Some num -> printfn "%i" num
    | None     -> printfn "%s" "failed"


let phoneNumbers = [111; 222; 444; 555]

do List.fold (fun state num -> (nextCall state num)) None phoneNumbers
|> logCall
Run Code Online (Sandbox Code Playgroud)

我用一个更好的List函数,tryPick来加强它:

type PhoneNumber = int

let tryCallNumber phoneNumber = 
    if phoneNumber % 2 = 0 then Some phoneNumber
    else None

let logCall phoneNumberOption = 
    match phoneNumberOption with
    | Some num -> printfn "%i" num
    | None     -> printfn "%s" "failed"


let phoneNumbers = [111; 222; 444; 555]

do List.tryPick (fun num -> tryCallNumber num) phoneNumbers
|> logCall
Run Code Online (Sandbox Code Playgroud)

这看起来像是一个好方法吗?在阅读了关于monadic错误处理的内容之后,我想知道我是否应该以某种方式在这种精神上做更多的事情.

Car*_*Dev 3

惯用性很难衡量。我认为你的方法接近最惯用的方法。你已经得到了 Tomas 的签字...我会添加 的function快捷方式logCall,将do, 管道phoneNumbers放入,eta 减少tryCallNumberlambda:

let phoneNumbers = [111; 222; 444; 555]

let tryCallNumber phoneNumber = 
    if phoneNumber % 2 = 0 then Some phoneNumber
    else None

let logCall = function
| Some num -> printfn "%i" num
| None     -> printfn "failed"

phoneNumbers
|> List.tryPick tryCallNumber
|> logCall
Run Code Online (Sandbox Code Playgroud)

就我个人而言(不幸的是,这在 .NET / F# 标准库中并不惯用),我还将重命名tryCallNumber为 just callNumber,因为 IMOoption返回类型足够明显,而且我的代码往往是try-heavy 并且不依赖异常。类似于async默认库,其中...Async后缀被删除。