【问题标题】:Scala Pattern Matching pretty printedScala Pattern Matching 打印得很漂亮
【发布时间】:2015-06-24 21:25:35
【问题描述】:

是否有可能以某种方式将 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)
}

但是,如果我需要以 人类可读 形式(用于记录)的“我期望的”到“我所拥有的”的结果映射怎么办。说吧,

(case "foo")         -> Some(R1)
(case Int if _ > 10) -> Some(R2)
(case Boolean)       -> None

这可能吗?某些宏/元有效?

【问题讨论】:

  • 好主意。我不得不说更多评论......显然,替代方案是其他副作用。

标签: scala pattern-matching human-readable


【解决方案1】:

运行时没有什么可以很好地打印编译后的代码。

您可以编写一个宏来打印树的源代码并使用它吗?大多数宏教程都以用于打印源代码的宏开头——参见例如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:它是一种编译语言,并未针对代码本身的反射进行优化。

【讨论】:

    【解决方案2】:

    感谢您的回答。使用宏是有趣的一种选择。 但作为一种选择,解决方案可能是使用某种命名的部分函数。这个想法是给函数命名,所以在输出中你可以看到函数的名称而不是源代码。

    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))
    }
    

    【讨论】:

      猜你喜欢
      • 2011-01-27
      • 1970-01-01
      • 2021-12-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-22
      • 2014-08-13
      • 2016-07-07
      • 2014-05-19
      相关资源
      最近更新 更多