Почему параметр типа, связанный с функцией более высокого порядка, применяется неправильно? - PullRequest
0 голосов
/ 07 мая 2019

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

object Repeater {
  // The first parameter is passed in a separate parameter list.
  def repeat[DstType >: ElemType, ElemType](list: List[ElemType])
                                           (function: DstType => DstType,
                                            times: Int): List[DstType] = {
    var currentList: List[DstType] = list
    for (_ <- 0 until times) {
      currentList = currentList.map(function)
    }
    currentList
  }

  // The first parameter is passed in the same parameter list as the others.
  def repeat2[DstType >: ElemType, ElemType](list: List[ElemType],
                                             function: DstType => DstType,
                                             times: Int): List[DstType] = {
    var currentList: List[DstType] = list
    for (_ <- 0 until times) {
      currentList = currentList.map(function)
    }
    currentList
  }
}

class Base()

class Extended() extends Base

object Test extends App {
  val list: List[Extended] = Nil

  Repeater.repeat(list)( x => x, 1)
  Repeater.repeat(list)( (x: Base) => x, 1)

  Repeater.repeat2(list, x => x, 1)
  Repeater.repeat2(list, (x: Base) => x, 1)
}

Первый вызовrepeat() компилируется, и мне не нужно указывать тип параметра в функции, заданной для repeat(), что является моим предполагаемым поведением.

Второй вызов repeat() не компилируется:

Error:(25, 39) type mismatch;
 found   : pipeops.Base
 required: pipeops.Extended
  Repeater.repeat(list)( (x: Base) => x, 1)

Я не понимаю эту ошибку, потому что найденный тип base является супертипом Extended и, таким образом, вписывается в мой связанный тип предоставления DstType >: ElemTyp.

Первый вызов repeat2()не компилируется:

Error:(27, 26) missing parameter type
  Repeater.repeat2(list, x => x, 1)

Мне действительно странно, что компилятор в этом случае ожидает от меня указания типа параметра функций.

Второй вызов repeat2() компилируется и

Теперь у меня есть два вопроса:

  1. Может кто-нибудь объяснить мне, откуда эти различия?

  2. Может быть, есть другой способуказание функции повтора, которая не требует, чтобы my указывал тип параметра, если переданная функция переходит с ElemType на ElemType, но позволяет расширить тип переданных функций для работы с супертипом ElemType, если я хочу.

1 Ответ

1 голос
/ 07 мая 2019

Что не так с одним параметром типа?

  object Repeater {
    def repeat[ElemType](list: List[ElemType])
                                             (function: ElemType => ElemType,
                                              times: Int): List[ElemType] = {
      var currentList: List[ElemType] = list
      for (_ <- 0 until times) {
        currentList = currentList.map(function)
      }
      currentList
    }

    def repeat2[ElemType](list: List[ElemType],
                                               function: ElemType => ElemType,
                                               times: Int): List[ElemType] = {
      var currentList: List[ElemType] = list
      for (_ <- 0 until times) {
        currentList = currentList.map(function)
      }
      currentList
    }
  }

  class Base()

  class Extended() extends Base

  object Test extends App {
    val list: List[Extended] = Nil
    val list1: List[Base] = list

    Repeater.repeat(list)( (x: Extended) => x, 1)
    Repeater.repeat(list1)( (x: Base) => x, 1)

    Repeater.repeat2(list, (x: Extended) => x, 1)
    Repeater.repeat2(list, (x: Base) => x, 1)
    Repeater.repeat2(list1, (x: Base) => x, 1)

    Repeater.repeat[Extended](list)( (x: Extended) => x, 1)
    Repeater.repeat[Base](list1)( (x: Base) => x, 1)
    Repeater.repeat2[Extended](list, (x: Extended) => x, 1)
    Repeater.repeat2[Base](list, (x: Base) => x, 1)
  }

Если иногда компилятор не заставляет вас явно указывать типы, это означает, что он может выводить их сам, в противном случае он не может и вам следует указать.

...