Что такое понятие «слабое соответствие» в Scala? - PullRequest
27 голосов
/ 22 июня 2010

Я только недавно столкнулся с термином «Слабое соответствие» (у пользователя переполнения стека retronym ответ на Как настроить неявное преобразование для разрешения арифметики между числовыми типами? ).

Что это?

Ответы [ 3 ]

20 голосов
/ 22 июня 2010

3.5.3 Слабое соответствие В некоторых ситуациях Scala использует более общее отношение соответствия.Тип S слабо соответствует типу T, написанному S <: <sub>w T, если S <: T или оба S и T являются типами примитивных чисел и S предшествует T в следующем порядке.</p>

  • Байт <: <sub>w Short
  • Byte <: <sub>w Символ
  • Short <: <sub>w Int
  • Int <: <sub>w Long
  • Long <: <sub>w Float
  • Float <:<sub> w Double

Слабая наименьшая верхняя граница - это наименьшая верхняя граница в отношении слабого соответствия.

Где это используется?С одной стороны, он определяет тип if выражений:

Тип условного выражения - это слабая наименьшая верхняя граница (§3.3.3) типов e2 и e3

В Scala 2.7.x это будет иметь тип AnyVal с наименьшим верхним пределом Int и Double.В 2.8.x он печатается как Double.

scala> if (true) 1 else 1d
res0: Double = 1.0

Аналогично:

scala> try { 1 } catch { case _ => 1.0 }
res2: Double = 1.0

scala> (new {}: Any) match { case 1 => 1; case _ => 1.0 }
res6: Double = 1.0

scala> def pf[R](pf: PartialFunction[Any, R]): PartialFunction[Any, R] = pf
pf: [R](pf: PartialFunction[Any,R])PartialFunction[Any,R]

scala> pf { case 1 => 1; case _ => 1d }
res4: PartialFunction[Any,Double] = <function1>

Другое место, где он используется, находится в выводе типа:

scala> def foo[A](a1: A, a2: A): A = a1
foo: [A](a1: A,a2: A)A

scala> foo(1, 1d)
res8: Double = 1.0

scala> def foos[A](as: A*): A = as.head
foos: [A](as: A*)A

scala> foos(1, 1d)
res9: Double = 1.0

А также для простого числового расширения:

Числовое расширение.Если e имеет примитивный тип чисел, который слабо соответствует (§3.5.3) ожидаемому типу, он расширяется до ожидаемого типа, используя один из методов преобразования чисел 6.26 Неявные преобразования 97 toShort, toChar, toInt, toLong, toFloat, toDoubleопределено в §12.2.1.ожидаемый тип - это примитивный числовой тип Byte, Short или Char, а выражение e - это целочисленный литерал, подходящий в диапазоне этого типа, он преобразуется в тот же литерал в этом типе.

scala> 1: Double
res10: Double = 1.0

ОБНОВЛЕНИЕ

Как указал Дэниел, спецификация неверна в отношении того, какие типы имеют слабую совместимость.Давайте спросим сам компилятор:

scala> :power
** Power User mode enabled - BEEP BOOP      **
** scala.tools.nsc._ has been imported      **
** New vals! Try repl, global, power        **
** New cmds! :help to discover them         **
** New defs! Type power.<tab> to reveal     **

scala> settings.maxPrintString = 10000


scala> import global.definitions._
import global.definitions._

scala> (for{c1 <- ScalaValueClasses;
      c2 <- ScalaValueClasses
      isNSC = isNumericSubClass(c1, c2)
      if isNSC
  } yield ("isNumericSubClass (%s, %s) = %b" format (c1, c2, isNSC))).mkString("\n")


