1
|
|
package algebra
|
2
|
|
|
3
|
|
/**
|
4
|
|
* Priority is a type class for prioritized implicit search.
|
5
|
|
*
|
6
|
|
* This type class will attempt to provide an implicit instance of `P`
|
7
|
|
* (the preferred type). If that type is not available it will
|
8
|
|
* fallback to `F` (the fallback type). If neither type is available
|
9
|
|
* then a `Priority[P, F]` instance will not be available.
|
10
|
|
*
|
11
|
|
* This type can be useful for problems where multiple algorithms can
|
12
|
|
* be used, depending on the type classes available.
|
13
|
|
*/
|
14
|
|
sealed trait Priority[+P, +F] {
|
15
|
|
|
16
|
|
import Priority.{Preferred, Fallback}
|
17
|
|
|
18
|
|
def fold[B](f1: P => B)(f2: F => B): B =
|
19
|
|
this match {
|
20
|
0
|
case Preferred(x) => f1(x)
|
21
|
0
|
case Fallback(y) => f2(y)
|
22
|
|
}
|
23
|
|
|
24
|
|
def join[U >: P with F]: U =
|
25
|
0
|
fold(_.asInstanceOf[U])(_.asInstanceOf[U])
|
26
|
|
|
27
|
|
def bimap[P2, F2](f1: P => P2)(f2: F => F2): Priority[P2, F2] =
|
28
|
|
this match {
|
29
|
0
|
case Preferred(x) => Preferred(f1(x))
|
30
|
0
|
case Fallback(y) => Fallback(f2(y))
|
31
|
|
}
|
32
|
|
|
33
|
|
def toEither: Either[P, F] =
|
34
|
0
|
fold[Either[P, F]](p => Left(p))(f => Right(f))
|
35
|
|
|
36
|
|
def isPreferred: Boolean =
|
37
|
0
|
fold(_ => true)(_ => false)
|
38
|
|
|
39
|
|
def isFallback: Boolean =
|
40
|
0
|
fold(_ => false)(_ => true)
|
41
|
|
|
42
|
|
def getPreferred: Option[P] =
|
43
|
0
|
fold[Option[P]](p => Some(p))(_ => None)
|
44
|
|
|
45
|
|
def getFallback: Option[F] =
|
46
|
0
|
fold[Option[F]](_ => None)(f => Some(f))
|
47
|
|
}
|
48
|
|
|
49
|
|
object Priority extends FindPreferred {
|
50
|
|
|
51
|
|
case class Preferred[P](get: P) extends Priority[P, Nothing]
|
52
|
|
case class Fallback[F](get: F) extends Priority[Nothing, F]
|
53
|
|
|
54
|
|
def apply[P, F](implicit ev: Priority[P, F]): Priority[P, F] = ev
|
55
|
|
}
|
56
|
|
|
57
|
|
private[algebra] trait FindPreferred extends FindFallback {
|
58
|
|
implicit def preferred[P](implicit ev: P): Priority[P, Nothing] =
|
59
|
0
|
Priority.Preferred(ev)
|
60
|
|
}
|
61
|
|
|
62
|
|
private[algebra] trait FindFallback {
|
63
|
|
implicit def fallback[F](implicit ev: F): Priority[Nothing, F] =
|
64
|
0
|
Priority.Fallback(ev)
|
65
|
|
}
|