我在F#中使用第三方供应商的API。初始化时,API返回一个嵌套的msg容器的C#对象。它由状态消息填充,并可能包含错误消息。供应商提供了一个C#示例解析例程,我已经移植了F#。
代码示例通过嵌套的msg容器循环提取致命和非致命错误,然后返回BBResponseType * string类型的元组列表。
答复Enum:
type BBResponseType =
| Status = 0
| Data = 1
| Error = 2
| FatalError = -1 我到F#的端口如下所示:
member private this.ProcessStatusMsg(eventObj: Blpapi.Event) =
let responseLst = List<(BBResponseType * string)>()
for msg in eventObj do
if msg.MessageType.Equals(SUBSTARTED) then
if msg.GetElement(EXCEPTIONS).NumValues > 0 then // <- check for errors/exceptions
let e = msg.GetElement(EXCEPTIONS)
for i in 0..e.NumValues-1 do
let error = e.GetValueAsElement(i)
let field = error.GetElementAsString(FieldID)
let reason = error.GetElement(REASON)
let message = sprintf "Subscription Started w/errors( Field: %s \n Reason: %s)" field (reason.GetElementAsString(DESCRIPTION))
responseLst.Add(BBResponseType.Error, message)
else
let message = sprintf "Subscription Started"
responseLst.Add(BBResponseType.Status, message)
if msg.MessageType.Equals(SUBSCFAILURE) then // <- check for subscriptions failure
if msg.HasElement(REASON) then
let reason = msg.GetElement(REASON)
let desc = reason.GetElementAsString(DESCRIPTION)
let message = sprintf "Real-time Subscription Failure: %s" desc
responseLst.Add(BBResponseType.FatalError, message)
else
let message = sprintf "Subscription Failure: (reason unknown) "
responseLst.Add(BBResponseType.FatalError, message)
responseLst在我完成它之后,我看了看它,然后想:“哇,这是尽可能多的非功能性的,而且仍然是在F#中的代码。”
这看起来确实比C#版本更清晰、更简洁,但我认为必须有一个更好的方法来完成这一切,而不需要使用那么多循环和if/后天。
如何使用模式匹配和递归更好地解析这些嵌套结构?
发布于 2013-08-02 06:30:26
很少有指点:
seq { }计算表达式。Message -> (BBResponseType * string)类型的函数,并在seq表达式中使用此函数发布于 2013-08-05 07:12:50
补充@Ankur的回答:
member private this.ProcessStatusMsg(eventObj: Blpapi.Event) =
// 0. Define a parameterized active pattern to turn if/else into pattern matching
let (|Element|_|) e msg =
if msg.HasElement(e) then
Some <| msg.GetElement(e)
else None
// 1. Wrapping the whole method body in a sequence expression
seq {
for msg in eventObj do
// 2. Extracting if/else part and using it in sequence expression
match msg.MessageType with
// 3. Using pattern matching to figure out what kind (BBResponseType * string) to return
| SUBSTARTED ->
match msg with
// 4. Use active pattern to pattern match on message directly
| Element EXCEPTIONS e when e.NumValues > 0 ->
for i in 0..e.NumValues-1 do
let error = e.GetValueAsElement(i)
let field = error.GetElementAsString(FieldID)
let reason = error.GetElement(REASON)
let message = sprintf "Subscription Started w/errors( Field: %s \n Reason: %s)" field (reason.GetElementAsString(DESCRIPTION))
yield (BBResponseType.Error, message)
| _ ->
let message = sprintf "Subscription Started"
yield (BBResponseType.Status, message)
| SUBSCFAILURE ->
match msg with
| Element REASON reason ->
let desc = reason.GetElementAsString(DESCRIPTION)
let message = sprintf "Real-time Subscription Failure: %s" desc
yield (BBResponseType.FatalError, message)
| _ ->
let message = sprintf "Subscription Failure: (reason unknown) "
yield (BBResponseType.FatalError, message)
// There are probably more cases, processing them here
| _ -> ()
}评论中的第1、2和3点来自另一个答案。我添加了点0和4来使用活动模式来进行简单的模式匹配。
https://stackoverflow.com/questions/18009699
复制相似问题