F#惯用尝试直到

时间:2016-08-04 23:36:28

标签: 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

我用更好的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

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

1 个答案:

答案 0 :(得分:3)

习得性很难衡量。我认为你的方法是最接近惯用的。你有Tomas'签名...我会为function添加logCall快捷方式,删除do,管道phoneNumbers,eta-reduce tryCallNumber lambda:

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

个人(不幸的是,在.NET / F#standard-lib中非惯用),我还将tryCallNumber重命名为callNumber,作为IMO {{ 1}}返回类型足够明显,我的代码往往是option - 很重,不依赖于异常。与try类似 - 删除async后缀的默认库。