使用`implicit def`制作类型类实例?

时间:2016-05-15 19:54:29

标签: scala typeclass

假设:

scala> trait Resource[A] { def f: String }
defined trait Resource

scala> case class Foo(x: String)
defined class Foo

然后暗示:

scala> implicit def fooToResource(foo: Foo): Resource[Foo] = 
        new Resource[Foo] { def f = foo.x }

以下作品:

scala> implicitly[Resource[Foo]](Foo("foo")).f
res2: String = foo

我定义了一个函数:

scala> def f[A](x: A)(implicit ev: Resource[A]): String = ev.f
f: [A](x: A)(implicit ev: Resource[A])String

但是,以下代码无法编译:

scala> f(Foo("foo"))
<console>:17: error: could not find implicit value for parameter ev: Resource[Foo]
       f(Foo("foo"))

其次,然后我尝试了:

scala> f2(Foo("bippy"))
<console>:17: error: could not find implicit value for parameter ev: Resource[Foo]
       f2(Foo("bippy"))
        ^

最后,我尝试了:

scala> def g(foo: Foo)(implicit ev: Resource[Foo]): String = ev.f
g: (foo: Foo)(implicit ev: Resource[Foo])String

scala> g(Foo("5"))
<console>:17: error: could not find implicit value for parameter ev: Resource[Foo]
       g(Foo("5"))
        ^

然而,它也失败了。我该如何解决f

2 个答案:

答案 0 :(得分:5)

好的Peter Neyens&#39;回答,这不是一个类型类,这是一个隐式转换,你应该避免 - 应该有一些警告,要求你导入scala.language.implicitConversions。

作为补充,这就是第一个implicitly起作用的原因:

隐含的只是:

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

当您在不提供参数的情况下编写implicitly[T] 时,它将在范围内查找隐式类型T并返回它。但是,您使用参数隐式调用(我相信没有正当理由这样做),因此它只会返回您的参数Foo("foo")Foo的实例。除非您明确声明T应该是资源[Foo]。如果您编写了类型归属,例如(Foo("foo"): Resource[Foo]),那么它的工作方式也会相同。 implicitly与此无关。

关键是Foo("foo")不是预期类型Resource[Foo],而只是Foo。编译器会拒绝它,除了此时,您在上面定义的隐式转换启动,并且您的Foo实例转换为Resource[Foo]。然后,您可以拨打f

接下来,您致电f(Foo("foo"))。有一个隐含参数,但是这一次,你不提供它。所以编译器会查找一个(虽然它第一次没有这样做),并且因为没有这样的实例,所以失败了。

答案 1 :(得分:4)

implicit def fooToResource不是类型类实例,但如果您提供Foo,则会返回一个,这就是以下行的原因:

implicitly[Resource[Foo]](Foo("foo")).f

解决方案是更改Resource.f函数以获取A类型的参数:

trait Resource[A] { 
  def f(a: A): String 
}

然后,您可以为Resource定义Foo类型类实例,如下所示:

case class Foo(x: String)

implicit val fooResource = new Resource[Foo] {
  def f(foo: Foo) = foo.x
}

我们可以重写f以使用更改后的Resource

def f[A](a: A)(implicit resA: Resource[A]): String = resA.f(a)

你需要做什么(我认为):

f(Foo("hello world")) // String = hello world