如何专注于 Scala 中的类型投影? [英] How to specialize on a type projection in Scala?
问题描述
问题陈述
考虑一个包含抽象类型成员A
的类型T
:
Consider a type T
that contains an abstract type member A
:
trait T {
type A
}
我想创建一个将 T0 <: T
作为类型参数的类,但专门研究 类型投影 T0#A代码>.例如,下面的方法
foo
可以特化吗?
I'd like to create a class that takes a T0 <: T
as a type parameter, but specializes on the type projection T0#A
. For example, in the following, can the method foo
be specialized?
class Foo[T0 <: T] {
def foo(a: T0#A, f: T0#A => T0#A) = f(a)
}
请注意,使用 @specialized
注释 T0
不会达到预期的结果.是否有专门针对类型投影 T#A
的 foo
的好方法?
Note that annotating T0
with @specialized
will not achieve the desired result. Is there is a good way to specialize foo
on the type projection T#A
?
有限的解决方案:从带有额外参数的特殊父类继承
在这种特殊情况下,这里有一种专门处理 T0#A
的方法:
In this particular case, here's a way to specialize on T0#A
:
trait SpecializedFoo[@specialized A0, T0 <: T] {
def foo(a: A0, f: A0 => A0) = f(a)
}
class Foo2[T0 <: T] extends SpecializedFoo[T0#A, T0]
通过继承专门的父类 SpecializedFoo
,我们确保 Foo2.foo
是专门的.
By inheriting from the specialized parent class SpecializedFoo
, we ensure that Foo2.foo
is specialized.
专业化验证
为了验证 Foo2.foo
而不是 Foo.foo
是特化的,我们可以使用显式的 T
调用它们,其中 T#A
是一个原始的 Double,
To verify that Foo2.foo
, but not Foo.foo
, is specialized, we can call them with an explicit T
where T#A
is a primitive Double,
trait ExplicitT extends T {
type A = Double
}
object Test {
def test1 = (new Foo[ExplicitT]).foo(1.0, _ + 1.0)
def test2 = (new Foo2[ExplicitT]).foo(1.0, _ + 1.0)
}
可以使用命令:javap -v Test"从 REPL 检查字节码,
The bytecode can be examined from the REPL with the command ":javap -v Test",
public double test1();
Code:
Stack=4, Locals=1, Args_size=1
0: new #16; //class Foo
3: dup
4: invokespecial #18; //Method Foo."<init>":()V
7: dconst_1
8: invokestatic #24; //Method scala/runtime/BoxesRunTime.boxToDouble:(D)Ljava/lang/Double;
11: new #26; //class Test$$anonfun$test1$1
14: dup
15: invokespecial #27; //Method Test$$anonfun$test1$1."<init>":()V
18: invokevirtual #31; //Method Foo.foo:(Ljava/lang/Object;Lscala/Function1;)Ljava/lang/Object;
21: invokestatic #35; //Method scala/runtime/BoxesRunTime.unboxToDouble:(Ljava/lang/Object;)D
24: dreturn
LineNumberTable:
line 13: 0
public double test2();
Code:
Stack=5, Locals=1, Args_size=1
0: new #38; //class Foo2
3: dup
4: invokespecial #39; //Method Foo2."<init>":()V
7: dconst_1
8: new #41; //class Test$$anonfun$test2$1
11: dup
12: invokespecial #42; //Method Test$$anonfun$test2$1."<init>":()V
15: invokeinterface #48, 4; //InterfaceMethod SpecializedFoo.foo$mcD$sp:(DLscala/Function1;)D
20: dreturn
LineNumberTable:
line 14: 0
请注意,装箱出现在 test1
中,但不出现在 test2
中.
Note that boxing appears in test1
but not test2
.
限制
Edit 7/9 上面的技巧比我最初意识到的要有限.专门用于这种情况,它根本不起作用:
Edit 7/9 The trick above is more limited than I realized at first. It won't work at all for specializing this case:
trait T {
type A
def x: A
def f: A => Double
}
class Foo[T0 <: T] {
def foo(t: T0) = t.f(t.x)
}
我看不出为什么(假设的)编译器不能专注于 A
原则上;通常,只有在编译时已知特定的 T#A
时,专用版本才可用.自然的实际解决方案是将 A
提升为 T
的类型参数,但我想知道是否可以避免这种情况.
I see no reason why a (hypothetical) compiler couldn't specialize on A
in principle; a usual, the specialized versions would only be usable when a specific T#A
is known at compile time. The natural practical solution is to lift A
into a type parameter of T
, but I was wondering if I could avoid that.
推荐答案
这是编译器限制;一个不能通常专注于类型参数的元素.但是,建议的技巧足以满足我的目的:
This is a compiler limitation; one cannot generally specialize on elements of a type parameter. However, the proposed trick is good enough for my purposes:
trait Types {
type A
type B
}
trait GenOps[@specialized A, @specialized B] {
...
}
trait Ops[T <: Types] extends GenOps[T#A, T#B]
通过这种方式,特征 Ops
变得特殊,因为它继承了特征 GenOps
中的特殊实现.我的动机是我希望 trait Ops
采用单个类型参数 T
,而不是 T#A
和 T#B
(当 Ops
也采用期望 T
作为参数的更高种类类型时,这变得必要).
This way the trait Ops
gets specialized because it inherits the specialized implementations in trait GenOps
. My motivation is that I want trait Ops
to take a single type parameter T
, rather than both T#A
and T#B
(this becomes necessary when Ops
also takes a higher kinded type that expects T
as a parameter).
这篇关于如何专注于 Scala 中的类型投影?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!