元组列表的匹配模式

时间:2019-05-27 03:52:50

标签: f# pattern-matching

我正在尝试编写一个包含元组和表达式列表的fcn(我正在研究后缀表达式eval)。此函数应遍历表达式并在元组中找到相同的字母。如果匹配,则返回与元组中的字母相对应的int值。当我运行下面的代码时,我的程序已编译并运行,但随后在执行期间挂起。我做错了什么?

    let rec getVar ls exp = 

        match ls with
       |head::tl when (fst head) = exp -> printfn "%d" (snd head)
       | _  -> getVar ls exp



    let ls = [("a",5);("b",2);("c",3)]

    let exp = "ab+"
    getVar ls exp

3 个答案:

答案 0 :(得分:3)

您的match表达式具有最后一个包罗万象的子句(_子句),该子句仅使用相同的参数再次调用getVar。如果when (fst head) = exp条件失败,则代码进入catch-all子句,因此getVar用相同的参数再次调用,因此第一个条件将失败,因此代码陷入catch- all子句,因此getVar再次被调用...这是一个无限循环。

您可能想做的是,如果您的getVar条件失败,则在列表的 tail 上再次致电when

match ls with
|head::tail when (fst head) = exp -> printfn "%d" (snd head)
|head::tail -> getVar tail exp

您还需要考虑如果列表为空(该条件需要与[]匹配的匹配条件)该怎么办。我将由您自己决定,因为您可以有很多事情想要做一个空列表,并且不清楚要哪个。

答案 1 :(得分:2)

您的比赛必须处理三种情况。

  1. 空列表->返回一些默认值(或没有副作用的单位)
  2. 找到匹配项->返回一个值或触发一些副作用。
  3. 尚未找到匹配项->继续在列表末尾搜索。

第一次尝试时,您不小心一直在整个列表中搜索而不是仅在尾部搜索,从而导致无休止的递归循环。 在第二次尝试中,您在空情况下创建了一个无限循环。 以下是如何编写递归函数的一个示例。

 let rec getVar ls exp =
     match ls with
     |[] -> None
     |head::tail when (fst head) = exp -> Some <| sprintf "%d" (snd head)
     |head::tail  -> getVar tail exp

 let ls = [("a",5);("b",2);("c",3)]

 let result1 = getVar ls "ab+"   // result = None
 let result2 = getVar ls "b"     // result = Some "2"

答案 2 :(得分:0)

您的getVar函数的签名错误。最后一个参数应该是表达式的字母,而不是整个表达式。调用getVar函数的代码将遍历表达式,对于每个字符,检查它是否是字母,如果是,则调用getVar,否则执行其他操作。

在其他答案中清楚地说明了代码被挂起的原因,因此在此不再赘述。但是,作为一种好的做法,除非完全控制情况,否则请勿使用| _ -> ...。通常,我们应该显式地编写所有匹配条件,以便如果我们错过了某些内容,编译器将向我们发出警告。之后,在了解所有条件后,如果确实表示“其余条件 s ”,则可以使用| _ -> ...

您的getVar函数可以重写为:

let rec getVar ls letter =
    match ls with
    | [] -> ()
    | head :: tail when fst head = letter -> printfn "%d" (snd head)
    | _ :: tail -> getVar tail letter

我建议您学习F#核心库的常见内置函数。因此,您可以在问题中使用List.tryFind函数:

let getVar ls letter =
    ls |> List.tryFind (fun (key, value) ->
                 if key = letter then
                     printfn "%d" value
                     true
                 else false)

您可以使用越多的内置功能,您遇到的错误越少。