For each of these exercises, try to write a test to ensure that it is producing what you expect it to do.
-
Write a function called
length
that takes a list of any type and returns the number of elements in that list. -
Write the body for a function called
head
that takes a list of any type and returns the first element of it. -
Write a function called
map
that takes a list of any typeA
, a function that goes from that type to another typeB
and returns a list of typeB
.
Previously we have implemented our own version of Option
having fixed the type to Int
and called it MaybeInt
.
This time we are just going to shamelessly rip off the generic Option
type and implement our own version called Maybe
.
The key difference between Maybe
and our previous MaybeInt
is that our Maybe
won't care about the type of the internal
value - it will be entirely generic!
To make this quick to test, we've created a a test spec (see below). Once you've implemented your Maybe
type, paste the
test code into a file in your project, import your Maybe
class at the top of it and see if they pass!
To get these tests to pass you will need to create an interface called Maybe
. This will have two classes that implement it,
an Actual
(equivalent to Some
) and a Missing
(equivalent to None). You should try and define the following functions
.isDefined
.exists
.map
and feel free to implement more of the functions that Option
has if you get this far. Or, if you are tired of thinking
about Option
, why not try to implement your own version of Either
or List
?
Note: none of these tests will work - or even compile! - before you have defined and imported your Maybe class, which should be defined in a separate file in your src folder.
//MaybeSpec.scala
import org.scalatest.{FlatSpec, Matchers}
class MaybeSpec extends FlatSpec with Matchers {
"Creating a Maybe with a value" should "produce an Actual" in {
Maybe(8.9) should be (Actual(8.9))
Maybe(false) should be (Actual(false))
}
"Creating a Maybe with a null" should "produce a Missing" in {
Maybe(null) should be (Missing)
}
"The .isDefined function" should "be defined for Maybe" in {
Maybe(2).isDefined should be (true)
Maybe("two").isDefined should be (true)
Maybe(true).isDefined should be (true)
Maybe(null).isDefined should be (false)
}
"The .exists function" should "be defined for Maybe" in {
Maybe(2).exists(_ >= 2) should be (true)
Maybe(2).exists(_ > 2) should be (false)
Maybe("two").exists(_.contains("w")) should be (true)
Maybe("two").exists(_.contains("x")) should be (false)
Maybe(null).exists(_ => true) should be (false)
Maybe(null).exists(_ => false) should be (false)
}
"The .map function" should "be defined on Maybe" in {
Maybe(2).map(_ + 4) should be(Actual(6))
Maybe("AbCdEfG").map(_.count(_.isUpper)) should be (Actual(4))
val missingInt: Maybe[Int] = Missing
missingInt.map(_ + 5) should be (Missing)
}
}