Question

I want to use the SYB implementation in the Shapeless library to write the following generic traversal function:

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)
}

Unfortunately, this code produces the following type error (using Shapeless 2.0.0-M1 and 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)

I assume, that the type parameter B needs to be constrained in some way, to make the implicit macros of the Shapeless library applicable, but I have no idea how.

Can such a traversal function be written using Shapeless?

Was it helpful?

Solution

You need to make an implicit witness for the everywhere combinator available in the body of your method,

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

Note that for reasons that I'm not able to fathom just at the moment, giving traverseAndManipulate an explicit result type of B causes the compiler to report a similar ambiguity. The result type is however correctly inferred as B. If you prefer to have an explicit result type, the following should be equivalent,

def traverseAndManipulate[B](expr: B)
  (implicit e: Everywhere[manipulate.type, B] { type Result = B }): B = e(expr)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top