带有Shapeless的Scala结构编程:如何正确使用SYB实现?

时间:2013-11-01 12:31:45

标签: scala generic-programming shapeless

我想使用SYB中的Shapeless library实现来编写以下通用遍历函数:

class Data

// Perform the desired manipulation on the given data 
object manipulate extends ->((data: Data) => data)

def traverseAndManipulate[B](expr: B): B = {
  everywhere(manipulate)(expr)
}

不幸的是,此代码产生以下类型错误(使用Shapeless 2.0.0-M1和Scala 2.10.2):

type mismatch;
[error]  found   : shapeless.EverywhereAux[SYB.manipulate.type]
[error]  required: ?{def apply(x$1: ? >: B): ?}
[error] Note that implicit conversions are not applicable because they are ambiguous:
[error]  both method inst1 in trait PolyInst of type [A](fn: shapeless.Poly)(implicit cse: fn.ProductCase[shapeless.::[A,shapeless.HNil]])A => cse.Result
[error]  and macro method apply in object Poly of type (f: Any)shapeless.Poly
[error]  are possible conversion functions from shapeless.EverywhereAux[SYB.manipulate.type] to ?{def apply(x$1: ? >: B): ?}
[error]     everywhere(manipulate)(expr)

我假设,类型参数B需要以某种方式进行约束,以使Shapeless库的隐式宏适用,但我不知道如何。

可以使用Shapeless编写这样的遍历函数吗?

1 个答案:

答案 0 :(得分:3)

您需要为方法正文中可用的任何组合器做一个隐含的见证,

def traverseAndManipulate[B](expr: B)
  (implicit e: Everywhere[manipulate.type, B]) = everywhere(manipulate)(expr)

请注意,由于我目前无法理解的原因,给traverseAndManipulate显式结果类型B会导致编译器报告类似的歧义。但是,结果类型正确推断为B。如果您希望具有显式结果类型,则以下内容应相同,

def traverseAndManipulate[B](expr: B)
  (implicit e: Everywhere[manipulate.type, B] { type Result = B }): B = e(expr)