【发布时间】:2012-04-07 15:14:33
【问题描述】:
好的,公平的警告:这是我上周的ridiculous question 的后续行动。虽然我认为这个问题并不那么荒谬。无论如何,这里是:
上一个荒谬的问题:
假设我有一些基本特征T 和子类A、B 和C,例如,我可以声明一个集合Seq[T],它可以包含A、B 类型的值和C。让子类型更加明确,让我们使用Seq[_ <: T] 类型绑定语法。
现在假设我有一个类型类TC[_],其成员为A、B 和C(其中“成员”表示编译器可以在隐式范围内找到一些TC[A] 等)。与上面类似,我想声明一个Seq[_ : TC] 类型的集合,使用上下文绑定语法。
这不是合法的 Scala,尝试模仿可能会让您觉得自己像 bad person。请记住,上下文绑定语法(如果使用得当!)为正在定义的类或方法脱糖到一个隐式参数列表中,这在这里没有任何意义。
新前提:
所以让我们假设类型类实例(即隐式值)是不可能的,在这种情况下我们需要使用隐式转换。我有一些类型V(“v”应该代表“view”fwiw),以及A => V、B => V 和C => V 范围内的隐式转换。现在我可以填充Seq[V],尽管A、B 和C 在其他方面不相关。
但是,如果我想要一组可以隐式转换为视图V1 和V2 的东西怎么办?我不能说Seq[V1 with V2],因为我的隐式转换不会以那种方式神奇地聚合。
隐式转换的交集?
我这样解决了我的问题:
// a sort of product or intersection, basically identical to Tuple2
final class &[A, B](val a: A, val b: B)
// implicit conversions from the product to its member types
implicit def productToA[A, B](ab: A & B): A = ab.a
implicit def productToB[A, B](ab: A & B): B = ab.b
// implicit conversion from A to (V1 & V2)
implicit def viewsToProduct[A, V1, V2](a: A)(implicit v1: A => V1, v2: A => V2) =
new &(v1(a), v2(a))
现在我可以像老板一样写Seq[V1 & V2]了。例如:
trait Foo { def foo: String }
trait Bar { def bar: String }
implicit def stringFoo(a: String) = new Foo { def foo = a + " sf" }
implicit def stringBar(a: String) = new Bar { def bar = a + " sb" }
implicit def intFoo(a: Int) = new Foo { def foo = a.toString + " if" }
implicit def intBar(a: Int) = new Bar { def bar = a.toString + " ib" }
val s1 = Seq[Foo & Bar]("hoho", 1)
val s2 = s1 flatMap (ab => Seq(ab.foo, ab.bar))
// equal to Seq("hoho sf", "hoho sb", "1 if", "1 ib")
从String 和Int 到类型Foo & Bar 的隐式转换发生在填充序列时,然后从Foo & Bar 到Foo 和Bar 的隐式转换发生在调用foobar.foo 和foobar.bar.
当前荒谬的问题:
- 以前有没有人在任何地方实现过这种模式,还是我是第一个这样做的白痴?
- 有没有一种我盲目错过的更简单的方法?
- 如果不是,那么我将如何实现更通用的管道,以便我可以写
Seq[Foo & Bar & Baz]?这似乎是HList的工作...... -
额外的超级组合奖励:在实现更通用的管道时,我可以将类型限制为唯一吗?比如我想禁止
Seq[Foo & Foo]。
失败的附录:
My latest attempt (gist)。不可怕,但有两件事我不喜欢那里:
-
Seq[All[A :: B :: C :: HNil]]语法(我希望HList内容不透明,并且更喜欢Seq[A & B & C]) - 转换所需的显式类型注释 (
abc[A].a)。似乎您可以进行类型推断或隐式转换,但不能同时进行...无论如何,我无法弄清楚如何避免它。
【问题讨论】:
-
这个问题与“额外的超级连击奖励”有关:enforce type difference
-
我不确定我是否看到
HList与您要执行的操作之间的联系.... HList 是一个列表,其类型维护有关组成元素的类型信息,而听起来您想要一个列表,其中每个组成部分都符合某些固定的类型集。 -
@AaronNovstrup 我正在尝试使用
HList之类的东西作为我定义的固定 2-arity&[A, B]类的任意替代品。我的目标是拥有最像我的Seq[A & B]的东西,其中集合的元素可以同时被视为A和B,但同样适用于任意数量的类型。 -
@AaronNovstrup ...虽然我想知道使用类似 Miles 的 unboxed union type 而不是
HList的技术来编码是否更自然。 -
这与您的问题并不真正相关,但我只想指出
Seq[_ <: T]与Seq[T]不同。Seq[_ <: T]是存在的。