Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
645 views
in Technique[技术] by (71.8m points)

scala - How do I get an instance of the type class associated with a context bound?

Note: I'm posing this question to answer it myself, but other answers are welcome.

Consider the following simple method:

def add[T](x: T, y: T)(implicit num: Numeric[T]) = num.plus(x,y)

I can rewrite this using a context bound as follows

def add[T: Numeric](x: T, y: T) = ??.plus(x,y) 

but how do I get an instance of the Numeric[T] type so that I can invoke the plus method?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Using the implicitly method

The most common and general approach is to use the implicitly method, defined in Predef:

def add[T: Numeric](x: T, y: T) = implicitly[Numeric[T]].plus(x,y)

Obviously, this is somewhat verbose and requires repeating the name of the type class.

Referencing the evidence parameter (don't!)

Another alternative is to use the name of the implicit evidence parameter automatically generated by the compiler:

def add[T: Numeric](x: T, y: T) = evidence$1.plus(x,y)

It's surprising that this technique is even legal, and it should not be relied upon in practice since the name of the evidence parameter could change.

Context of a Higher Kind (introducing the context method)

Instead, one can use a beefed-up version of the implicitly method. Note that the implicitly method is defined as

def implicitly[T](implicit e: T): T = e

This method simply relies on the compiler to insert an implicit object of the correct type from the surrounding scope into the method call, and then returns it. We can do a bit better:

def context[C[_], T](implicit e: C[T]) = e

This allows us to define our add method as

def add[T: Numeric](x: T, y: T) = context.plus(x,y)

The context method type parameters Numeric and T are inferred from the scope! Unfortunately, there are circumstances in which this context method will not work. When a type parameter has multiple context bounds or there are multiple parameters with different context bounds, for example. We can resolve the latter problem with a slightly more complex version:

class Context[T] { def apply[C[_]]()(implicit e: C[T]) = e }
def context[T] = new Context[T]

This version requires us to specify the type parameter every time, but handles multiple type parameters.

def add[T: Numeric](x: T, y: T) = context[T]().plus(x,y)

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...