Skip to content

Instantly share code, notes, and snippets.

@JonNorman
Last active November 26, 2018 16:11
Show Gist options
  • Save JonNorman/dcbd0cc9f9f576ac9c39a9fb288d8111 to your computer and use it in GitHub Desktop.
Save JonNorman/dcbd0cc9f9f576ac9c39a9fb288d8111 to your computer and use it in GitHub Desktop.
Exercises for playing with parameterised types

Paramtereised types (exercises)

For each of these exercises, try to write a test to ensure that it is producing what you expect it to do.

Part I

  1. Write a function called length that takes a list of any type and returns the number of elements in that list.

  2. Write the body for a function called head that takes a list of any type and returns the first element of it.

  3. Write a function called map that takes a list of any type A, a function that goes from that type to another type B and returns a list of type B.

Part II

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!

Formal requirements

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?

Test Spec

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)
  }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment