括号匹配F#

时间:2014-03-31 17:59:41

标签: f#

所以我试图用f#来查找一个字符串是否有匹配的括号。 即:(abc)返回true,((hello)返回false,并且)(返回false,等等......

我(我想)正在做的是在列表中看到'('和pop,当它看到')'时使用堆栈进行推送。然后,如果字符串列表为空,则堆栈有一个项目,或者它没有。如果是,那么我说它是无效的,如果我遇到一个')'并且堆栈是空的,它也是无效的。否则它是一个有效的字符串。

// Break string
let break_string (str:string) =
    Seq.toList str

let isBalanced (str:string) =
    let lst = break_string str
    let stack = []
    let rec balance str_lst (stk:'a list)= 
        match str_lst with
        | [] -> 
            if stk.Length > 0 then
                false
            else 
                true
        | x::xs -> 
            if x = '(' then
                balance (xs x::stack)
            elif x = ')' then
                if stack.Length = 0 then
                    false
                else
                    stack = stack.tail
    balance (lst, stack)

我对f#很新,所以我认为这可能正在做我想要的,但是我收到错误消息: “这个表达式预计会有bool类型,但这里有类型'a list - > bool”

首先,这究竟意味着什么? 第二,既然它正在返回一个布尔,那为什么不起作用呢?

1 个答案:

答案 0 :(得分:2)

类型检查器认为您忘记了balance的第二个参数。当你这样写:

balance (xs x::stack)

这意味着"将balance应用于{将xs应用于x::stack)"。你可能意味着这个:

balance xs (x::stack)

您的最终elif似乎也错过了else分支,而stack = stack.tail行看起来像是您尝试分配给stack。你不能这样做,因为stack是一个不可变的变量。可能你想要balance xs (List.tail stack)。原则是,您可以使用新值调用函数,而不是分配给变量。


当然,你有正确的想法。通过将所有匹配(字母是什么?堆栈中的内容?)折叠成一个单个匹配语句,可以更加简洁。诀窍是将您想要查看的所有内容放入单个元组中:

let isBalanced str = 
    let rec loop xs stack = 
        match (xs, stack) with
        | '(' :: ys,  stack -> loop ys ('(' :: stack)
        | ')' :: ys, '(' :: stack -> loop ys stack
        | ')' :: _, _ -> false
        | _ :: ys, stack -> loop ys stack
        | [], [] -> true
        | [], _ -> false
    loop (Seq.toList str) []