summaryrefslogtreecommitdiff
path: root/src/library/scala/MatchingStrategy.scala
blob: 4eaf7852b836188cff2c802ac469c19037e75cd2 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package scala

abstract class MatchingStrategy[M[+x]] {
  def zero: M[Nothing]
  def one[T](x: T): M[T]
  def guard[T](cond: Boolean, then: => T): M[T] // = if(cond) one(then) else zero
  def altFlatMap[T, U](f: T => M[U])(a: M[U], b: M[T]): M[U] // = a orElse b.flatMap(f) -- can't easily&efficiently express M[T] should have flatMap and orElse
  def runOrElse[T, U](x: T)(f: T => M[U]): U
  def isSuccess[T, U](x: T)(f: T => M[U]): Boolean

  // find the first alternative to successfully flatMap f
  // to avoid code explosion due to alternatives
  def or[T, U](f: T => M[U], alts: M[T]*) = (alts foldLeft (zero: M[U]))(altFlatMap(f))

  def caseResult[T](x: T): M[T] = one(x) // used as a marker to distinguish the RHS of a case (case pat => RHS) and intermediate successes
  // when deriving a partial function from a pattern match, we need to
  // distinguish the RHS of a case, which should not be evaluated when computing isDefinedAt,
  // from an intermediate result (which must be computed)

}

object MatchingStrategy {
  implicit object OptionMatchingStrategy extends MatchingStrategy[Option] {
    type M[+x] = Option[x]
    @inline def guard[T](cond: Boolean, then: => T): M[T] = if(cond) Some(then) else None
    @inline def zero: M[Nothing] = None
    @inline def one[T](x: T): M[T] = Some(x)
    @inline def altFlatMap[T, U](f: T => M[U])(a: M[U], b: M[T]): M[U] = a orElse b.flatMap(f)
    @inline def runOrElse[T, U](x: T)(f: T => M[U]): U = f(x) getOrElse (throw new MatchError(x))
    @inline def isSuccess[T, U](x: T)(f: T => M[U]): Boolean = !f(x).isEmpty
  }
}