Last active
September 30, 2019 18:08
-
-
Save gustavofranke/512690839e2963545912123fc3298f32 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package tasks.option | |
import org.scalatest.FunSuite | |
/** | |
* show some scala stuff that I found weird when I started this journey | |
* | |
* I'll use scala test as a vehicle, | |
* but this is not a talk about writing tests, so the tests themselves will be a little repetitive. | |
* I'll be using a very basic subset of the library, the library has lots of features. | |
* | |
* Pattern matching could be used as kinda like a switch statement, although that's not how it's aimed to be used. | |
*/ | |
class PatternSuite extends FunSuite { | |
test("match or not") { | |
val a = 5 match { | |
case 1 => "one"; | |
case 5 => "five" | |
} | |
assert(a === "five") | |
} | |
test("match boom!") { | |
assertThrows[scala.MatchError] { | |
5 match { | |
case 1 => "one"; | |
case 4 => "four" | |
} | |
} | |
assertThrows[scala.MatchError] { | |
"yes" match { | |
case "y" => 1; | |
case "n" => 0 | |
} | |
} | |
} | |
test("match boom! - there, I fixed it") { | |
val a = 2 match { | |
case 1 => "one"; | |
case 5 => "five"; | |
case _ => "none of them" | |
} | |
assert(a === "none of them") | |
} | |
} | |
/** | |
* In the functional-scala talk, we discussed intuitions for the concepts of | |
* 1. type | |
* 2. product => tuple | |
* 3. co-product => ADT, GADT | |
* | |
* But in reality, | |
* pattern matching is aimed to traverse an entire ADT hierarchy (at the type level, | |
* as opposed to at the value level) | |
*/ | |
class ADTSuite extends FunSuite { | |
sealed trait Status | |
case object Active extends Status | |
case object Inactive extends Status | |
def toNumber(s: Status): Int = s match { | |
case Active => 1 | |
case Inactive => 2 | |
} | |
test("asdfdsa") { | |
val a: Status = Active | |
val b: Status = Inactive | |
assert(toNumber(a) === 1) | |
assert(toNumber(b) === 2) | |
} | |
} | |
class OptionSuite extends FunSuite { | |
test("basic get happy path") { | |
val a = Some(5) | |
assert(a.get === 5) | |
} | |
test("basic get unhappy path") { | |
assertDoesNotCompile( | |
""" | |
| val a: Option[Int] = None | |
|a.get === 5 | |
""".stripMargin) | |
} | |
test("happy path") { | |
val a = Some(5) | |
assert(a.map(x => x + 1) === Some(6)) | |
} | |
test("unhappy path") { | |
val a: Option[Int] = None | |
assert(a.map(x => x + 1) === None) | |
} | |
test("need to flatten") { | |
val a = Some(5) | |
assert(a.map(x => Some(x + 1)) === Some(Some(6))) | |
} | |
test("flatten! happy path") { | |
val a: Option[Int] = None | |
assert(a.flatMap(x => Some(x + 1)) === None) | |
} | |
test("flatten!") { | |
val a = Some(5) | |
assert(a.flatMap(x => Some(x + 1)) === Some(6)) | |
} | |
test("combine 2 somes with for comprehension") { | |
val a = for { | |
b <- Some(3) | |
c <- Some(2) | |
} yield b + c | |
assert(a === Some(5)) | |
} | |
test("combine 1 some and 1 none with for comprehension") { | |
val none: Option[Int] = None | |
val a = for { | |
b <- none | |
c <- Some(2) | |
} yield b + c | |
assert(a === None) | |
} | |
test("dissect a for comprehension with previously used values (2 somes)") { | |
val a = Some(3).flatMap(b => | |
Some(2).map(c => | |
b + c) | |
) | |
assert(a === Some(5)) | |
} | |
test("dissect a for comprehension with previously used values (1 some and 1 none)") { | |
val none: Option[Int] = None | |
val a = none.flatMap(b => | |
Some(2).map(c => | |
b + c) | |
) | |
assert(a === None) | |
} | |
} | |
/** | |
* in the effects talk, | |
* we explored a model for computations that allow us to come up with concepts for some common effects | |
* | |
* If we stick to one of them, we can see a lot of language features in action | |
* | |
* pattern matching | |
* generics | |
* variance | |
* HOFs | |
* co-product or sum type, ADT, GADT | |
* botton type | |
*/ | |
sealed trait Option[+A] { | |
def map[B](f: A => B): Option[B] = this match { | |
case None => None | |
case Some(s) => Some(f(s)) | |
} | |
def flatMap[B](f: A => Option[B]): Option[B] = map(f).getOrElse(None) | |
def getOrElse[B >: A](default: B): B = this match { | |
case None => default | |
case Some(s) => s | |
} | |
def filter(f: A => Boolean): Option[A] = flatMap(s => if (f(s)) Some(s) else None) | |
} | |
case object None extends Option[Nothing] | |
case class Some[+A](get: A) extends Option[A] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment