Created
June 15, 2019 01:12
-
-
Save kwiest/4c26f914ce33a3e7eb5a7a0ff082f6e7 to your computer and use it in GitHub Desktop.
Implementing a set as a function
This file contains hidden or 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
// Traits are like interfaces | |
trait MySet[A] extends (A => Boolean) { | |
def apply(element: A): Boolean = contains(element) | |
def contains(element: A): Boolean | |
def +(element: A): MySet[A] | |
def ++(otherSet: MySet[A]): MySet[A] | |
def -(element: A): MySet[A] | |
def --(otherSet: MySet[A]): MySet[A] | |
def map[B](fn: A => B): MySet[B] | |
def flatMap[B](fn: A => MySet[B]): MySet[B] | |
def filter(fn: A => Boolean): MySet[A] | |
def foreach(fn: A => Unit): Unit | |
} | |
class EmptySet[A] extends MySet[A] { | |
def contains(element: A): Boolean = false | |
def +(element: A): MySet[A] = new NonEmptySet(element, this) | |
def ++(otherSet: MySet[A]): MySet[A] = otherSet | |
def -(element: A): MySet[A] = this | |
def --(otherSet: MySet[A]): MySet[A] = this | |
def map[B](fn: A => B): MySet[B] = new EmptySet[B] | |
def flatMap[B](fn: A => MySet[B]): MySet[B] = new EmptySet[B] | |
def filter(fn: A => Boolean): MySet[A] = this | |
def foreach(fn: A => Unit): Unit = () | |
} | |
class NonEmptySet[A](head: A, tail: MySet[A]) extends MySet[A] { | |
def contains(element: A): Boolean = | |
head == element || tail.contains(element) | |
def +(element: A): MySet[A] = | |
if (this contains element) this | |
else new NonEmptySet[A](element, this) | |
def ++(otherSet: MySet[A]): MySet[A] = | |
tail ++ otherSet + head | |
def -(element: A): MySet[A] = | |
if (head == element) tail | |
else tail - element + head | |
def --(otherSet: MySet[A]): MySet[A] = filter(e => !otherSet.contains(e)) | |
def map[B](fn: A => B): MySet[B] = (tail map fn) + fn(head) | |
def flatMap[B](fn: A => MySet[B]): MySet[B] = (tail flatMap fn) ++ fn(head) | |
def filter(fn: A => Boolean): MySet[A] = { | |
val filteredTail = tail filter fn | |
if (fn(head)) filteredTail + head | |
else filteredTail | |
} | |
def foreach(fn: A => Unit): Unit = { | |
fn(head) | |
tail foreach fn | |
} | |
} | |
object MySet { | |
def apply[A](values: A*): MySet[A] = { | |
@tailrec | |
def buildSet(valueSequence: Seq[A], accumulator: MySet[A]): MySet[A] = { | |
if (valueSequence.isEmpty) accumulator | |
else buildSet(valueSequence.tail, accumulator + valueSequence.head) | |
} | |
buildSet(values.toSeq, new EmptySet[A]) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment