Значение по умолчанию для параметра метода не учитывается - PullRequest
0 голосов
/ 22 апреля 2019

Я предоставил значения по умолчанию для параметра «currentStack» в объекте «Пустой», а также в классе «Верх», но если я опускаю параметр при вызове метода push, я получаю следующее сообщение

"error: not enough arguments for method push: (newTop
: A, currentStack: Main.Stack[A])Main.Stack[A].
Unspecified value parameter currentStack.
                    currentBracket == '{') isBracketingValid(rest, bracketStack.push(currentBracket))".

Я попытался создать пустой стек так же, как уже заполненный, и вызвал метод push для них, который работал для добавления одного элемента.Как только я попытался добавить еще один элемент с помощью следующего push-вызова, я получил сообщение об ошибке выше.

lazy val s1 = Empty

println(s1.push(1)) // <- works

//println(s1.push(1).push(2)) <- doesn't work

lazy val s2 = Top(3, Top(4, Empty))

println(s2.push(1)) // <- works

//println(s2.push(1).push(2)) <- doesn't work

здесь определение стека:

sealed trait Stack[+A] {
    def push[A] (newTop: A, currentStack: Stack[A]): Stack[A] = ???

    def pop: (Option[A], Stack[A]) = ???
}

case object Empty extends Stack[Nothing] {
    override def push[A] (newTop: A, currentStack: Stack[A] = Empty): Stack[A] = Top(newTop, currentStack)

    override def pop: (Option[Nothing], Stack[Nothing]) = (None, Empty)
}

case class Top[A](val top: A, val rest: Stack[A]) extends Stack[A] {
    override def push[A] (newTop: A, currentStack: Stack[A] = Top(top, rest)): Stack[A] = Top(newTop, currentStack)

    override def pop: (Option[A], Stack[A]) = (Some(top), rest)
}

def isBracketingValid(bracketString: String): Boolean = {
    def isBracketingValid(bracketList: List[Char], bracketStack: Stack[Char]): Boolean = bracketList match {
        case Nil => bracketStack == Empty
        case currentBracket :: rest => {
            lazy val previousBracket = bracketStack.pop._1.getOrElse('$')

            lazy val isRestValid = isBracketingValid(rest, bracketStack.pop._2)

            if (currentBracket == '(' ||
                currentBracket == '[' ||
                currentBracket == '{') isBracketingValid(rest, bracketStack.push(currentBracket))
            else if (currentBracket == ')') previousBracket == '(' && isRestValid
            else if (currentBracket == ']') previousBracket == '[' && isRestValid
            else if (currentBracket == '}') previousBracket == '{' && isRestValid
            else false
        }
    }
    isBracketingValid(bracketString.toList, Empty)
}

EDIT

переписать определение стека после намека Луиса на использование «this», так что нет, это не вызывает упомянутой проблемы, так как стек не передается, но я все еще заинтересован в понимании причины.

sealed trait Stack[+A] {
    def push[A] (newTop: A): Top[A] = ???

    def pop: (Option[A], Stack[A]) = ???
}

case object Empty extends Stack[Nothing] {
    override def push[A] (newTop: A): Top[A] = Top(newTop, this)

    override def pop: (Option[Nothing], Stack[Nothing]) = (None, Empty)
}

case class Top[A](val top: A, val rest: Stack[A]) extends Stack[A] {
    override def push[A] (newTop: A): Top[A] = Top(newTop, this.asInstanceOf[Stack[A]])

    override def pop: (Option[A], Stack[A]) = (Some(top), rest)
}

EDIT 2

реорганизовал определение стека благодаря пониманию Луиса, что он не использует asInstanceof, но вместо этого достигает цели с более низкой границей типа.А также проверил, почему предложения в общем случае должны быть окончательными.

sealed trait Stack[+A] {
    def push[B >: A] (newTop: B): Top[B] = ???

    def pop: (Option[A], Stack[A]) = ???
}

case object Empty extends Stack[Nothing] {
    override def push[A] (newTop: A): Top[A] = Top(newTop, this)

    override def pop: (Option[Nothing], Stack[Nothing]) = (None, Empty)
}

final case class Top[+A] (val top: A, val rest: Stack[A]) extends Stack[A] {
    override def push[B >: A] (newTop: B): Top[B] = Top(newTop, this)

    override def pop: (Option[A], Stack[A]) = (Some(top), rest)
}

1 Ответ

1 голос
/ 22 апреля 2019

Итак, подведем итоги.Проблема заключалась в том, что даже если в двух ваших подклассах вы переопределили метод push, чтобы он имел значение по умолчанию.
Сигнатура метода на признаке не имела такого значения по умолчанию.И, поскольку это был тот, который вы вызывали, компилятор выдал правильную ошибку.
Вы могли бы выполнить сопоставление с образцом, чтобы узнать, какой конкретный случай из Stack у вас был, и таким образомкомпилятор нашел бы подпись со значением по умолчанию.Однако, поскольку по умолчанию всегда был Stack с той же формой, что и , это , и поскольку вам действительно нужно было просто использовать this (так как в качестве неизменяемой коллекции, вы можете иметь структурное разделение) , было бы лучше просто переписать метод.

Ниже приведена реализация вашей Stack, которая является более краткой и простой (ИМХО) .

sealed trait Stack[+A] {
  final def push[B >: A](newTop: B): Stack[B] =
    Top(newTop, this)

  final def pop: (Option[A], Stack[A]) = this match {
    case Top(top, rest) => (Some(top), rest)
    case Empty          => (None, Empty)
  }
}

final case class Top[+A](top: A, rest: Stack[A]) extends Stack[A]
case object Empty extends Stack[Nothing]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...