Recursion F#模式匹配&;递归与循环&;如果..那么';用于分析嵌套结构的
我正在F#中使用第三方供应商的API。初始化时,API返回嵌套在msg容器中的C#对象。它由状态消息填充,可能包含错误消息。供应商提供了一个C#示例解析例程,我已将其移植到F# 代码示例在嵌套的msg容器中循环,提取致命和非致命错误,然后返回类型为Recursion F#模式匹配&;递归与循环&;如果..那么';用于分析嵌套结构的,recursion,f#,pattern-matching,nested-loops,c#-to-f#,Recursion,F#,Pattern Matching,Nested Loops,C# To F#,我正在F#中使用第三方供应商的API。初始化时,API返回嵌套在msg容器中的C#对象。它由状态消息填充,可能包含错误消息。供应商提供了一个C#示例解析例程,我已将其移植到F# 代码示例在嵌套的msg容器中循环,提取致命和非致命错误,然后返回类型为BBResponseType*string 响应枚举: type BBResponseType = | Status = 0 | Data = 1 | Error = 2 | FatalError = -1 我的F#
BBResponseType*string
响应枚举:
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
成员私有this.ProcessStatusMsg(eventObj:Blpapi.Event)=
让responseLst=List()
对于eventObj do中的msg
如果msg.MessageType.Equals(子标题),则
如果msg.GetElement(异常).NumValues>0,则//几个指针:
使用seq{}
计算表达式创建序列,而不是返回一个元组列表,而是返回一个元组序列
将if/else部分提取为类型为Message->(BBResponseType*string)
的函数,并在seq
表达式中使用此函数
在这个新函数中(将消息转换为元组),使用模式匹配来确定返回哪种类型的(BBResponseType*字符串)李>
补充@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
| _ -> ()
}
成员私有this.ProcessStatusMsg(eventObj:Blpapi.Event)=
// 0. 定义一个参数化的活动模式,将if/else转换为模式匹配
设(|元素| |)e msg=
如果msg.HasElement(e),则
一些
配味精
// 4. 使用活动模式直接在消息上进行模式匹配
|当e.NumValues>0->
对于0..e.NumValues-1do中的i
let error=e.GetValueAsElement(i)
let field=error.GetElementAsString(FieldID)
let reason=error.GetElement(原因)
let message=sprintf“订阅已启动,但有错误(字段:%s\n原因:%s)”字段(原因.GetElementAsString(说明))
产量(BBResponseType.Error,message)
| _ ->
let message=sprintf“订阅已启动”
产量(BBResponseType.Status,message)
|子故障->
配味精
|元素原因->
让desc=reason.GetElementAsString(描述)
let message=sprintf“实时订阅失败:%s”desc
产量(BBResponseType.FatalError,消息)
| _ ->
let message=sprintf“订阅失败:(原因未知)”
产量(BBResponseType.FatalError,消息)
//可能还有更多的案例,在这里处理
| _ -> ()
}
评论中的第1、2和3点来自另一个答案。我添加了第0点和第4点,以便使用活动模式进行简单的模式匹配。我喜欢这个答案,并对其进行了投票,但作为一个完全的F#初学者,一点代码将非常有用helpul@ChrisTarn:我同意,不幸的是我没有F#环境,tryfsharp.org在Linux上不工作:(添加0点和4点(参数化活动模式)非常好。非常突出了活动模式在模式匹配方面的强大作用!好吧,+50 rep奖励非常值得!通过查看此代码并将其与原始代码进行比较,我学到了很多东西。将整个方法按顺序包装似乎是一项非常好的技术。但我还没有在我的任何书籍中看到它。谢谢Ankur和P广告!!@ChrisTarn:很高兴能帮上忙。仅供参考,你必须手动分配奖金。