F# 匹配多个ParserResult并提取值

F# 匹配多个ParserResult并提取值,f#,fparsec,F#,Fparsec,这是一个关于使用FParsec的ParserResult的问题 是否有一个更干净的match\u result实现来提取ParserResult中包含的XKEYVALUE或XATTRIBUTES,而无需两个嵌套匹配 以下代码用作F#控制台应用程序 // Learn more about F# at http://fsharp.org open System open FParsec // Types type XKEYVALUE = string * string type XATTRIBU

这是一个关于使用FParsec的ParserResult的问题

是否有一个更干净的
match\u result
实现来提取
ParserResult
中包含的
XKEYVALUE
XATTRIBUTES
,而无需两个嵌套匹配

以下代码用作F#控制台应用程序

// Learn more about F# at http://fsharp.org

open System
open FParsec

// Types
type XKEYVALUE = string * string
type XATTRIBUTES = Map< string, string>

type PARSER_RESULT_XML = 
    | PR_XKEYVALUE of ParserResult<XKEYVALUE, unit>
    | PR_XATTRIBUTES of ParserResult<XATTRIBUTES, unit>

// Parser Trace
let (<!>) (p: Parser<_,_>) label : Parser<_,_> =
    fun stream ->
        printfn "%A: Entering %s" stream.Position label
        let reply = p stream
        do
            match (reply.Status) with
                | Ok  -> printfn "%A: Leaving %s (%A) - %A" stream.Position label reply.Status reply.Result
                | Error -> printfn "%A: Leaving %s (%A) - %A" stream.Position label reply.Status reply.Error
                | FatalError -> printfn "%A: Leaving %s with FatalError (%A)" stream.Position label reply.Status
                | _ -> printfn "%A: Leaving %s with unknown status" stream.Position label
        reply

// Parsers
let ws = spaces
let str = pstring
let xKey : Parser<string,unit> = (ws >>. regex "[a-zA-Z][a-zA-Z0-9:]*") <!> "xKey"
let xStringLiteral = regex "[^\"]+" <!> "xStringLiteral"
let xKeyValue : Parser<XKEYVALUE, unit> = 
    ws >>. xKey .>>. (ws >>. str "=" >>. ws >>. str "\"" >>. xStringLiteral .>> str "\"" .>> ws) |>> XKEYVALUE <!> "xKeyValue"
let xAttributes : Parser<XATTRIBUTES, unit> = sepEndBy xKeyValue ws |>> XATTRIBUTES <!> "xAttributes"

// Test Data
let xKeyValue_text = """    key =  "value"    aa"""
let xAttributes_text = "key1=\"value1\" key2=\"value2\""

let match_result ( result : PARSER_RESULT_XML) : string =
    match result with 
        | PR_XKEYVALUE(a) ->    match a with  
                                    | Success( ((key : string), (value : string)), x2, x3) -> sprintf "%s=\"%s\"" key value
                                    | Failure( _, _, _) -> sprintf "FAILURE"
        | PR_XATTRIBUTES( a) -> match a with
                                    | Success( (x1 : Map<string, string>), x2, x3) -> sprintf "x1=%A, x2=%A, x3=%A" x1 x2 x3
                                    | Failure( _, _, _) -> sprintf "FAILURE"

[<EntryPoint>]
let main argv =
    run xKeyValue xKeyValue_text |> PR_XKEYVALUE |> match_result |> printfn "%A"
    run xAttributes xAttributes_text |> PR_XATTRIBUTES |> match_result |> printfn "%A"
    0 // return an integer exit code
