#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. Большое вам спасибо! Спасибо за подробное и приятное объяснение!