Обобщенные ограничения в параметре типа? - PullRequest
2 голосов
/ 05 апреля 2020

SLS задает синтаксис параметра параметра типа как

TypeParamClause   ::=  ‘[’ VariantTypeParam {‘,’ VariantTypeParam} ‘]’
FunTypeParamClause::=  ‘[’ TypeParam {‘,’ TypeParam} ‘]’
VariantTypeParam  ::=  {Annotation} [‘+’ | ‘-’] TypeParam
TypeParam         ::=  (id | ‘_’) [TypeParamClause] [‘>:’ Type] [‘<:’ Type] {‘<%’ Type} {‘:’ Type}                  {‘<%’ Type} {‘<%’ Type}

, где мы видим >:, <:, <%, <%, : как разрешенные зарезервированные имена в предложении параметра типа. Есть ли способ, которым мы могли бы использовать обобщенное ограничение типа symboli c names <:<, =:= в предложении параметра типа, так что

def f[T =:= 42] = ???

расширится до

def f[T](implicit ev: T =:= 42) = ???

аналогично тому, как контекстная привязка

def f[T: Numeric] = ???

расширяется до

def f[T](implicit ev: Numeric[T]) = ???

1 Ответ

6 голосов
/ 05 апреля 2020

В 2.13 (которая поддерживает одноэлементные типы, если вам интересно ограничиться синглетами) вы можете делать такие вещи:

@ import $plugin.$ivy.`org.typelevel:kind-projector_2.13.1:0.11.0`
import $plugin.

@ type a = 23
defined type a

@ def f[N : * =:= a]: Unit = ()
defined function f

@ f[a]


@ f[23]


@ f[25]
cmd9.sc:1: Cannot prove that 25 =:= Int(23).
val res9 = f[25]
            ^
Compilation Failed

@ def g[N : * =:= 16]: Unit = ()
defined function g

@ g[16]


@ g[23]
cmd11.sc:1: Cannot prove that 23 =:= 16.
val res11 = g[23]
             ^
Compilation Failed

Так что, да, это кажется возможным. Вам просто нужно использовать добрые проекторы, чтобы применить второй параметр.

С <:< должно быть то же самое:

@ def h[N : * <:< 16]: Unit = ()
defined function h

@ h[16]


@ h[17]
cmd13.sc:1: Cannot prove that 17 <:< 16.
val res13 = h[17]
             ^
Compilation Failed
...