//了解更多关于F#at的信息http://fsharp.org
开放系统
开放式FParsec
//类型
类型XKEYVALUE=string*string
type XATTRIBUTES=Map
类型分析器\u结果\u XML=
|ParserResult的prxKeyValue
|ParserResult的Prxatu贡献
//分析器跟踪
let()(p:Parser)label:Parser=
趣味流->
printfn“%A:正在输入%s”流。位置标签
让reply=p流
做
将(回复.状态)与匹配
|确定->打印fn“%A:离开%s(%A)-%A”流。位置标签应答。状态应答。结果
|错误->打印fn“%A:离开%s(%A)-%A”流。位置标签应答。状态应答。错误
|FatalError->printfn“%A:将%s保留为FatalError(%A)”流。位置标签回复。状态
|->printfn“%A:使%s处于未知状态”流。位置标签
回复
//解析器
设ws=spaces
设str=pstring
设xKey:Parser=(ws>.regex“[a-zA-Z][a-zA-Z0-9:][*”)xKey
设xStringLiteral=regex“[^\”]+“xStringLiteral”
让xKeyValue:解析器=
ws>>.xKey.>>.(ws>.str“=”>>.ws>>.str“\”>.xStringLiteral.>>str“\”。>>ws)|>>XKEYVALUE“XKEYVALUE”
让xAttributes:Parser=sepEndBy xKeyValue ws |>>xAttributes“xAttributes”
//测试数据
让xKeyValue_text=“”key=“value”aa”“”
让xAttributes\u text=“key1=”value1\”key2=”value2“
让match_result(结果:解析器_result_XML):字符串=
匹配结果
|prxkeyValue(a)->将a与
|Success((key:string),(value:string)),x2,x3)->sprintf“%s=\%s\”键值
|失败(u,u,u)->sprintf“失败”
|PR_XATTRIBUTES(a)->将a与
|成功((x1:Map),x2,x3)->sprintf“x1=%A,x2=%A,x3=%A”x1 x2 x3
|失败(u,u,u)->sprintf“失败”
[]
让主argv=
运行xKeyValue xKeyValue_text |>PR_xKeyValue |>match_result |>printfn“%A”
运行xAttributes xAttributes|u text |>PR| xAttributes |>match|u result |>printfn“%A”
0//返回整数退出代码
但是
match\u result
的嵌套匹配看起来很笨拙

一个失败的实验是使用一个将
PARSER\u RESULT\u XML&Success(…)
的匹配放在同一个匹配表达式中,但我无法使两个匹配表达式的类型一致


您将如何修改
match\u result
以更好或更清晰地执行此操作?

这对我来说是主观的,但如果您去掉不必要的类型注释并更改match\u result上的缩进,我想它会稍微提高可读性

let match_result result =
    match result with 
    | PR_XKEYVALUE a ->
        match a with  
        | Success ((key, value), _, _) -> sprintf "%s=\"%s\"" key value
        | Failure _ -> sprintf "FAILURE"
    | PR_XATTRIBUTES a -> 
        match a with
        | Success (x1, x2, x3) -> sprintf "x1=%A, x2=%A, x3=%A" x1 x2 x3
        | Failure _ -> sprintf "FAILURE"
如果您仍然对此不满意,您可能会发现在此处使用活动模式很有帮助:

let (|KeyValue|Attributes|Failed|) result =
    match result with
    | PR_XKEYVALUE a ->
        match a with  
        | Success ((key, value), _, _) -> KeyValue (key, value)
        | Failure _ -> Failed
    | PR_XATTRIBUTES a -> 
        match a with
        | Success (x1, x2, x3) -> Attributes (x1, x2, x3)
        | Failure _ -> Failed

let match_result result =
    match result with 
    | KeyValue (key, value) -> sprintf "%s=\"%s\"" key value
    | Attributes (x1, x2, x3) -> sprintf "x1=%A, x2=%A, x3=%A" x1 x2 x3
    | Failed -> sprintf "FAILURE"

后者更好,因为您可以将结果以域术语进行解释,以及如何处理(在本例中为打印消息)。

您可以根据需要将模式匹配到结构中的深度:

let match_result result =
    match result with
    | PR_XKEYVALUE (Success ((key, value), _, _)) -> sprintf "%s=\"%s\"" key value 
    | PR_XATTRIBUTES (Success (x1, x2, x3)) -> sprintf "x1=%A, x2=%A, x3=%A" x1 x2 x3
    | _ -> "FAILURE"

该代码未编译。该代码编译并运行,在Visual Studio Pro 16.8.2版中带有默认设置的警告。VS Pro编译器抛出三个警告:第40行和第43行出现2 x“此表达式上的模式匹配不完整…”,以及1 x“永远不会达到此规则”。“第46行。很明显,如果出现这些警告,编译器被配置为不编译。我已删除警告并替换代码。谢谢你的评论,这样我就可以让其他人更容易理解了。这是一个很好的观点!最初,我尝试了这个方法,但当我学习F#时,我可能会被另一个错误弄糊涂,我认为这是因为我尝试了深层模式匹配。谢谢你让我知道这是可行的。杰出的谢谢你,吉姆。我喜欢使用活动模式来避免使用类型构造函数。