res5: String =
isNumericSubClass (class Byte, class Byte) = true
isNumericSubClass (class Byte, class Short) = true
isNumericSubClass (class Byte, class Int) = true
isNumericSubClass (class Byte, class Long) = true
isNumericSubClass (class Byte, class Float) = true
isNumericSubClass (class Byte, class Double) = true
isNumericSubClass (class Short, class Short) = true
isNumericSubClass (class Short, class Int) = true
isNumericSubClass (class Short, class Long) = true
isNumericSubClass (class Short, class Float) = true
isNumericSubClass (class Short, class Double) = true
isNumericSubClass (class Int, class Int) = true
isNumericSubClass (class Int, class Long) = true
isNumericSubClass (class Int, class Float) = true
isNumericSubClass (class Int, class Double) = true
isNumericSubClass (class Long, class Long) = true
isNumericSubClass (class Long, class Float) = true
isNumericSubClass (class Long, class Double) = true
isNumericSubClass (class Char, class Int) = true
isNumericSubClass (class Char, class Long) = true
isNumericSubClass (class Char, class Char) = true
isNumericSubClass (class Char, class Float) = true
isNumericSubClass (class Char, class Double) = true
isNumericSubClass (class Float, class Float) = true
isNumericSubClass (class Float, class Double) = true
isNumericSubClass (class Double, class Double) = true
5 голосов
/ 22 июня 2010

Чтобы завершить ответ Сандора , эта новая функция в 2.8 все еще запекается (и исправляется).

В этой теме , Эссер обнаруживает неприятный побочный эффект:

scala> val a= 10 
a: Int = 10 

scala> val b= 3 
b: Int = 3 

scala> if (b!=0) a/b else Double.NaN 
res0: Double = 3.0 

scala> def div1(a: Int, b: Int) = if (b!=0) a/b else Double.NaN 
div1: (a: Int,b: Int)Double 

scala> def div2(a: Int, b: Int): Double = if (b!=0) a/b else Double.NaN 
div2: (a: Int,b: Int)Double 

scala> div1(10,3) 
res1: Double = 3.0 

scala> div2(10,3) 
res2: Double = 3.3333333333333335 

Кажется интересным, поскольку неявно найденный тип результата - Double, а результат - 3,0.
Если Double задан явно, результат равен 3.33 ...

В этой теме , Мартин Одерский добавляет (21 июня):

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

Это предпочтительнее метод добавления Float => Float в Int, чем метод Int => Int, если тип результата был Float.
Я пытался быть консервативным в своем переходе к слабому соответствию, поскольку требовал слабого соответствия только там, где это выглядело абсолютно необходимым.
Но теперь кажется, что консервативность привела к проблеме, на которую мы смотрим!

И еще один релиз Scala RC;)


Подтверждено в этой теме Мартином Одерским (22 июня) :

Итак, будет RC7 с тремя изменениями от RC6:

  1. val x: Double = 10/3 даст 3.0, а не 3.3333333 - это была регрессия, о которой я упоминал
  2. [...]
  3. [...]

Вот и все. Теперь наши приоритеты - как можно быстрее развернуть 2.8, и в то же время избежать действительно плохих регрессий, таких как (1) выше.

Хронология:

  • Мы будем ждать еще одну неделю, чтобы получить отзывы о RC6.
  • Мы выпустим RC7 в начале следующей недели.
    Если больше никаких проблем не появится, RC7 превратится в 2,8 финала через 10-14 дней после его выпуска.

(так что примерно 12 июля, я полагаю, но это предположение только мое;))

4 голосов
/ 22 июня 2010

Согласно спецификации Scala lang 2.8:
http://www.scala -lang.org / archives / downloads / distrib / files / nightly / pdfs / ScalaReference.pdf

3.5.3 Слабое соответствие
В некоторых ситуациях Scala использует более общее отношение соответствия.Тип S слабо соответствует типу T, написанному S <: w T, если S <: T или оба S и T являются типами примитивных чисел и S предшествует T в следующем порядке. <br>Byte <: w Short <br>Byte <: w Символ <br>Short <: w Int <br>Int <: w Long <br>Long <: w Float <br>Float <: w Double <br>Слабая наименьшая верхняя граница - наименьшая верхняясвязаны со слабым соответствием.

...