【发布时间】:2017-01-01 18:50:10
【问题描述】:
我有一些选项,当它们没有时,我不想运行我的转换函数。
当前处理选项的方法如下所示:
def writeOptionalXml[T](content: Option[T], mapFn: T => Xml): Xml =
content match {
case Some(c) => mapFn(c)
case None => NodeSeq.Empty
}
而且效果很好。但我还有其他不是选项但仍然可以为空的输入,例如空字符串、空 xml 节点或某些案例类。
我认为重构为类型类对我来说是一次很好的学习经历。经过大量代码争论后,我发现我需要使用上下文边界来处理选项类型,并认为我正在实现我的类型类梦想。
我卡住的地方是转换函数(在示例中被错误地命名为 mapFn)。 在没有选项的情况下,我想要方法签名: (内容:Option[T],mapFn:T => Xml):Xml 而在其他情况下: (输入:A,mapFn:A => Xml):Xml
我一直在努力更改类型签名,使用 [_] 尝试获得我想要的但无济于事。
我目前拥有的合成版本的代码,一点也不漂亮,看起来像这样:
import scala.annotation.implicitNotFound
object writableTypes extends App {
type Xml = String
@implicitNotFound("No member of type class in scope for ${T}")
trait WritableLike[A] {
def toXml[B](input: A, mapFn: ((_$1) forSome {type _$1}) => Xml): Xml
}
object WritableLike {
implicit object WritableLikeString extends WritableLike[String] {
override def toXml[B](input: String, mapFn: ((_$1) forSome {type _$1}) => Xml): Xml =
mapFn(input)
}
implicit def OptionFormat[T: WritableLike]: Object = new WritableLike[Option[T]] {
override def toXml[B](input: Option[T], mapFn: ((_$1) forSome {type _$1}) => Xml): Xml =
mapFn(input.get)
}
def writeXml[X](input: X, mapFn: ((_$1) forSome {type _$1}) => Xml )(implicit ev: WritableLike[X]): Xml =
ev.toXml[X](input, mapFn)
}
println(WritableLike.writeXml(Option(SomeCaseClass(5)), transformToXml))
case class SomeCaseClass(content: Int) { def someMethod = ""}
def transformToXml[T](input: SomeCaseClass): String = input.someMethod
}
不幸的是,这没有编译,因为在这个方法调用中 WritableLike.writeXml(Option(SomeCaseClass(5)), transformToXml)
函数 transformToXml 不满足所需的方法签名。
我已经尝试了很多这种排列,但找不到解决方案,否则很优雅。
我确信有一些简单的方法可以通过将所有内容都设置为选项来解决它,但我更感兴趣的是找到使其真正通用的解决方案。
我不确定我是否已经很好地解释了这一点,这是我第一次尝试编写类型类,我认为这很简单,但我试图解决的特定问题似乎有一些额外的复杂性。
如果有人对使用 Scala 类型系统的泛型编程有更深入的了解,我将不胜感激。
谢谢
【问题讨论】:
标签: scala optional typeclass higher-order-functions existential-type