简体   繁体   中英

How to use a wildcard for a higher-kinded type in Scala?

Let's say I have this trait

trait Ctx[C, V[_]]

I am unable to construct any method signature that takes a Ctx of which the second type parameter is unspecified (wildcard). Eg this:

def test(c: Ctx[_, _]) = ()

doesn't compile ( "error: _$2 takes no type parameters, expected: one" ). Neither can I do

def test(c: Ctx[_, _[_]]) = ()

( "error: _$2 does not take type parameters" ). What am I missing?

I'm able to define this one:

def test[V[X]](c:Ctx[_,V]) {}

And it seems to work ok with type inference:

scala> trait Ctx[ C, V[ _ ]]
defined trait Ctx

scala> def test[V[X]](c:Ctx[_,V]) {}
test: [V[X]](c: Ctx[_, V])Unit

scala> class P extends Ctx[Int, List]
defined class P

scala> new P
res0: P = P@1f49969

scala> test(res0)

Edit : I suspect it won't be practical to replace Ctx to use an abstract type, but this is what I was able to do:

trait Ctx[C] { type V[X] }
class CtxOption[C] extends Ctx[C] { type V[X] = Option[X] }
class CtxList[C] extends Ctx[C] { type V[X] = List[X] }

def test(ctx:Ctx[_]) { println(ctx) }

val ctxOptInt = new CtxOption[Int]
val ctxListStr = new CtxList[String]

test(ctxOptInt)
test(ctxListStr)

val list = collection.mutable.ListBuffer[Ctx[_]]()
list += ctxOptInt
list += ctxListStr
list

Using an abstract type for V spares you the complicated (or impossible) task of figuring the type parameter syntax for a wildcard type constructor. Additionally as demonstrated in the ListBuffer example you can then handle objects where the V is a different type constructor ( Option and List in my example). The first solution I provided would not allow you to do that.

Edit 2 : How about?

trait AbstractCtx[C] { type W[X] }
trait Ctx[C,V[_]] extends AbstractCtx[C] { type W[X] = V[X] }
def test(ctx:AbstractCtx[_]) { println(ctx) }

You need to pass a type constructor for the second argument of Ctx . Scala is not able to infer the correct kind if you just pass _ . Neither is it possible to define a type constructor with wildcards (ie _[_]] on the fly. Note that in your first example _$2 in the error message refers to the type passed as second argument to Ctx as a whole. In the second example however _$2 refers to the the first wildcard type in _[_] . See the location indicator in the error messages:

<console>:6: error: _$2 does not take type parameters
       def test( c: Ctx[ _, _[ _ ]]) {}
                            ^

The following works since here V is a type constructor of the right kind expected by Ctx .

def test[V[_]]( c: Ctx[ _, V]) {}

It's all explained here . Focus on the "Common Pitfalls" section at the bottom.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM