vas*_*ase 3 recursion scala implicits
我正在尝试编写一个转换库,用于将一些scala类型转换为HTML表示.比方说,我想要执行List(1,2).toHtml和获取<ul><li>1</li><li>2</li></ul>,作为一个String.
到目前为止,我已经编写了一组隐式转换,它们可以很好地检测结果类型并应用正确的结果toHtml.
让我展示一个示例:
object Conversions {
implicit def fromIterable[A](l : Iterable[A]) = new Object {
def toHtml = <ul> { l.map{ e => <li>{ e }</li> } } </ul> toString
}
}
import Conversions._
Run Code Online (Sandbox Code Playgroud)
有了这段代码,每当我问编译器时,List(1,2).toHtml我得到正确的转换.就像任何其他Iterableval一样.
我的问题和问题是如何递归地使用这个toHtml转换?因为如果我输入List( List(1,2), List(3,4) ).toHtml我想要获得<ul> <li><ul><li>1</li><li>2</li></ul></li> <li><ul><li>3</li><li>4</li></ul></li> </ul>,toHtml转换应用递归地应用于输入的每个元素Iterable.
我试图将toHtml定义更改为def toHtml = <ul> { l.map{ e => <li>{ e.toHtml }</li> } } </ul> toString无效,因为编译器告诉我value toHtml is not a member of type parameter A哪个是完全合理的.
我知道我的问题可能存在于new Object { ... }我从fromIterable[A]隐式定义返回,它应该可能返回一个具有特征或类别的类.
我已经尝试过很多关于implicits的阅读但是我还没想到它能够递归地应用这个toHtml转换而不去解析fromIterable签名并定义几个特定的情况,比如类似的fromIterable(l : List[List[Any]])东西......
你能不能请我给我一些关于如何实现它以及我做错了什么的建议?
谢谢!
您可以使用类型类以优雅且类型安全的方式解决此类问题:
// Evidence that we can turn an A into some XML:
trait Markup[-A] { def toHtml(a: A): xml.Node }
def baseMarkup[A] = new Markup[A] { def toHtml(a: A) = xml.Text(a.toString) }
implicit def markup[A](implicit m: Markup[A] = baseMarkup[A]) =
new Markup[Iterable[A]] {
def toHtml(c: Iterable[A]) = <ul>
{ c.map(child => <li>{ m.toHtml(child) }</li>) }
</ul>
}
implicit def fromMarkup[A](a: A)(implicit m: Markup[A]) = new {
def toHtml = m toHtml a
}
Run Code Online (Sandbox Code Playgroud)
这适用于任意深度的嵌套列表:
val messy = List(List(List("a")), List(List("b", "c"), List("c")))
val printer = new xml.PrettyPrinter(80, 2)
Run Code Online (Sandbox Code Playgroud)
然后:
scala> printer format messy.toHtml
res1: String =
<ul>
<li>
<ul>
<li>
<ul>
<li>a</li>
</ul>
</li>
</ul>
</li>
<li>
<ul>
<li>
<ul>
<li>b</li>
<li>c</li>
</ul>
</li>
<li>
<ul>
<li>c</li>
</ul>
</li>
</ul>
</li>
</ul>
Run Code Online (Sandbox Code Playgroud)
见我的答案在这里为上述方法更详细的解释.