Каррированный тип «не принимает параметры типа»

#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.html

4. @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

https://github.com/scala/bug/issues/4719

Комментарии:

1. Ах, это очень плохо. Я подожду некоторое время, а затем открою проблему на GitHub.