F#模式匹配出现问题

3

我刚开始学习F#,所以这可能是一个简单的问题,但我不明白为什么我的代码中的模式匹配会起作用。

代码的快速解释:
函数calcNextMatch应该递归一个列表,如果两个元素相等,则它们应该相加。 最后,该函数应返回一个数字,该数字是所有具有与列表中下一个数字匹配的数字的总和。
例如 [1;3;2;2;5] 应返回 4

代码:

let rec printList l =
    match l with
    | head :: tail -> printf "%d " head; printList tail
    | [] -> printfn ""

let rec calcNextMatch list =
    printList list
    match list with
    | [] -> 0
    | _ :: tail ->            
        printList tail
        let h = Seq.head list
        let t = Seq.tryHead tail
        printfn "h: %i" h
        printfn "t: %O" t
        match t with
        | Some h -> 
            printfn "TAIL t: %i is equal to HEAD h: %i" t.Value h
            printfn "Calculation is: %i" (t.Value + h)
            (t.Value + h) + calcNextMatch tail
        | _ -> calcNextMatch tail

let sequence = [ 1;3;2;2;5 ]
let run = calcNextMatch sequence

当我运行这段代码时,问题在于模式匹配并没有按照我预期的方式工作。例如,从运行脚本中输出的打印结果。
h: 1
t: Some(3)
TAIL t: 3 is equal to HEAD h: 3

这意味着F#已经匹配成功。
match t with
        | Some h -> 

在 t = Some(3) 且 h = 1 的情况下,翻译成:
match 3 with
        | Some 1 -> 

我不理解这个问题。 在匹配前的打印输出中,t和h的值为31,但是在模式匹配中,h的值已经改变为3
这是怎么可能的?


有人正在声明一个新变量“h”,而不是匹配现有变量的值。 - Mankarse
1个回答

3

您只能对常量进行模式匹配,否则该值将被绑定为一个新的let绑定。

在这些情况下,通常要添加一个when条件:

    match t with
    | Some x when x = h -> 

还要注意,您可以进一步使用模式匹配来简化代码,例如在这里:
| _ :: tail ->            
    printList tail
    let h = Seq.head list

你可以写:

| h :: tail ->            
    printList tail

同时,以下是需要翻译的内容:

还有这部分:

| _ :: tail ->            
    printList tail
    let h = Seq.head list
    let t = Seq.tryHead tail
    printfn "h: %i" h
    printfn "t: %O" t
    match t with
    | Some h -> 
        printfn "TAIL t: %i is equal to HEAD h: %i" t.Value h
        printfn "Calculation is: %i" (t.Value + h)
        (t.Value + h) + calcNextMatch tail

成为:

| h :: tail ->            
    printList tail
    //printfn "h: %i" h
    //printfn "t: %O" t
    match tail with
    | t::_ when t = h -> 
        printfn "TAIL t: %i is equal to HEAD h: %i" t h
        printfn "Calculation is: %i" (t + h)
        (t + h) + calcNextMatch tail

你可以将所有匹配项统一在一个中,这样你的整个函数就变成了:

let rec calcNextMatch list =
    printList list
    match list with
    | [] -> 0
    | h::x::tail when x = h -> x + h + calcNextMatch (x::tail)
    | _::tail -> calcNextMatch tail

最后,当你完成调试后,可以删除打印语句。由于函数的最后一个参数是你要匹配的参数,所以可以使用关键字 function,同时使用 as 模式避免重构列表:

let rec calcNextMatch = function
    | [] -> 0
    | h::((x::_) as tail) when x = h -> x + h + calcNextMatch tail
    | _::tail -> calcNextMatch tail

1
感谢您的帮助和详细的解释。我现在明白了。 我之前还以为这是因为我不知道 F# 是如何处理的。 现在我的算法已经按照预期运行了 :-D - ThBlitz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接