Несоответствие типа для понимания: получение «Продукта с Serializable»

#scala #types #yield #for-comprehension

#scala #типы #выход #для понимания

Вопрос:

Я пишу функцию, которая будет принимать список вхождений символов ( List[(Char, Int)] ) в строке и создавать все подмножества этого списка вхождений.

Итак, учитывая

 List(('a', 2), ('b', 2))
  

Это приведет к

 List(
  List(),
  List(('a', 1)),
  List(('a', 2)),
  List(('b', 1)),
  List(('a', 1), ('b', 1)),
  List(('a', 2), ('b', 1)),
  List(('b', 2)),
  List(('a', 1), ('b', 2)),
  List(('a', 2), ('b', 2))
)
  

Я реализовал это следующим образом:

 type Occurrences = List[(Char, Int)]

def combinations(occurrences: Occurrences): List[Occurrences] =
  if (occurrences.isEmpty) List(List())
  else for {
    (c, n) <- occurrences
    i <- n to 1 by -1
  } yield (c, i) :: combinations(occurrences.tail)
  

И я получаю эту ошибку:

 type mismatch;
 found   : List[List[Product with Serializable]]
 required: List[Occurrences]
    (which expands to)  List[List[(Char, Int)]]
  

Пожалуйста, помогите мне понять, почему это происходит, и как мне это исправить?

Я попытался переписать его как flatMap …, используя Intellij «Explain Scala code» и т.д.

Комментарии:

1. Какая-либо конкретная причина, которая мешает вам принять ответ?

Ответ №1:

На самом деле скобки отсутствуют:

 type Occurrences = List[(Char, Int)]

  def combinations(occurrences: Occurrences): List[Occurrences] =
    if (occurrences.isEmpty) List(List())
    else (for {
      (c, n) <- occurrences
      i <- n to 1 by -1
    } yield (c, i)) :: combinations(occurrences.tail)
  

В вашем исходном коде для понимания пытались выдать, (c, i) :: combinations(occurrences.tail) который List имеет Any элемент внутри ( Tuple / другой List ).

Обновить:

Правильный метод, который выполняет требуемую магию:

 type Occurrences = List[(Char, Int)]


  /**
    * Returns the list of all subsets of the occurrence list.
    *  This includes the occurrence itself, i.e. `List(('k', 1), ('o', 1))`
    *  is a subset of `List(('k', 1), ('o', 1))`.
    *  It also include the empty subset `List()`.
    *
    *  Example: the subsets of the occurrence list `List(('a', 2), ('b', 2))` are:
    *
    *    List(
    *      List(),
    *      List(('a', 1)),
    *      List(('a', 2)),
    *      List(('b', 1)),
    *      List(('a', 1), ('b', 1)),
    *      List(('a', 2), ('b', 1)),
    *      List(('b', 2)),
    *      List(('a', 1), ('b', 2)),
    *      List(('a', 2), ('b', 2))
    *    )
    *
    *  Note that the order of the occurrence list subsets does not matter -- the subsets
    *  in the example above could have been displayed in some other order.
    */
  def combinations(occurrences: Occurrences): List[Occurrences] =
    occurrences.foldRight(List[Occurrences](Nil)) {
      case ((ltr, cnt), acc) =>
        acc ::: (for {
          comb <- acc
          ltrNum <- 1 to cnt
        } yield (ltr, ltrNum) :: comb)
    }
  

Вся слава автору этого кода.

Комментарии:

1. Круглые скобки определяют тип, но изменяют предполагаемое поведение кода. Я пытаюсь получить точно (c, i) :: combinations(occurrences.tail)

2. Давайте разберем это: combinations(occurrences.tail) имеет тип List[List[(Char, Int)]] . Вы пытаетесь добавить, (c, i) что есть (Char, Int) . Вы должны добавить List[(Char, Int)]

3. Однако даже после этого это не дает требуемого результата, что заставляет меня думать, что сам алгоритм не совсем корректен. Я не собираюсь публиковать решение алгоритмической проблемы, поскольку ваш вопрос требует решения проблемы компиляции.

4. Пожалуйста, ознакомьтесь с обновлением, оно содержит метод, который делает то, что вам нужно.