Recursion F#模式匹配&;递归与循环&;如果..那么';用于分析嵌套结构的

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#

我正在F#中使用第三方供应商的API。初始化时,API返回嵌套在msg容器中的C#对象。它由状态消息填充,可能包含错误消息。供应商提供了一个C#示例解析例程,我已将其移植到F#

代码示例在嵌套的msg容器中循环,提取致命和非致命错误,然后返回类型为
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:很高兴能帮上忙。仅供参考,你必须手动分配奖金。