Изменения вывода типов в Scala 3

Какие изменения в выводе типов принесет Scala 3? В настоящее время в документации просто указано TODO. Например,

Слабое соответствие

Скала 2.13

scala> val i: Int = 42
val i: Int = 42

scala> val c: Char = 'a'
val c: Char = a

scala> List(i,c)
val res0: List[Int] = List(42, 97)

Скала 3 (точка 0.24.0-RC1)

scala> val i: Int = 42
val i: Int = 42

scala> val c: Char = 'a'
val c: Char = a

scala> List(i,c)
val res0: List[AnyVal] = List(42, a)

Равенство

Скала 2.13

scala> 42 == Some(42)
          ^
       warning: comparing values of types Int and Some[Int] using `==` will always yield false
val res2: Boolean = false

Скала 3

scala> 42 == Some(42)
1 |42 == Some(42)
  |^^^^^^^^^^^^^^
  |Values of types Int and Some[Int] cannot be compared with == or !=

person Mario Galic    schedule 30.05.2020    source источник
comment
AFAIK, в общих улучшениях и типах союзов.   -  person Luis Miguel Mejía Suárez    schedule 30.05.2020
comment
Не уверен, что это подпадает под вывод, но на типы, зависящие от пути, теперь можно ссылаться в одном и том же списке параметров, поэтому потребность в шаблоне AUX меньше.   -  person Mario Galic    schedule 31.05.2020
comment
@MarioGalic Вы можете посмотреть выступления Гийома Мартреса на youtube.com/watch?v=lMvOykNQ4zs youtube.com/watch?v=YIQjfCKDR5A Слайды: guillaume.martres.me/talks/typelevel-summit-oslo guillaume.martres.me/talks   -  person Dmytro Mitin    schedule 04.06.2020


Ответы (2)


Итак, что касается вашего Equality примера, то он на самом деле вызван новым многосторонним равенством что в значительной степени означает, что если у вас есть Eql[A, B], где A есть B, то тип A можно сравнивать только с вещами, для которых он имеет экземпляр Eql (в форме Eql[A, C] или Eql[C, A]).

С точки зрения общего вывода типов для scala 3, главное:

  • Типы объединения: теперь мы можем представлять типы объединения и выражения. как

     if (condition) 1 else "1"
    

    должен быть выведен как тип Int | String.

  • Явные значения Null: одно из новых применений union types — это способ описания типов, допускающих значение null, поэтому, например, мы могли бы написать такой код на Java:

     public String getUser(int id) {
         if (id == 0) {
             return "Admin";
         }
         return null;
     }
    

    А также в scala 2 мы могли бы написать:

    def getUser(id: Int): String = if (id == 0) return "Admin" else null
    

    Но в scala 3 такой метод также должен быть объявлен как тип String | Null, чтобы представить его обнуляемость, и не будет компилироваться по умолчанию в более новых версиях scala 3.

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

  • GADT: аналогично тому, как @functionalInterface работает в Java, у нас есть GADT. Это означает, что если бы у вас был трейт с одним нереализованным методом:

    trait Fooable {
        def foo(): Unit
    }
    

    Вы можете создать его экземпляр, передав лямбду с этой подписью, поэтому в этом примере:

    val fooable: Fooable = () => print("Fooing")
    

    Есть еще несколько, в том числе функции контекста, Неявные преобразования и Развязка параметров, но это основные.

person Guyde    schedule 02.06.2020
comment
Что касается маркированного списка GADT - Fooable похоже, что это SAM, который был доступен некоторое время. Как SAM связан с GADT? - person Mario Galic; 04.06.2020
comment
Извините, вы правы, я имел в виду SAM, извините, что перепутал имена, я действительно случайно объединил два пункта. Что касается GADT, я хотел сказать, что члены GADT (в частности, перечисления) при создании экземпляра предполагаются как относящиеся к типу перечисления, а не к их фактическому типу. Так, например, enum Bool{ case True case False } будет иметь Bool.True, выведенный как тип Bool, а не Bool.True, даже если это его базовый тип. По поводу SAM-ов то, что они теперь выводятся для java-типов (не более new Runnable() { def run() .. }) - person Guyde; 05.06.2020

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

Скала 2.13

scala> def f[T](i: T, g: T => T) = g(i)
def f[T](i: T, g: T => T): T

scala> f(41, x => x + 1)
             ^
       error: missing parameter type

Скала 3

scala> def f[T](i: T, g: T => T) = g(i)
def f[T](i: T, g: T => T): T

scala> f(41, x => x + 1)
val res0: Int = 42

Я предполагаю, что это изменение может быть связано с Разрешить межпараметрические зависимости #2079


Улучшенный вывод, когда параметры типа не отображаются в терминах

Скала 2.13

scala> def f[F <: List[A], A](as: F) = as
def f[F <: List[A], A](as: F): F

scala> f(List(42))
       ^
       error: inferred type arguments [List[Int],Nothing] do not conform to method f's type parameter bounds [F <: List[A],A]
             ^
       error: type mismatch;
        found   : List[Int]
        required: F

Скала 3

scala> def f[F <: List[A], A](as: F) = as                                                                                                                
def f[F <: List[A], A](as: F): F

scala> f(List(42))                                                                                                                                       
val res0: List[Int] = List(42)
person Community    schedule 03.06.2020