如何在Scala中以递归方式应用隐式转换
我正在尝试编写一个转换库,用于将一些scala类型转换为HTML表示。比如说,我想执行如何在Scala中以递归方式应用隐式转换,scala,recursion,implicits,Scala,Recursion,Implicits,我正在尝试编写一个转换库,用于将一些scala类型转换为HTML表示。比如说,我想执行列表(1,2).toHtml并获得12,作为字符串 到目前为止,我已经编写了一组隐式转换,可以很好地检测结果类型并将正确的应用到html 让我举一个例子: object Conversions { implicit def fromIterable[A](l : Iterable[A]) = new Object { def toHtml = <ul> { l.map{ e =&
列表(1,2).toHtml
并获得1 2
,作为字符串
到目前为止,我已经编写了一组隐式转换,可以很好地检测结果类型并将正确的应用到html
让我举一个例子:
object Conversions {
implicit def fromIterable[A](l : Iterable[A]) = new Object {
def toHtml = <ul> { l.map{ e => <li>{ e }</li> } } </ul> toString
}
}
import Conversions._
对象转换{
隐式def fromIterable[A](l:Iterable[A])=新对象{
def toHtml={l.map{e=>- {e}
}
toString
}
}
导入转换_
有了这段代码,每当我询问编译器List(1,2).toHtml
时,我都会得到正确的转换。与任何其他Iterable
val一样
我的问题是如何递归地使用这个toHtml转换?因为如果我键入List(List(1,2),List(3,4)).toHtml
我想得到
,toHtml
转换递归地应用到输入的每个元素
我试图将toHtml
定义更改为deftohtml={l.map{e=>{li>{e.toHtml}
}
toString
,但该定义不起作用,因为编译器告诉我toHtml的值不是类型参数a的成员,这非常合理。
我知道我的问题可能存在于新对象{…}
中,我从fromIterable[A]
隐式定义返回,该隐式定义可能返回一个具有特征或其他内容的类。
我已经阅读了很多关于隐式的内容,但是我还没有弄明白,在不去参数化fromIterable签名和定义几个特定的例子的情况下,如何将这个递归地应用到HTML
转换,比如fromIterable(l:List[List[Any]])
或者类似的东西
你们能不能请我给我一些建议,如何实现它,我做错了什么
谢谢 首先让我们看看如何在没有隐式/对象和转换的情况下完成这项工作。我还删除了toString
,但可以随时添加它
def toHtml[A](l:Iterable[A]):scala.xml.Elem =
<ul> {l.map( _ match{
case e:Iterable[_] => <li>{toHtml(e)}</li>
case e => <li>{e}</li>
})}</ul>
// Exiting paste mode, now interpreting.
toHtml: [A](l: Iterable[A])scala.xml.Elem
scala> toHtml(List(List(1,2), List(3,4)))
res17: scala.xml.Elem = <ul> <li><ul> <li>1</li><li>2</li></ul></li><li><ul> <li>3</li><li>4</li></ul></li></ul>
def-toHtml[A](l:Iterable[A]):scala.xml.Elem=
{l.map({match{
案例e:Iterable[\u]=>- {toHtml(e)}
案例e=>- {e}
})}
//正在退出粘贴模式,现在正在解释。
toHtml:[A](l:Iterable[A])scala.xml.Elem
scala>toHtml(列表(列表(1,2),列表(3,4)))
res17:scala.xml.Elem=- 1
- 2
- 3
- 4
现在让我们重新包装所有内容,以回答您的问题:
object Conversions {
implicit def fromIterable[A](l : Iterable[A]):Object{def toHtml:xml.Elem} = new Object {
def toHtml:xml.Elem =
<ul>{l.map( _ match{
case e:Iterable[_] => <li>{e.toHtml}</li>
case e => <li>{e}</li>
})}</ul>
}
}
import Conversions._
对象转换{
隐式def fromIterable[A](l:Iterable[A]):对象{def toHtml:xml.Elem}=new对象{
def toHtml:xml.Elem=
{l.map({match{
案例e:Iterable[\u]=>- {e.toHtml}
案例e=>- {e}
})}
}
}
导入转换_
这将产生所需的结果:
scala> List(List(1,2), List(3,4)).toHtml
res3: scala.xml.Elem = <ul><li><ul><li>1</li><li>2</li></ul></li><li><ul><li>3</li><li>4</li></ul></li></ul>
scala>List(List(1,2),List(3,4)).toHtml
res3:scala.xml.Elem=- 1
- 2
- 3
- 4
几句话:
- 其次,我必须给出“fromIterable”方法的返回类型。我确信存在更好的解决方案,但我对隐式转换没有太多经验李>
- 最后,如果有人提出建议,我很乐意编辑我的答案。(或随意编辑)
您可以通过以下方式优雅、安全地解决此类问题:
然后:
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>
scala>打印机格式messy.toHtml
res1:字符串=
-
-
- a
-
-
- b
- c
-
- c
有关上述方法的更详细说明,请参见我的答案。非常感谢您,我想这正是我想要的!我仍然不能完全确定,但我会在我的工作中集成这一点,我会让你知道的。至于你得到的警告,你只需从签名中删除B,然后写案例e:Iterable[\u]=>…
,它就可以工作了。非常感谢!你的解决方案看起来更优雅,更接近我认为我必须做的事情。它使用了一个trait来定义某个类型将有一个toHtml方法,以便我可以应用它。然而,当我尝试您的代码时,我不知道如何将其应用于Iterables,而不仅仅是列表。。。有什么提示吗?将Markup
的类型参数设置为反变量,并在Markup
方法中将List
更改为Iterable
,就可以全部设置了。我会在有机会的时候更新答案。感谢迈尔斯·萨宾的帮助,这可以简化一点。感谢你的努力:)你可以编写类似于隐式def-mapMarkup[a:Markup,B:Markup]:Markup[Map[a,B]]
,但是你需要一个特征和对象来区分隐式的优先级(这样地图就不会被当作一个可数了)。今晚我会尝试更新答案。
val messy = List(List(List("a")), List(List("b", "c"), List("c")))
val printer = new xml.PrettyPrinter(80, 2)
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>