使用Applicative Functor匹配3个Scala Regex中的至少一个

Ral*_*lph 4 regex scala scalaz applicative

我有三个Scala正则表达式,我需要测试它们是否与给定的String匹配.

我知道我可以做以下事情:

val matches = R1.findFirstIn(myString).isDefined ||
              R2.findFirstIn(myString).isDefined ||
              R3.findFirstIn(myString).isDefined
Run Code Online (Sandbox Code Playgroud)

但我相信有一种方法可以使用Scalaz库中的Applicative Functor或Monad来实现.

如何才能做到这一点?

Tra*_*own 5

这是"第一个"(或"最后")monoid实例下的总和Option.在Scalaz 7中你可以写:

import scalaz._, Scalaz._

val R1 = "[a-c]".r
val R2 = "[d-f]".r
val R3 = "[g-i]".r

val m: Option[String] = List(R1, R2, R3).map(_.findFirstIn("test").first).suml
Run Code Online (Sandbox Code Playgroud)

或者,或者:

val r1m = R1.findFirstIn("test").first
val r2m = R2.findFirstIn("test").first
val r3m = R3.findFirstIn("test").first

val m: Option[String] = r1m |+| r2m |+| r3m
Run Code Online (Sandbox Code Playgroud)

请注意,这两个解决方案都返回匹配本身,isDefined如果您想要与实现中的行为相同,您当然可以调用它.


作为旁注,|+|这里的第一个monoid实例只是orElse在标准库中,所以你可以在没有Scalaz的情况下简洁地编写它:

List(R1, R2, R3).map(_.findFirstIn("test")).reduce(_ orElse _)
Run Code Online (Sandbox Code Playgroud)

这当然不是反对使用Scalaz的论据,因为它可以让我们更清晰地捕获抽象,并提供一种优雅的方式来改变关于Some是返回第一个还是最后一个的行为.

  • 我更喜欢`Seq(R1,R2,R3).exists(_.findFirstIn("test").isDefined)`因为它会在找到第一个匹配时停止,所以效率更高. (3认同)