我有一个函数,它接受输入并成功并返回一些输入或返回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错误处理的内容之后,我想知道我是否应该以某种方式在这种精神上做更多的事情.
惯用性很难衡量。我认为你的方法接近最惯用的方法。你已经得到了 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后缀被删除。