#scala #types #scala-3 #dotty #match-types
#scala #типы #scala-3 #dotty #совпадающие типы
Вопрос:
Я хотел создать тип, который я мог бы использовать для проверки, является ли кортеж однородным. Я написал это, что должно гарантировать, что все элементы T
равны X
(Scastie):
type Homogenous[X] = [T <: Tuple] =>> T match {
case EmptyTuple => DummyImplicit
case X *: t => Homogenous[X][t] //Doesn't work
case _ => Nothing
}
def f[T <: Tuple : Homogenous[String]](t: T) = ???
По какой-то причине третья строка не компилируется с этой ошибкой:
Однородный [X] не принимает параметры типа
Однако, если я заставляю Homogenous
принимать 2 параметра, он компилируется, но я больше не могу использовать привязку к контексту (Scastie).
type Homogenous[X, T <: Tuple] = T match {
case EmptyTuple => DummyImplicit
case X *: t => Homogenous[X, t]
case _ => Nothing
}
Я не понимаю, почему это происходит. Это не значит, что лямбда [T] =>>
-выражение возвращается только из определенного случая типа соответствия, поэтому компилятор должен понимать, что Homogenous[X]
оно всегда принимает параметр. Это ошибка или я делаю что-то не так, и есть ли исправление / обходной путь?
Комментарии:
1. Хотя это несколько ожидаемо. Когда у вас есть рекурсивная функция, вам всегда нужно сначала объявить ее, прежде чем вызывать ее в определении, like
val f = (a:Int) => (b:Int) => f(a)(b)
не будет работать, потому что он не знает, что такое f тип во время компиляции, и он не может выполнять вывод и определение типа одновременно. Так что вам нужно сделатьval f: Int=>Int=>Int = a => b => f(a)(b)
, чтобы заставить его работать. Но для определения типа dotty не разрешает объявление (привязку) и определение в одной строке, поэтому компилятор не знает, что Homogenous — это конструктор типа curried, поэтому вы видите ошибку.2.@texasbruce Хороший момент. Но я думаю, что это еще не вся история, потому что тип
U[Int]
разрешенtype U <: [T] =>> Any
, но если мы добавим верхнюю границу, в нашем случаеtype Homogenous[X] <: ([T <: Tuple] =>> Any) = [T <: Tuple] =>> T match { ...
все равно не компилируется. Я подозреваю, что дело также может заключаться в том, как типы совпадений преобразуются вMatch
dotty.epfl.ch/docs/reference/new-types /…3.@texasbruce «Но для определения типа dotty не разрешает объявление (привязку) и определение в одной строке» Для типов соответствия допускается верхняя граница вместе с определением. Смотрите фрагмент кода
type Concat[Xs <: Tuple, Ys <: Tuple] <: Tuple = Xs match {...
dotty.epfl.ch/docs/reference/new-types/match-types.html4. @DmytroMitin Это правда. Похоже, что границы типов и определения одновременно разрешены только в том случае, если rhs не является типом более высокого порядка с предложением match. Довольно странное требование.
5. @texasbruce Ну, как я уже упоминал в своем ответе, несколько списков параметров типа недостаточно реализованы. Может
type Homogenous[X][T <: Tuple] = T match {...
быть, илиtype Homogenous = [X] =>> [T <: Tuple] =>> T match {...
будет скомпилирован тогда.
Ответ №1:
Похоже на ошибку или недостаточно реализованную функцию.
В качестве обходного пути попробуйте
trait Hom[X] {
type Rec[T <: Tuple] = T match {
case EmptyTuple => DummyImplicit
case X *: t => Rec[t]
case _ => Nothing
}
}
type Homogenous[X] = [T <: Tuple] =>> Hom[X]#Rec[T]
Возможно, связано с
https://contributors.scala-lang.org/t/multiple-type-parameter-lists-in-dotty-si-4719
Комментарии:
1. Ах, это очень плохо. Я подожду некоторое время, а затем открою проблему на GitHub.