Ошибка при передаче кортежа универсальному методу

#scala #generics

#scala #универсальные методы

Вопрос:

Вот функция для запоминания / кэширования промежуточного результата :

  def memoize[I, O](f: I => O) = new scala.collection.mutable.HashMap[I, O]() {
   override def apply(key: I): O = getOrElseUpdate(key, f(key))    
 }
  

Это отлично работает для кода, подобного приведенному ниже,

 val double: Int=>Int = memoize {
    _*2
}
  

Однако, когда я пытаюсь использовать tuple в качестве входного параметра (I), он показывает ошибку времени компиляции,

 val isGivenNumIsHead:(List[Int], Int) => Boolean = memoize {
  case (Nil, _) => false
  case (a:: as, n) => a == n
}
  

Ошибка во время компиляции :

Выражение изменяемого типа.HashMap[Ничего, логическое значение] {def apply(key: Ничего): Boolean} не соответствует ожидаемому типу (List[Int], Int) => Boolean

Это что-то связанное со стиранием.

Как мне это исправить?

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

1. Я в замешательстве. memoize возвращает HashMap[O, I] , но вы хотите вернуть функцию типа: (List[Int], Int]) => Boolean ?

Ответ №1:

Я предполагаю, что вы хотите использовать кортеж в качестве ключа в HashMap. Имея это в виду, вот объяснение.

Фактический возвращаемый тип memoize является scala.collection.mutable.HashMap[_,_] . Это присваивается double тому, который имеет тип Int => Int or Function1[Int,Int] ( функция, которая принимает целое число и выдает промежуточное значение). Компилятор не выдает ошибку, потому что mutable.HashMap расширяет scala.collection.mutable.MapLike , которое, в свою очередь, расширяет, scala.collection.MapLike которое, в свою очередь, расширяет, scala.PartialFunction[A, B] которое, в свою очередь, расширяет scala.Function1[A, B] . Следовательно, ошибки компиляции нет.

С другой стороны, синтаксис для функций, принимающих один параметр и возвращающих одно значение, является val functionName : A => B = a => {return b} или может быть записан как val function : (A) => B = a => {return b} или val function: (A => B) = a => {return b} . Вы использовали второй метод. В этом случае значение A должно быть одного типа. Вы использовали List[Int],Int который не относится к одному типу. Обратите внимание, что я намеренно удалил скобки. Итак, чтобы создать это как единый тип и передать его как кортеж, вы должны использовать еще один набор скобок. Правильный синтаксис был бы

 val isGivenNumIsHead:((List[Int], Int)) => Boolean = memoize {
  case (Nil, _) => false
  case (a:: as, n) => a == n
}
  

Обратите внимание на использование дополнительных скобок, чтобы сделать его кортежем.

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

1. Большое вам спасибо! Спасибо за подробное и приятное объяснение!