summaryrefslogtreecommitdiffstats
path: root/Scala/funsets/src
diff options
context:
space:
mode:
Diffstat (limited to 'Scala/funsets/src')
-rw-r--r--Scala/funsets/src/main/scala/common/package.scala40
-rw-r--r--Scala/funsets/src/main/scala/funsets/FunSets.scala90
-rw-r--r--Scala/funsets/src/main/scala/funsets/Main.scala6
-rw-r--r--Scala/funsets/src/test/scala/funsets/FunSetSuite.scala112
4 files changed, 248 insertions, 0 deletions
diff --git a/Scala/funsets/src/main/scala/common/package.scala b/Scala/funsets/src/main/scala/common/package.scala
new file mode 100644
index 0000000..f1c74c3
--- /dev/null
+++ b/Scala/funsets/src/main/scala/common/package.scala
@@ -0,0 +1,40 @@
+import java.io.File
+
+package object common {
+
+ /** An alias for the `Nothing` type.
+ * Denotes that the type should be filled in.
+ */
+ type ??? = Nothing
+
+ /** An alias for the `Any` type.
+ * Denotes that the type should be filled in.
+ */
+ type *** = Any
+
+
+ /**
+ * Get a child of a file. For example,
+ *
+ * subFile(homeDir, "b", "c")
+ *
+ * corresponds to ~/b/c
+ */
+ def subFile(file: File, children: String*) = {
+ children.foldLeft(file)((file, child) => new File(file, child))
+ }
+
+ /**
+ * Get a resource from the `src/main/resources` directory. Eclipse does not copy
+ * resources to the output directory, then the class loader cannot find them.
+ */
+ def resourceAsStreamFromSrc(resourcePath: List[String]): Option[java.io.InputStream] = {
+ val classesDir = new File(getClass.getResource(".").toURI)
+ val projectDir = classesDir.getParentFile.getParentFile.getParentFile.getParentFile
+ val resourceFile = subFile(projectDir, ("src" :: "main" :: "resources" :: resourcePath): _*)
+ if (resourceFile.exists)
+ Some(new java.io.FileInputStream(resourceFile))
+ else
+ None
+ }
+}
diff --git a/Scala/funsets/src/main/scala/funsets/FunSets.scala b/Scala/funsets/src/main/scala/funsets/FunSets.scala
new file mode 100644
index 0000000..594a49d
--- /dev/null
+++ b/Scala/funsets/src/main/scala/funsets/FunSets.scala
@@ -0,0 +1,90 @@
+package funsets
+
+import common._
+
+/**
+ * 2. Purely Functional Sets.
+ */
+object FunSets {
+ /**
+ * We represent a set by its characteristic function, i.e.
+ * its `contains` predicate.
+ */
+ type Set = Int => Boolean
+
+ /**
+ * Indicates whether a set contains a given element.
+ */
+ def contains(s: Set, elem: Int): Boolean = s(elem)
+
+ /**
+ * Returns the set of the one given element.
+ */
+ def singletonSet(elem: Int): Set = ???
+
+ /**
+ * Returns the union of the two given sets,
+ * the sets of all elements that are in either `s` or `t`.
+ */
+ def union(s: Set, t: Set): Set = ???
+
+ /**
+ * Returns the intersection of the two given sets,
+ * the set of all elements that are both in `s` and `t`.
+ */
+ def intersect(s: Set, t: Set): Set = ???
+
+ /**
+ * Returns the difference of the two given sets,
+ * the set of all elements of `s` that are not in `t`.
+ */
+ def diff(s: Set, t: Set): Set = ???
+
+ /**
+ * Returns the subset of `s` for which `p` holds.
+ */
+ def filter(s: Set, p: Int => Boolean): Set = ???
+
+ /**
+ * The bounds for `forall` and `exists` are +/- 1000.
+ */
+ val bound = 1000
+
+ /**
+ * Returns whether all bounded integers within `s` satisfy `p`.
+ */
+ def forall(s: Set, p: Int => Boolean): Boolean = {
+ def iter(a: Int): Boolean = {
+ if (???) ???
+ else if (???) ???
+ else iter(???)
+ }
+ iter(???)
+ }
+
+ /**
+ * Returns whether there exists a bounded integer within `s`
+ * that satisfies `p`.
+ */
+ def exists(s: Set, p: Int => Boolean): Boolean = ???
+
+ /**
+ * Returns a set transformed by applying `f` to each element of `s`.
+ */
+ def map(s: Set, f: Int => Int): Set = ???
+
+ /**
+ * Displays the contents of a set
+ */
+ def toString(s: Set): String = {
+ val xs = for (i <- -bound to bound if contains(s, i)) yield i
+ xs.mkString("{", ",", "}")
+ }
+
+ /**
+ * Prints the contents of a set on the console.
+ */
+ def printSet(s: Set) {
+ println(toString(s))
+ }
+}
diff --git a/Scala/funsets/src/main/scala/funsets/Main.scala b/Scala/funsets/src/main/scala/funsets/Main.scala
new file mode 100644
index 0000000..6126909
--- /dev/null
+++ b/Scala/funsets/src/main/scala/funsets/Main.scala
@@ -0,0 +1,6 @@
+package funsets
+
+object Main extends App {
+ import FunSets._
+ println(contains(singletonSet(1), 1))
+}
diff --git a/Scala/funsets/src/test/scala/funsets/FunSetSuite.scala b/Scala/funsets/src/test/scala/funsets/FunSetSuite.scala
new file mode 100644
index 0000000..e75ba8c
--- /dev/null
+++ b/Scala/funsets/src/test/scala/funsets/FunSetSuite.scala
@@ -0,0 +1,112 @@
+package funsets
+
+import org.scalatest.FunSuite
+
+import org.junit.runner.RunWith
+import org.scalatest.junit.JUnitRunner
+
+/**
+ * This class is a test suite for the methods in object FunSets. To run
+ * the test suite, you can either:
+ * - run the "test" command in the SBT console
+ * - right-click the file in eclipse and chose "Run As" - "JUnit Test"
+ */
+@RunWith(classOf[JUnitRunner])
+class FunSetSuite extends FunSuite {
+
+
+ /**
+ * Link to the scaladoc - very clear and detailed tutorial of FunSuite
+ *
+ * http://doc.scalatest.org/1.9.1/index.html#org.scalatest.FunSuite
+ *
+ * Operators
+ * - test
+ * - ignore
+ * - pending
+ */
+
+ /**
+ * Tests are written using the "test" operator and the "assert" method.
+ */
+ test("string take") {
+ val message = "hello, world"
+ assert(message.take(5) == "hello")
+ }
+
+ /**
+ * For ScalaTest tests, there exists a special equality operator "===" that
+ * can be used inside "assert". If the assertion fails, the two values will
+ * be printed in the error message. Otherwise, when using "==", the test
+ * error message will only say "assertion failed", without showing the values.
+ *
+ * Try it out! Change the values so that the assertion fails, and look at the
+ * error message.
+ */
+ test("adding ints") {
+ assert(1 + 2 === 3)
+ }
+
+
+ import FunSets._
+
+ test("contains is implemented") {
+ assert(contains(x => true, 100))
+ }
+
+ /**
+ * When writing tests, one would often like to re-use certain values for multiple
+ * tests. For instance, we would like to create an Int-set and have multiple test
+ * about it.
+ *
+ * Instead of copy-pasting the code for creating the set into every test, we can
+ * store it in the test class using a val:
+ *
+ * val s1 = singletonSet(1)
+ *
+ * However, what happens if the method "singletonSet" has a bug and crashes? Then
+ * the test methods are not even executed, because creating an instance of the
+ * test class fails!
+ *
+ * Therefore, we put the shared values into a separate trait (traits are like
+ * abstract classes), and create an instance inside each test method.
+ *
+ */
+
+ trait TestSets {
+ val s1 = singletonSet(1)
+ val s2 = singletonSet(2)
+ val s3 = singletonSet(3)
+ }
+
+ /**
+ * This test is currently disabled (by using "ignore") because the method
+ * "singletonSet" is not yet implemented and the test would fail.
+ *
+ * Once you finish your implementation of "singletonSet", exchange the
+ * function "ignore" by "test".
+ */
+ ignore("singletonSet(1) contains 1") {
+
+ /**
+ * We create a new instance of the "TestSets" trait, this gives us access
+ * to the values "s1" to "s3".
+ */
+ new TestSets {
+ /**
+ * The string argument of "assert" is a message that is printed in case
+ * the test fails. This helps identifying which assertion failed.
+ */
+ assert(contains(s1, 1), "Singleton")
+ }
+ }
+
+ ignore("union contains all elements") {
+ new TestSets {
+ val s = union(s1, s2)
+ assert(contains(s, 1), "Union 1")
+ assert(contains(s, 2), "Union 2")
+ assert(!contains(s, 3), "Union 3")
+ }
+ }
+}