Question

For the data my app is using, I'm trying to give the data structure (which is a tree) a built-in traversal method, so that the caller can simply call it, providing functions to execute on the branches (Row) and leaves (Container). To allow for the output of any type T, not just a mapping over the tree data, I'm putting the onus on the caller to join the results from calling on subtrees, which they must do explicitly with the descend callback, which gets passed to the provided rowVisitor function. My problem is that I'm getting the following error:

Error:(45, 40) missing parameter type for expanded function
The argument types of an anonymous function must be fully known. (SLS 8.5)
Expected type was: T
      def descend(node: Content): T = {
                                      ^

Here is the code of my data structure and traverse method:

 trait Layout {
    def contentTree: Content
    def traverse[T](rowVisitor: (Row, Content => T) => T, containerVisitor: Container => T): T = {
      def descend(node: Content): T = {
        case Row(columns) => rowVisitor(Row(columns), descend)
        case Container(name) => containerVisitor(Container(name))
      }
      descend(contentTree)
    }
  }

  sealed trait Content
  case class Row(columns: Seq[Content]) extends Content
  case class Container(name: ContainerId) extends Content

Typically, this traverse function would be called in a template to render this content tree, and therefore T would be Play's Html or String.

Was it helpful?

Solution

Here is the correction, as per the comments:

def traverse[T](rowVisitor: (Row, Content => T) => T)(containerVisitor: Container => T): T = {
  def descend(node: Content): T = node match {
    case Row(columns) => rowVisitor(Row(columns), descend)
    case Container(name) => containerVisitor(Container(name))
  }
  descend(contentTree)
}

I also split the parameter list so that it can be called like:

layout.traverse[OutputType] { (row, descend) =>
    /* call descend on each column of the row, and then aggregate to OutputType */
} { container =>
    /* do something with container producing OutputType */
}

It seems to require an explicit type parameter specification or an explicit type on descend in the first anonymous function to compile. Not sure there's a way around that.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top