score:2
First for a disclaimer: if you're planning to use this in real code, I think it's almost certainly a bad idea. It'd be better to try to use Shapeless to do what you're trying to do directly rather than going through this type-unsafe representation. But it's a fun problem, so here goes.
(Oh, and another disclaimer: this implementation is off the top of head and there may be nicer ways to accomplish this.)
First for a helper type class (note that all of the code in the three sections below will need to be defined together—you can use :paste
if you're in a REPL):
import scalaz.{ Show, Tree, \/ }, scalaz.syntax.either._
import shapeless._, ops.hlist.ToTraversable
trait TreeifyCc[A, C] {
def apply(tf: Treeify[A], c: C): Tree[Class[_] \/ Any]
}
trait LowPriorityTreeifyCc {
implicit def singleMemberTreeifyCc[A, C, R <: HList, X](implicit
gen: Generic.Aux[C, R],
ev: R <:< (X :: HNil)
): TreeifyCc[A, C] = new TreeifyCc[A, C] {
def apply(tf: Treeify[A], c: C): Tree[Class[_] \/ Any] = Tree.Node(
c.getClass.left,
Stream(Tree.Leaf(ev(gen.to(c)).head.right))
)
}
}
object TreeifyCc extends LowPriorityTreeifyCc {
implicit def recursiveTreeifyCc[A, C, R <: HList](implicit
gen: Generic.Aux[C, R],
ts: ToTraversable.Aux[R, Stream, A]
): TreeifyCc[A, C] = new TreeifyCc[A, C] {
def apply(tf: Treeify[A], c: C): Tree[Class[_] \/ Any] =
Tree.Node(c.getClass.left, ts(gen.to(c)).map(tf(_)))
}
}
And another helper type class:
trait TreeifyAdt[A, C] {
def apply(tf: Treeify[A], c: C): Tree[Class[_] \/ Any]
}
object TreeifyAdt {
implicit def cnilTreeifyAdt[A]: TreeifyAdt[A, CNil] =
new TreeifyAdt[A, CNil] {
def apply(tf: Treeify[A], c: CNil): Tree[Class[_] \/ Any] =
sys.error("impossible")
}
implicit def cconsAdt[A, H, T <: Coproduct](implicit
cc: TreeifyCc[A, H],
ta: TreeifyAdt[A, T]
): TreeifyAdt[A, H :+: T] = new TreeifyAdt[A, H :+: T] {
def apply(tf: Treeify[A], c: H :+: T): Tree[Class[_] \/ Any] = c match {
case Inl(h) => cc(tf, h)
case Inr(t) => ta(tf, t)
}
}
}
And the type class we actually care about:
trait Treeify[A] {
def apply(a: A): Tree[Class[_] \/ Any]
}
object Treeify {
implicit def treeifyAdt[A, R <: Coproduct](implicit
gen: Generic.Aux[A, R],
adt: TreeifyAdt[A, R]
): Treeify[A] = new Treeify[A] {
def apply(a: A): Tree[Class[_] \/ Any] = adt(this, gen.to(a))
}
def toTree[A](a: A)(implicit tf: Treeify[A]): Tree[Class[_] \/ Any] = tf(a)
}
And we can use it like this:
scala> val ex: Ex = Add(Lit(0), Add(Lit(1), Var('a')))
ex: Ex = Add(Lit(0),Add(Lit(1),Var(a)))
scala> Treeify.toTree(ex).drawTree(scalaz.Show.showFromToString)
res0: String =
"-\/(class Add)
|
+- -\/(class Lit)
| |
| `- \/-(0)
|
`- -\/(class Add)
|
+- -\/(class Lit)
| |
| `- \/-(1)
|
`- -\/(class Var)
|
`- \/-(a)
"
This will work for any ADT where all of the leaves either have a single member or one or more recursive members.
Source: stackoverflow.com
Related Query
- Converting a case class hierarchy to scalaz.Tree with Shapeless
- Shapeless - turn a case class into another with fields in different order
- Converting Map[String,Any] to a case class using Shapeless
- Converting a tuple of options to an option of tuple with Scalaz or Shapeless
- Get case class field's name and type with shapeless
- How to get Scala case class fields and values as (String, String) with Shapeless or Macro
- Issue converting scala case class to spark dataset with embedded options that wrap monads
- Check case class with Option fields to make sure all of them are None using Shapeless HList
- How to get map of field names to field types of case class with shapeless
- Converting one case class to another that is similar with additional parameter in Scala
- Shapeless extensible records with case class type as keys
- Scala: extend subset of case class hierarchy with trait
- Define common copy for a class hierarchy with many case classes
- Using Spark converting nested json with optional fields to Scala case class not working
- Create "enriched" type from case class with Shapeless in Scala
- How to update a mongo record using Rogue with MongoCaseClassField when case class contains a scala Enumeration
- What is *so* wrong with case class inheritance?
- Scala case class extending Product with Serializable
- case class copy 'method' with superclass
- Scala. Can case class with one field be a value class?
- Weird behavior trying to convert case classes to heterogeneous lists recursively with Shapeless
- Read CSV in Scala into case class instances with error handling
- Converting nested case classes to nested Maps using Shapeless
- Lift-json extract json with 'type' field into a case class
- How to write a Play JSON writes converter for a case class with a single nullable member
- How to shapeless case classes with attributes and typeclasses?
- Update case class from incomplete JSON with Argonaut or Circe
- Scala copy case class with generic type
- Scala wont pattern match with java.lang.String and Case Class
- Custom Json Writes with combinators - not all the fields of the case class are needed
More Query from same tag
- How can I do IOException.class in scala with junit?
- Scala returning coordinate as tuple
- Json4s alternative api with scala generics / type members
- Fill in missing weeks within a given date interval in Spark (Scala)
- Scala Slick: How to do an except join (left outer join with is null)?
- Looking for Javacpp FFMPEG CustomIO Example
- Play Framework stay on same page then changing language
- How do I make sbt include non-Java sources to published artifact?
- How to return model query result as JSON in scala play framework
- Scala: Collect values defined in hashmap passed by a list argument
- How to read parquet file from S3 using akka streams or alpakka
- What is the idiomatic way of making a String from two Int in Scala?
- How to use nested generics in scala
- Creating immutable instances and modifying copies in an idiomatic way
- Filter RDD's csv with JSON field using Spark/Scala
- Proper way to handle error on ConfigFactory Load
- serving hierarchical static content with spray
- Filter condition using filtered value
- How do you print the select statements for the following Slick queries?
- Inferring type parameters
- Scala polymorphism - covariant and type bound
- How to write scala matcher for class?
- Usefulness of Child Trait?
- How can Akka Alppaka Producer Integration with Akka HTTP
- Need to apply correlation matrix on the sql query on spark dataframe
- How to send email with attached file in scala and play framework (2.3.9) using activator?
- Parsing primitive types in Circe
- How to iterate scala map?
- Typesafe play-oauth2-scala example
- is it possible to load scala classes "dynamic"? (like pythons import_module)