【问题标题】:Parsing expression tree into nested lists将表达式树解析为嵌套列表
【发布时间】:2016-05-21 05:24:58
【问题描述】:

我对 F# 比较陌生,并且在解析包含嵌套列表的表达式树时确实遇到了困难。从网上的点点滴滴,我拼凑了以下内容。

我的标准类型已定义:

type Return = 
    | Real of float
    | Func of string * Return list

我对外部应用程序进行了函数调用,它返回如下内容:

val out : Return =
    Func
        ("List",
             [Func ("List",[Real 1.0; Real 2.0; Real 3.0]);
              Func ("List",[Real 1.0; Real 2.0; Real 3.0]);
              Func ("List",[Real 1.0; Real 2.0; Real 3.0])])

我需要解析成

[ [1.0; 2.0; 3.0] ; [1.0; 2.0; 3.0] ; [1.0; 2.0; 3.0] ]

我最初的幼稚想法是

let rec parse data =
    match data with
    | Real(y) -> y
    | Func("List", x) -> x |> List.map parse 
    | _ -> failwithf "Unrecognised"

但它抱怨类型差异,我现在明白了。

我的第二个想法是可能使用一些递归 List.fold (因为我可以折叠 Reals 列表并获取内部列表,但无法弄清楚如何在没有编译器抱怨的情况下将其概括为递归函数类型)。超越我目前的智力火力。

我的第三个想法是,也许我从外部应用程序获得的回报让这变得太难了,因为元组 fst 中没有关于元组 snd 中的内容的指示,除了它是一个“列表什么”?

有这个:Convert tree to list,但它和我正在尝试的解决方案一样神秘。

任何关于我追求的途径的指针都将非常感激。

【问题讨论】:

    标签: f# expression-trees


    【解决方案1】:

    您希望parse 函数返回的对象类型是什么?

    如果您想要的输出是[ [1.0; 2.0; 3.0] ; [1.0; 2.0; 3.0] ; [1.0; 2.0; 3.0] ],那么您想要返回的似乎既不是float list 也不是float list list,而是float任意嵌套列表

    但这并不作为标准类型存在,您需要自己将其定义为递归可区分联合(我们将使其成为通用的,以实现良好实践):

    type NestedList<'a> = 
        | Single of 'a
        | Collection of NestedList<'a> list
    

    好吧,看看那个!它只是您原来的Return 类型的一个薄层。这是因为原始类型几乎已经是标准的嵌套列表实现,除了 "List" 标签。

    parse 函数几乎没有真正的工作要做:

    let rec parse = function
        | Real y ->  Single y
        | Func ("List", returns) -> Collection (returns |> List.map parse)
        | Func (l, _) -> failwithf "Unrecognised label %s" l
    

    【讨论】:

    • 非常感谢。我显然仍然在以一种过于松散的方式思考类型,但这给了我所需的结构。
    【解决方案2】:

    有时最好对您正在实现的功能进行注释。然后它会明确说明您要做什么:

    type Return = 
        | Real of float
        | Func of string * Return list
    
    let rec parse (data : Return) : float list =
        match data with
        | Real y ->  [ y ]
        | Func (_, returns) -> returns |> List.collect parse
        | _ -> failwithf "Unrecognised"
    

    您的 x |&gt; List.map parse 具有 float list list 类型,但在其他分支上,您的表达式具有 float 类型。你试图返回float list,我说的对吗?

    【讨论】:

    • 谢谢,并注意到类型注释。然而,在上面的示例中,我需要返回一个浮点列表列表,因为表达式树嵌套的深度为 2。所以我需要 [[ 1.0; 2.0; 3.0 ]; [1.0; 2.0; 3.0 ]; [1.0; 2.0; 3.0] ] 而不是您的代码给出的 [1.0; 2.0; 3.0; 1.0; 2.0; 3.0; 1.0; 2.0; 3.0]。当然,如果我得到的返回嵌套深度为三,我需要返回浮动列表列表列表。
    • 在这种情况下,我不会尝试编写递归函数,因为您只允许将特定形状的 Return 类型传递给您的函数,而对于其他情况,您只是抛出异常。如果您只想支持 2 深度表达式树,只需显式地对它们进行模式匹配。
    • 谢谢巴泰克。我显然对递归函数的含义还不够了解,还不知道它们何时(不)有用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-19
    • 1970-01-01
    • 1970-01-01
    • 2017-11-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多