Is there a way to implicitly convert an implicit parameter in Scala?

依然范特西╮ 提交于 2019-12-24 03:27:49

问题


Is there a way to make this work (Scala 2.8.1):

class A
class B
def f(implicit b: B) {}
implicit val a = new A
implicit def aToB(a: A) = new B
f(a) // works ok
f // error: could not find implicit value for parameter b: B

Actually my problem is with Lift's (2.2) dependency injection, i'm trying to convert Vendor[T] to T and implicitly require it in a class constructor without adding imports after each val:

object DependencyFactory extends Factory {
  implicit def vendorToVal[T](vendor: Vendor[T]): T = vendor.vend

  implicit val db = new FactoryMaker[DbAccess](Model) {}
  //uncommenting the following line makes it work, but can we avoid it? 
  //import db._
  implicit val userStore = new FactoryMaker[UserStore](new UserStore) {}
}

Where UserStore is:

class UserStore(implicit db: DbAccess)

Am i doing something wrong?

UPDATE

Thanks to Easy Angel for answering the first part. But it doesn't solve my Lift DI problem because it turns out that there is an opposite conversion in scope (from T to Vendor[T]) and having those both leads to 'error: diverging implicit expansion'.

Can it be solved?

UPDATE2

Wow one more problem after previous: having a conversion from some Container[T] to T with implicit instance of Container[U] in scope and a function with implicit parameter U leads to 'diverging implicit expansion' too:

class A
case class Vendor[T](v: T)
def f(implicit a: A) {}
implicit val vendor = Vendor(new A)
implicit def vendorToVal[T](implicit v: Vendor[T]) = v.v
f

Any hints?


回答1:


You almost made it. You only need to declare a implicit:

implicit def aToB(implicit a: A) = new B

In this case compiler tries to find some implicit B for the first implicit argument of f and it finds aToB. Than compiler ties to satisfy aToB's requirement (implicit a: A) and finds your implicit val a.




回答2:


This is probably not the best and most concise solution to this problem. But it was interesting for me whether it's technically possible to achieve what you want. I tried to reproduce all involved classes as close as possible without Lift... and here is one of the possible solutions using view bounds:

class DbAccess
class UserStore[T](implicit db: T, ev: T => DbAccess)

class Vendor[T] (val vend: T)
class FactoryMaker[T] (vend: T) extends Vendor[T](vend)

implicit def vendorToVal[T](vendor: Vendor[T]) = vendor.vend

implicit val db: Vendor[DbAccess] = new FactoryMaker[DbAccess](new DbAccess) {}
implicit val userStore = new FactoryMaker[UserStore[Vendor[DbAccess]]](new UserStore) {}

In this case UserStore knows fact, that T is not DbAccess, but it also knows that T can be viewed and used as T.


Edit

About your second example (in comment). This simple workaround comes to my mind:

class A
class B
trait HighPrio

def f(implicit b: B) {}

implicit val a = new A with HighPrio

implicit def aToB(implicit a: A with HighPrio) = new B;
implicit def bToA(implicit b: B) = new A;

f

... not sure whether it will work in your Lift case.



来源:https://stackoverflow.com/questions/5204928/is-there-a-way-to-implicitly-convert-an-implicit-parameter-in-scala

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!