Scala 模式匹配漂亮的打印
Scala Pattern Matching pretty printed
是否有可能以某种方式将 PartialFunction(假设它总是只包含一种情况)编组为 人类可读的?
假设我们有 Any 类型的集合(消息:List[Any])
和使用模式匹配块定义的 PartialFuntion[Any, T] 的数量。
case object R1
case object R2
case object R3
val pm1: PartialFunction[Any, Any] = {
case "foo" => R1
}
val pm2: PartialFunction[Any, Any] = {
case x: Int if x > 10 => R2
}
val pm3: PartialFunction[Any, Any] = {
case x: Boolean => R3
}
val messages: List[Any] = List("foo", 20)
val functions = List(pm1, pm2)
然后我们可以找到与提供的PF和相关应用程序匹配的所有消息
val found: List[Option[Any]] = functions map { f =>
messages.find(f.isDefined).map(f)
}
但是如果我需要 'what I expect' 到 人类可读 形式(用于日志记录)中的“我所拥有的”的结果映射怎么办?说,
(case "foo") -> Some(R1)
(case Int if _ > 10) -> Some(R2)
(case Boolean) -> None
这可能吗?有些macro/meta作品?
运行时没有任何东西可以很好地打印编译后的代码。
您可以编写一个宏来打印树的源代码并使用它吗?大多数宏教程都以用于打印源代码的宏开始——参见例如http://www.warski.org/blog/2012/12/starting-with-scala-macros-a-short-tutorial/
也许:
// Given a partial function "pf", return the source code for pf
// as a string as well as the compiled, runnable function itself
def functionAndSource(pf: PartialFunction[Any, Any]): (String, PartialFunction[Any, Any]) = macro functionAndSourceImpl
def functionAndSourceImpl ...
val pm1: (String, PartialFunction[Any, Any]) = functionAndSource {
case "foo" => R1
}
这在 Scala 中永远不会那么容易或美好。
Scala 不是 Lisp 或 Ruby:它是一种编译语言,并且没有针对代码本身的反射进行优化。
感谢您的回答。使用宏是一个有趣的选择。
但作为一种选择,解决方案可能是使用一种命名的部分函数。这个想法是给函数命名,这样在输出中你可以看到函数的名称而不是源代码。
object PartialFunctions {
type FN[Result] = PartialFunction[Any, Result]
case class NamedPartialFunction[A,B](name: String)(pf: PartialFunction[A, B]) extends PartialFunction[A,B] {
override def isDefinedAt(x: A): Boolean = pf.isDefinedAt(x)
override def apply(x: A): B = pf.apply(x)
override def toString(): String = s"matching($name)"
}
implicit class Named(val name: String) extends AnyVal {
def %[A,B](pf: PartialFunction[A,B]) = new NamedPartialFunction[A, B](name)(pf)
}
}
那么接下来就可以如下使用了
import PartialFunctions._
val pm1: PartialFunction[Any, Any] = "\"foo\"" % {
case "foo" => R1
}
val pm2: PartialFunction[Any, Any] = "_: Int > 10" % {
case x: Int if x > 10 => R2
}
val pm3: PartialFunction[Any, Any] = "_: Boolean" % {
case x: Boolean => R3
}
val messages: List[Any] = List("foo", 20)
val functions = List(pm1, pm2)
val found: List[Option[(String, Any)]] = functions map { case f: NamedPartialFunction =>
messages.find(f.isDefined).map(m => (f.name, f(m))
}
是否有可能以某种方式将 PartialFunction(假设它总是只包含一种情况)编组为 人类可读的?
假设我们有 Any 类型的集合(消息:List[Any]) 和使用模式匹配块定义的 PartialFuntion[Any, T] 的数量。
case object R1
case object R2
case object R3
val pm1: PartialFunction[Any, Any] = {
case "foo" => R1
}
val pm2: PartialFunction[Any, Any] = {
case x: Int if x > 10 => R2
}
val pm3: PartialFunction[Any, Any] = {
case x: Boolean => R3
}
val messages: List[Any] = List("foo", 20)
val functions = List(pm1, pm2)
然后我们可以找到与提供的PF和相关应用程序匹配的所有消息
val found: List[Option[Any]] = functions map { f =>
messages.find(f.isDefined).map(f)
}
但是如果我需要 'what I expect' 到 人类可读 形式(用于日志记录)中的“我所拥有的”的结果映射怎么办?说,
(case "foo") -> Some(R1)
(case Int if _ > 10) -> Some(R2)
(case Boolean) -> None
这可能吗?有些macro/meta作品?
运行时没有任何东西可以很好地打印编译后的代码。
您可以编写一个宏来打印树的源代码并使用它吗?大多数宏教程都以用于打印源代码的宏开始——参见例如http://www.warski.org/blog/2012/12/starting-with-scala-macros-a-short-tutorial/
也许:
// Given a partial function "pf", return the source code for pf
// as a string as well as the compiled, runnable function itself
def functionAndSource(pf: PartialFunction[Any, Any]): (String, PartialFunction[Any, Any]) = macro functionAndSourceImpl
def functionAndSourceImpl ...
val pm1: (String, PartialFunction[Any, Any]) = functionAndSource {
case "foo" => R1
}
这在 Scala 中永远不会那么容易或美好。 Scala 不是 Lisp 或 Ruby:它是一种编译语言,并且没有针对代码本身的反射进行优化。
感谢您的回答。使用宏是一个有趣的选择。 但作为一种选择,解决方案可能是使用一种命名的部分函数。这个想法是给函数命名,这样在输出中你可以看到函数的名称而不是源代码。
object PartialFunctions {
type FN[Result] = PartialFunction[Any, Result]
case class NamedPartialFunction[A,B](name: String)(pf: PartialFunction[A, B]) extends PartialFunction[A,B] {
override def isDefinedAt(x: A): Boolean = pf.isDefinedAt(x)
override def apply(x: A): B = pf.apply(x)
override def toString(): String = s"matching($name)"
}
implicit class Named(val name: String) extends AnyVal {
def %[A,B](pf: PartialFunction[A,B]) = new NamedPartialFunction[A, B](name)(pf)
}
}
那么接下来就可以如下使用了
import PartialFunctions._
val pm1: PartialFunction[Any, Any] = "\"foo\"" % {
case "foo" => R1
}
val pm2: PartialFunction[Any, Any] = "_: Int > 10" % {
case x: Int if x > 10 => R2
}
val pm3: PartialFunction[Any, Any] = "_: Boolean" % {
case x: Boolean => R3
}
val messages: List[Any] = List("foo", 20)
val functions = List(pm1, pm2)
val found: List[Option[(String, Any)]] = functions map { case f: NamedPartialFunction =>
messages.find(f.isDefined).map(m => (f.name, f(m))
}