带参数的Scala提取器

标签 scala pattern-matching

Scala中是否有一种语法允许提取程序采用自定义参数?这个例子有些人为。假设我有一个关于整数的二进制搜索树,并且如果当前值可以被某些自定义值整除,我想在当前节点上进行匹配。

使用F#事件模式,我可以执行以下操作:

type Tree =
    | Node of int * Tree * Tree
    | Empty  

let (|NodeDivisibleBy|_|) x t =
    match t with
    | Empty -> None
    | Node(y, l, r) -> if y % x = 0 then Some((l, r)) else None

let doit = function
    | NodeDivisibleBy(2)(l, r) -> printfn "Matched two: %A %A" l r
    | NodeDivisibleBy(3)(l, r) -> printfn "Matched three: %A %A" l r
    | _ -> printfn "Nada"

[<EntryPoint>]
let main args =
    let t10 = Node(10, Node(1, Empty, Empty), Empty)
    let t15 = Node(15, Node(1, Empty, Empty), Empty)

    doit t10
    doit t15

    0

在Scala中,我可以做类似的事情,但不完全是我想要的:
sealed trait Tree
case object Empty extends Tree
case class Node(v: Int, l: Tree, r: Tree) extends Tree

object NodeDivisibleBy {
  def apply(x: Int) = new {
    def unapply(t: Tree) = t match { 
      case Empty => None
      case Node(y, l, r) => if (y % x == 0) Some((l, r)) else None
    }
  }
}

def doit(t: Tree) {
  // I would prefer to not need these two lines.
  val NodeDivisibleBy2 = NodeDivisibleBy(2)
  val NodeDivisibleBy3 = NodeDivisibleBy(3)
  t match { 
    case NodeDivisibleBy2(l, r) => println("Matched two: " + l + " " + r)
    case NodeDivisibleBy3(l, r) => println("Matched three: " + l + " " + r)
    case _ => println("Nada")
  }
}

val t10 = Node(10, Node(1, Empty, Empty), Empty)
val t15 = Node(15, Node(1, Empty, Empty), Empty)

doit(t10)
doit(t15)

如果可以,那就太好了:
case NodeDivisibleBy(2)(l, r) => println("Matched two: " + l + " " + r)
case NodeDivisibleBy(3)(l, r) => println("Matched three: " + l + " " + r)

但这是一个编译时错误:预期为'=>'但找到了'('。

有什么想法吗?

最佳答案

the spec:

   SimplePattern ::= StableId ‘(’ [Patterns] ‘)’

An extractor pattern x(p1, ..., pn) where n ≥ 0 is of the same syntactic form as a constructor pattern. However, instead of a case class, the stable identifier x denotes an object which has a member method named unapply or unapplySeq that matches the pattern.



和:

A stable identifier is a path which ends in an identifier.



即不是像NodeDivisibleBy(2)这样的表达式。

所以不,这不可能在Scala中以任何直接的方式实现,而且我个人认为还好:必须编写以下内容(通过我可能会在NodeDivisibleBy对象中定义并导入的方式):
val NodeDivisibleBy2 = NodeDivisibleBy(2)
val NodeDivisibleBy3 = NodeDivisibleBy(3)

对于不必在case子句中解释任意表达式而增加的可读性而言,这是一个很小的代价。

关于带参数的Scala提取器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13241939/

相关文章:

haskell - 为什么我不能在 Haskell 中的串联函数 (++) 上进行模式匹配?

sorting - 快速汉明距离计分

json - 如何在 Play 框架 v2.x 中不使用 withJsonBody 为 FakeRequest 发送 json 字符串主体?

scala - sbt Project name must be valid Scala identifier 创建新项目时出错

scala:将 None 设置为 Option

c# - 当单词出现的顺序或次数不重要时,两个字符串之间的最佳匹配?

scala - 类型类和包对象的奇怪隐式解析行为

java - Heroku JVM 调优

haskell - 为什么在枚举所有情况时通配符匹配不起作用?

java - 非迭代的 URL 匹配