Scala编程if';s

Scala编程if';s,scala,functional-programming,Scala,Functional Programming,我从scala开始,尝试将函数方法应用于它,但我提出了一系列嵌套的if\else结构,很难阅读,我想知道有没有更好的方法来编程这些东西 例如,我编写了一个脚本,执行括号平衡: def balance(chars: List[Char]): Boolean = { def checkParentesys(chars: List[Char], parentesis: List[Char]): Boolean = if (chars.isEmpty && paren

我从scala开始,尝试将函数方法应用于它,但我提出了一系列嵌套的if\else结构,很难阅读,我想知道有没有更好的方法来编程这些东西

例如,我编写了一个脚本,执行括号平衡:

def balance(chars: List[Char]): Boolean = {
    def checkParentesys(chars: List[Char], parentesis: List[Char]): Boolean =
      if (chars.isEmpty && parentesis.isEmpty)
        true
      else
        if (chars.head == '(')
            checkParentesys(chars.tail, '(' :: parentesis)
        else
            if (parentesis.isEmpty)
                false
            else
                checkParentesys(chars.tail, parentesis.tail)

    checkParentesys(chars.filter(s => s == '(' || s == ')'), List())
  }
我怎样才能写得更实用、更像scala?

嗯:

  • 您可以从使用
    else if
    条件来编写它开始
  • 继续用
    tailrec
    注释它,因为它是尾部递归的
  • 过滤条件可以更简单地写成
    Set('(','))
    ,这是从
    Char
    Boolean
    的函数
  • 我认为您缺少了
    chars
    为空而
    括号
    为空的条件
  • 所以它看起来像:

    def balance(chars: List[Char]): Boolean = {
      @tailrec
      def checkParentesys(chars: List[Char], parentesis: List[Char]): Boolean =
        if (chars.isEmpty && parentesis.isEmpty)
          true
        else if (chars.head == '(')
          checkParentesys(chars.tail, '(' :: parentesis)
        else if (chars.isEmpty || parentesis.isEmpty)
          false
        else
          checkParentesys(chars.tail, parentesis.tail)
    
      checkParentesys(chars.filter(Set('(', ')')), List())
    }
    
    您还可以将整个过程转换为模式匹配:

    def balance(chars: List[Char]): Boolean = {
      @tailrec
      def checkParentesys(chars: List[Char], parentesis: List[Char]): Boolean =
        (chars, parentesis) match {
          case (Nil, Nil) => true
          case ('(' :: charsTail, _) => checkParentesys(charsTail, '(' :: parentesis)
          case (Nil, _) => false
          case (_, Nil) => false
          case (')' :: charsTail, '(' :: parentesisTail) => checkParentesys(charsTail, parentesisTail)
        }
      checkParentesys(chars.filter(Set('(', ')')), List())
    }
    

    我认为没有任何理由在遍历列表之前过滤它。在遍历列表时,可以忽略非括号。我认为也没有必要建立第二份清单。您真正想知道的是,开括号的计数从来都不是负数:

    def balance(chars: List[Char]): Boolean = {
      @tailrec
      def _balance(chars: List[Char], count: Int) : Boolean = 
        chars match {
            case Nil => count == 0   // end of the string did we close every open?
            case '(' :: xs => _balance(xs, count+1)  
            case ')' :: xs => (count > 0) && _balance(xs, count-1) 
            case _ => _balance(chars.tail, count) // uninteresting char, skip it
        }
    
      _balance(chars, 0)
    }
    

    把它写成一个折页可能更好:

    def balance(chars: List[Char]): Boolean = chars.foldLeft(0){
      case (0, ')') => return false
      case (x, ')') => x - 1
      case (x, '(') => x + 1
      case (x, _  ) => x
    } == 0
    

    正如您所看到的,我没有使用count,因为count在()上不起作用(

    感谢Set和tailrec。因此,没有办法重写其他逻辑以提高可读性。否则if没有多大帮助,因为在我看来,它会混淆wich是否属于并破坏逻辑。我想我可以以某种方式将多个检查组合到一个表达式中?是的,这就是我要寻找的,没有看到你的第二部分comment@Pilgrim,我认为任何语言的大多数程序员都会说,
    else if
    更具可读性,因为它为读者提供了一个条件列表。此外,它肯定不会破坏逻辑;逻辑是相同的。好吧,也许你是对的,无论如何,我认为在模式匹配中重写,它看起来更具功能性,而且(对我来说,这不是不寻常的语法)它给出了更清晰的逻辑表示谢谢,这听起来很合理,而不是使用
    循环
    或其他什么。第一个是不符合非正式的风格指南。标准的方法是称之为
    平衡0
    我认为
    如果(count<1)错误的其他&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&,看起来函数式编程比命令式编程有更多的选择。我认为使用“return”是一种糟糕的风格?不总是这样。初学者,尤其是来自Java的初学者,倾向于过度使用
    return
    。但是,这里需要
    return
    ,以便尽早退出。当然,还有其他方法可以解决这个问题(请参阅其他答案),但在我看来,这个方法相当优雅,即使使用
    return
    @Ilan通常也是如此,但标准库没有一个折叠变体,当累加器达到某个条件时,它会停止折叠。这种方法自己编写非常简单,但我认为
    return
    在这里更简单,也更容易理解。不要害羞,只要说这个问题来自scala的coursera courseIt就行了,因为你刚刚发布了答案,违反了coursera的荣誉准则(见规则3)弗兰克:遵守荣誉守则很好,但就像法律合同一样,需要运用常识。意图区分不同的情况。事实上,人们期望它在解决问题后能找到更好的方法,不是吗?你有没有告诉一个想要知识的人,“因为荣誉代码不能说”?好吧,直到第一条评论只是一段代码,没有对cource的依恋。我认为网络教育和传统教育的主要目的是让你感兴趣的东西变得更好,而不是在没有知识的情况下完成一张纸。但不管怎样,谢谢,当我发布这个问题时,我没有考虑荣誉代码,所以下次我会很小心的,请不要因为违反Coursera的行为准则而打旗子。这不由我们来执行。如果这是一个好的技术问题,我们在这里没有问题。
    var parens :List[Char] =  Nil
    def matcher(chrs: List[Char]): Boolean = {
         if (chrs.isEmpty) {
            return parens.isEmpty
         }
         else {
             chrs.head match {
               case '(' =>  parens = '(' :: parens ;matcher(chrs.tail)
               case ')' =>  if (parens.isEmpty) return false 
                                else if (parens.apply(0) ==  '(') parens = parens.drop(1) 
                                else return false;  
                                matcher(chrs.tail);
               case _ => matcher(chrs.tail)
             }
         }
    }