首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >F#模式匹配与递归与循环&if.然后用于解析嵌套结构

F#模式匹配与递归与循环&if.然后用于解析嵌套结构
EN

Stack Overflow用户
提问于 2013-08-02 05:57:53
回答 2查看 813关注 0票数 4

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

代码示例通过嵌套的msg容器循环提取致命和非致命错误,然后返回BBResponseType * string类型的元组列表。

答复Enum:

代码语言:javascript
复制
type BBResponseType =
    | Status = 0
    | Data = 1
    | Error = 2
    | FatalError = -1 

我到F#的端口如下所示:

代码语言:javascript
复制
 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/后天。

如何使用模式匹配和递归更好地解析这些嵌套结构?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2013-08-02 06:30:26

很少有指点:

  1. 而不是返回一个元组列表,而是返回一个元组的seq --使用用于创建序列的seq { }计算表达式。
  2. 将if/ and部分解压缩为Message -> (BBResponseType * string)类型的函数,并在seq表达式中使用此函数
  3. 在这个新函数(将消息转换为元组)中,使用模式匹配来确定返回的类型(BBResponseType * string)。
票数 6
EN

Stack Overflow用户

发布于 2013-08-05 07:12:50

补充@Ankur的回答:

代码语言:javascript
复制
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来使用活动模式来进行简单的模式匹配。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/18009699

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档