scala - функции высшего порядка меняют тип T на тип Nothing - PullRequest
0 голосов
/ 07 февраля 2019

Устранение неполадок env: консоль sbt (Scala 2.11.8) и spark-shell (Spark 2.3, Scala 2.11)

У меня есть функция высшего порядка с типом привязки вида T ... ноэта сигнатура типа arg t: T меняется с T <% Double на Nothing, когда функция применяется частично.

Пример игрушки для демонстрации:

// tot: T needs to work on (at least) Int, Long, Double, Float
// no common supertype -> some kind of context bound

def func[T <% Double](isValid: Boolean)(tot: T, cnt: Int): Double = 
  if (isValid) tot.toDouble / cnt else Double.NaN

Когда я пытаюсь частично применить isValid, Я ожидаю, что результатом будет тип (T, Int) => Double, но вместо этого тип заканчивается (Nothing, Int) => Double, и я не могу передать arg tot.

val f1 = func(true)_   // f1: (Nothing, Int) => Double = <function2>
val f2 = func(false)_  // f2: (Nothing, Int) => Double = <function2>

val g1 = f1(10.0, 1)
// <console>:40: error: type mismatch;
// found   : Double(10.0)
// required: Nothing
//       val g1 = f1(10.0, 1)

Я не получаю никаких сообщений об ошибкахпри определении f1 или f2 ... так что трудно интерпретировать.Он просто конвертирует arg tot: T в тип Nothing.

Проверка scala doc ... Я вижу scala. Ничто не является подтипом КАЖДОГО другого типа, поэтому я подумал, что, возможно, он теряет вид, связанный с T... что, возможно, было связано с стиранием типов ... поэтому я попытался использовать ClassTag ...

import scala.reflect.ClassTag

def func[T <% Double](isValid: Boolean)(tot: T, cnt: Int)(implicit tag: ClassTag[T]): Double = 
  if (isValid) tot.toDouble / cnt else Double.NaN

Это не помогает.Та же проблема.

, если я попытаюсь использовать implicit num: Numeric[T], он задушит тип Nothing по-новому ...

def func[T](isValid: Boolean)(tot: T, cnt: Int)( implicit num: Numeric[T] ): Double = 
  if (isValid) num.toDouble(tot) / cnt else Double.NaN

val f1 = func(true)_
// <console>:40: error: could not find implicit value for parameter num: Numeric[Nothing]
//        val f1 = func(true)_

Если применить все сразу (используя first 'func 'наверху), он отлично работает ...

val g1 = func(true)(10.0, 1)
// g1: Double = 10.0

Но в моем реальном (не игрушечном) коде это не вариант.

Что здесь происходит и какможно ли заставить func работать при частичном применении?

РЕДАКТИРОВАТЬ [@ решение Алексея]

Я не могу получить предпочтительный подход 'def' к работе.

def func[T <% Double](isValid: Boolean)(tot: T, cnt: Int): Double =
  if (isValid) tot.toDouble / cnt else Double.NaN
// func: [T](isValid: Boolean)(tot: T, cnt: Int)(implicit evidence$1: T => Double)Double

def f1[T <% Double]: ((T, Int) => Double) = func[T](true)_
// f1: [T](implicit evidence$1: T => Double)(T, Int) => Double

f1[Double](10.0, 1)
<console>:41: error: too many arguments for method f1: (implicit evidence$1: Double => Double)(Double, Int) => Double
   f1[Double](10.0, 1)

1 Ответ

0 голосов
/ 07 февраля 2019

Когда я пытаюсь частично применить isValid, я ожидаю, что результатом будет тип (T, Int) => Double

Значения не могут быть общими.Таким образом, он может иметь этот тип для некоторого конкретного T, но вы не предоставляете точно параметры, которые позволили бы вывести его.Вы можете указать, например,

val f1 = func[TheTypeYouWant](true) _

или

val f1: (TheTypeYouWant, Int) => Double = func(true) _

Если вы хотите, чтобы оно было универсальным, оно должно быть снова def:

def f1[T <% Double] = func[T](true) _
...