使用连词进行模式匹配(PatternA AND PatternB)
Scala 有一个语言功能来支持模式匹配中的析取(“模式替代”):
x match {
case _: String | _: Int =>
case _ =>
}
但是,如果审查满足 PatternA 和 PatternB (合取),我经常需要触发一个操作。
我创建了一个模式组合器'&&'这增加了这种能力。三句小诗让我想起了为什么我喜欢 Scala!
// Splitter to apply two pattern matches on the same scrutiny.
object && {
def unapply[A](a: A) = Some((a, a))
}
// Extractor object matching first character.
object StartsWith {
def unapply(s: String) = s.headOption
}
// Extractor object matching last character.
object EndsWith {
def unapply(s: String) = s.reverse.headOption
}
// Extractor object matching length.
object Length {
def unapply(s: String) = Some(s.length)
}
"foo" match {
case StartsWith('f') && EndsWith('f') => "f.*f"
case StartsWith('f') && EndsWith(e) && Length(3) if "aeiou".contains(e) => "f..[aeiou]"
case _ => "_"
}
讨论要点
- 是否有现有的方法可以做到这一点?
- 这种方法有问题吗?
- 这种方法可以创建任何其他有用的组合器吗? (例如,
Not
) - 这样的组合器是否应该添加到标准库中?
更新 我刚刚被问到编译器如何解释 case A &&住宿加早餐旅馆C。这些是中缀运算符模式(Scala 参考的第 8.1.9 节)。您还可以使用标准提取模式 (8.1.7) 将其表示为 &&(&&(A, B), C)。请注意表达式如何从左到右关联,就像普通的中缀运算符方法调用一样,例如
Boolean#&in
val b = true &&假&&是的`。
Scala has a language feature to support disjunctions in pattern matching ('Pattern Alternatives'):
x match {
case _: String | _: Int =>
case _ =>
}
However, I often need to trigger an action if the scrutiny satisfies PatternA and PatternB (conjunction.)
I created a pattern combinator '&&' that adds this capability. Three little lines that remind me why I love Scala!
// Splitter to apply two pattern matches on the same scrutiny.
object && {
def unapply[A](a: A) = Some((a, a))
}
// Extractor object matching first character.
object StartsWith {
def unapply(s: String) = s.headOption
}
// Extractor object matching last character.
object EndsWith {
def unapply(s: String) = s.reverse.headOption
}
// Extractor object matching length.
object Length {
def unapply(s: String) = Some(s.length)
}
"foo" match {
case StartsWith('f') && EndsWith('f') => "f.*f"
case StartsWith('f') && EndsWith(e) && Length(3) if "aeiou".contains(e) => "f..[aeiou]"
case _ => "_"
}
Points for discussion
- Is there an existing way to do this?
- Are there problems with this approach?
- Can this approach create any other useful combinators? (for example,
Not
) - Should such a combinator be added to the standard library?
UPDATE
I've just been asked how the compiler interprets case A && B && C
. These are infix operator patterns (Section 8.1.9 of the Scala Reference). You could also express this with standard extract patterns (8.1.7) as &&(&&(A, B), C).' Notice how the expressions are associated left to right, as per normal infix operator method calls like
Boolean#&&in
val b = true && false && true`.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我真的很喜欢这个技巧。我不知道有任何现有的方法可以做到这一点,而且我预计它不会出现任何问题——但这并没有多大意义。我想不出任何方法来创建
Not
。至于将其添加到标准库中......也许吧。但我觉得有点难。另一方面,如何说服 Scalaz 人员将其纳入其中?它看起来更像是他们自己的辖区。
I really like this trick. I do not know of any existing way to do this, and I don't foresee any problem with it -- which doesn't mean much, though. I can't think of any way to create a
Not
.As for adding it to the standard library... perhaps. But I think it's a bit hard. On the other hand, how about talking Scalaz people into including it? It looks much more like their own bailiwick.
一个可能的问题是模式匹配器生成的翻译臃肿。
以下是示例程序的翻译,使用
scalac -print
生成。即使-optimise
也无法简化if (true) "_" else throw new MatchError()
表达式。大型模式匹配已经生成了比单个方法合法的字节码更多的字节码,并且使用此组合器可能会放大该问题。
如果
&&
内置于语言中,也许翻译会更智能。或者,对-optimise
进行一些小的改进也可能有所帮助。A possible problem with this is the bloated translation that the pattern matcher generates.
Here is the translation of the sample program, generated with
scalac -print
. Even-optimise
fails to simplify theif (true) "_" else throw new MatchError()
expressions.Large pattern matches already generate more bytecode than is legal for a single method, and use of this combinator may amplify that problem.
If
&&
was built into the language, perhaps the translation could be smarter. Alternatively, small improvements to-optimise
could help.