Предположим, что у меня есть функциональный тип, например.Получить «наиболее специфичный» тип ввода
trait Parser[-Context, +Out]
, и я хочу, чтобы иметь возможность объединить несколько парсеров так что комбинированная Context
будет наиболее конкретным типом среди контекстов объединившихся парсеров. Например:
Parser[Any, Int] + Parser[String, Long] = Parser[String, (Int, Long)]
Parser[String, Int] + Parser[Any, Long] = Parser[String, (Int, Long)]
Parser[Option[Int], Foo] + Parser[Some[Int], Bar] = Parser[Some[Int], (Foo, Bar)]
Parser[String, Foo] + Parser[Int, Bar] = <should be a compile error>
Чтобы поместить пример в более конкретных терминах, предположим, что у меня есть функция объединитель как
def zipFuncs[A, B1, B2](f1: A => B1, f2: A => B2): A => (B1, B2) = {
a => (f1(a), f2(a))
}
и некоторые функции, такие как
val f1 = { a: Any => 123 }
val f2 = { a: String => 123 }
val f3 = { a: Option[Int] => 123 }
Теперь я могу сделать
> zipFuncs(f1, f2)
res1: String => (Int, Int) = <function>
> zipFuncs(f1, f3)
res2: Option[Int] => (Int, Int) = <function>
> zipFuncs(f2, f3)
res3: Option[Int] with String => (Int, Int) = <function1>
B ut, что я хочу, это для zipFuncs(f2, f3)
, чтобы не компилировать вообще. Поскольку String
не является подтипом Option[Int]
, а Option[Int]
не является подтипом String
, нет возможности построить входное значение для res3
.
я создать класс типов:
// this says type `T` is the most specific type between `T1` and `T2`
sealed trait MostSpecificType[T, T1, T2] extends (T => (T1, T2))
// implementation of `object MostSpecificType` omitted
def zipFuncs[A, A1, A2, B1, B2](f1: A1 => B1, f2: A2 => B2)(
implicit mst: MostSpecificType[A, A1, A2]
): A => (B1, B2) = { a: A =>
val (a1, a2) = mst(a)
f1(a1) -> f2(a2)
}
Это завершало цели, описанные выше, но с очень раздражает проблемой. IntelliJ будет выделять допустимые комбинации как ошибки, вызывая, что «наиболее специфический тип (A
)» фактически равен Nothing
, когда он фактически является реальной стоимостью. Here's the actual issue in practice.
Проблема с подсветкой, несомненно, является ошибкой в IntelliJ, и поиск в google, по-видимому, подразумевает, что различные сбросы/кеш-файлы/etc должны исправлять его (это не так). Независимо от вины, я надеюсь найти альтернативный подход, который удовлетворяет моему первоначальному требованию и не путает IntelliJ.
Это точно поведение, которое я искал. Мне придется попробовать этот подход в моем реальном проекте! – Dylan