使用Scala實現Option資料結構

NO IMAGE

這個例子來源於scala聖經級教程《Functional Programming in Scala》,由於本人跟著書中的程式碼敲了一遍,然後寫了點測試程式碼驗證了一下正確性,所以就放在這做個備忘吧。貼出來只是為了方便自己得意,如果看不懂,但是又感興趣的就去看原書吧偷笑偷笑偷笑

package errorhandling
//hide std library `Option`, since we are writing our own
import scala.{Option => _}
sealed trait Option[ A] {
def map[B](f: A => B): Option[B] = this match {
case None => None
case Some(a) => Some(f(a))
}
def getOrElse[B >: A](default: => B): B = this match {
case None => default
case Some(a) => a
}
def flatMap[B](f: A => Option[B]): Option[B] = map(f) getOrElse None
def flatMap_1[B](f: A => Option[B]): Option[B] = this match {
case None => None
case Some(a) => f(a)
}
def orElse[B >: A](ob: => Option[B]): Option[B] = this map (Some(_)) getOrElse ob
def orElse_1[B >: A](ob: => Option[B]): Option[B] = this match {
case None => ob
case _ => this
}
def filter(f: A => Boolean): Option[A] = this match {
case Some(a) if f(a) => this
case _ => None
}
def filter_1(f: A => Boolean): Option[A] = flatMap(a => if (f(a)) Some(a) else None)
}
case class Some[ A](get: A) extends Option[A]
case object None extends Option[Nothing]
object Option {
def failingFn(i: Int): Int = {
val y: Int = throw new Exception("fail!")
try {
val x = 42   5
x   y
} catch {
case e: Exception => 43
}
}
def failingFn2(i: Int): Int = {
try {
val x = 42   5
x   ((throw new Exception("fail!")): Int)
}
catch {
case e: Exception => 43
}
}
def mean(xs: Seq[Double]): Option[Double] =
if (xs.isEmpty) None else Some(xs.sum / xs.length)
def variance(xs: Seq[Double]): Option[Double] = mean(xs) flatMap (m => mean(xs.map(x => math.pow(x - m, 2))))
def map2[A, B, C](a: Option[A], b: Option[B])(f: (A, B) => C): Option[C] = a flatMap (aa => b map (bb => f(aa, bb)))
def sequence[A](a: List[Option[A]]): Option[List[A]] = a match {
case Nil => Some(Nil)
case h :: t => h flatMap (hh => sequence(t) map (hh :: _))
}
def sequence_1[A](a: List[Option[A]]): Option[List[A]] = a.foldRight[Option[List[A]]](Some(Nil))((x, y) => map2(x, y)(_ :: _))
def traverse[A, B](a: List[A])(f: A => Option[B]): Option[List[B]] =
a match {
case Nil => Some(Nil)
case h :: t => map2(f(h), traverse(t)(f))(_ :: _)
}
def traverse_1[A, B](a: List[A])(f: A => Option[B]): Option[List[B]] = a.foldRight[Option[List[B]]](Some(Nil))((h, t) => map2(f(h), t)(_ :: _))
def sequenceViaTraverse[A](a: List[Option[A]]): Option[List[A]] =
traverse(a)(x => x)
def lift[A, B](f: A  => B): Option[A] => Option[B] = (a: Option[A]) =>  a.map(f)
def main(args: Array[String]): Unit = {
val someMap = Some(5) map ((a: Int) => "^"   a.toString   "^")
println(someMap)
/*println(Option.failingFn2(2))
println(Option.failingFn(1))*/
val f = (a: Int) => math.pow(a, 2) - a   1
val liftF = lift(f)
println(liftF(Some(5)))
val li = List(Some(1), Some(2), Some(3), Some(4), Some(5))
val sli = sequence(li)
println(sli)
val li2 = List(Some(1), Some(2), Some(3), Some(4), None)
val sli2 = sequence(li2)
println(sli2.orElse(Some(Nil)))
println(sli2.getOrElse(Nil))
val filterd = Some(5).filter(_ > 5).getOrElse(-1)
println(filterd)
val flat = Some(5) flatMap ((a: Int) => Some(a))
println(flat)
}
}

上述程式碼的執行結果是:

Some(^5^)
Some(21.0)
Some(List(1, 2, 3, 4, 5))
Some(List())
List()
-1
Some(5)