如何将类型类模式与子类型相结合? [英] How can I combine the typeclass pattern with subtyping?

查看:44
本文介绍了如何将类型类模式与子类型相结合?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我在 Scala 中使用 typeclass 模式.这是我如何制作 C 类类型类 Foo 的一部分:

Suppose I'm using the typeclass pattern in Scala. Here's how I make a class C part of the typeclass Foo:

Welcome to Scala version 2.9.0.1 (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_26).

scala> trait Foo[T] { def foo(t: T) }
defined trait Foo

scala> def foo[T : Foo](t: T) { implicitly[Foo[T]].foo(t) }
foo: [T](t: T)(implicit evidence$1: Foo[T])Unit

scala> class C
defined class C

scala> foo(new C)
<console>:11: error: could not find implicit value for evidence parameter of type Foo[C]
       foo(new C)
          ^

scala> implicit object FooC extends Foo[C] { override def foo(c: C) { println("it's a C!") } }
defined module FooC

scala> foo(new C)
it's a C!

到目前为止一切顺利.但是假设我有 C 的子类 D,并且我希望 D 的实例也在"类型类中:

So far so good. But suppose I have a subclass D of C, and I want instances of D to be "in" the typeclass too:

scala> class D extends C
defined class D

scala> foo(new D)
<console>:13: error: could not find implicit value for evidence parameter of type Foo[D]
       foo(new D)
          ^

哦!如何在不必为 D 显式提供类型类实例的情况下完成这项工作?

Doh! How do I make this work without having to explicitly provide a typeclass instance for D?

推荐答案

对此有不同的可能解决方案,这取决于我是想仅针对 C 解决问题,还是我想解决整个类型类的问题.

There are different possible solutions for this, depending on whether I want to fix the problem only for C, or whether I want to fix the problem for the entire typeclass.

仅对于 C,而不是 implicit object FooC ... 我们说:

For C only, instead of implicit object FooC ... we say:

implicit def CIsFoo[T <: C]: Foo[T] =
  new Foo[T] { override def foo(t: T) { println("it's a C!") } }

要修复所有 Foo,请使其逆变:

To fix all of Foo, make it contravariant:

trait Foo[-T] { def foo(t: T) }

或者如果由于某种原因您不能或不想这样做,您可以将 def foo... 替换为:

Or if for some reason you can't or don't want to do that, you can replace def foo... with:

def foo[T](t: T)(implicit foo: Foo[_ >: T]) =
  foo.foo(t)

(感谢#scala 居民 Daniel Sobral 和 Stefan Zeiger 的帮助.)

(Thanks to #scala denizens Daniel Sobral and Stefan Zeiger for their help.)

更新 2011 年 9 月 20 日包含我错过的make Foo逆变"解决方案

UPDATED Sep 20 2011 to include the "make Foo contravariant" solution, which I missed

这篇关于如何将类型类模式与子类型相结合?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