diff --git a/Scala/.gitignore b/Scala/.gitignore new file mode 100644 index 0000000..b4a5277 --- /dev/null +++ b/Scala/.gitignore @@ -0,0 +1,3 @@ +.idea/ +target/ +*.iml diff --git a/Scala/1-single-immutable.scala b/Scala/1-single-immutable.scala new file mode 100644 index 0000000..2f071ab --- /dev/null +++ b/Scala/1-single-immutable.scala @@ -0,0 +1,76 @@ +sealed trait SingleLinked[+A] { + def ::[B >: A](value: B): SingleLinked[B] = { + SingleLinked.::(value, this) + } + + def foreach[B >: A](f: B => Unit): Unit = { + SingleLinked.foreach(this)(f) + } + + def map[B](f: A => B): SingleLinked[B] = { + SingleLinked.map(this)(f) + } + + def flatMap[B](f: A => SingleLinked[B]): SingleLinked[B] = { + SingleLinked.flatMap(this)(f) + } +} + + +case object SNil extends SingleLinked[Nothing] +case class SNode[+A](value: A, tail: SingleLinked[A]) extends SingleLinked[A] + + +object SingleLinked { + def empty[A]: SingleLinked[A] = SNil + + def apply[A](values: A*): SingleLinked[A] = values.foldLeft(SingleLinked.empty[A])((list, item) => item :: list) + + def ::[A](value: A, list: SingleLinked[A]): SingleLinked[A] = SNode(value, list) + + def foreach[A](list: SingleLinked[A])(f: A => Unit): Unit = { + list match { + case SNil => + case SNode(value, tail) => + f(value) + tail.foreach(f) + } + } + + def map[A, B](list: SingleLinked[A])(f: A => B): SingleLinked[B] = { + list match { + case SNil => SNil + case SNode(value, tail) => SNode(f(value), tail.map(f)) + } + } + + def merge[A](list1: SingleLinked[A], list2: SingleLinked[A]): SingleLinked[A] = { + list1 match { + case SNil => list2 + case SNode(value, tail) => SNode(value, merge(tail, list2)) + } + } + + def flatMap[A, B](list: SingleLinked[A])(f: A => SingleLinked[B]): SingleLinked[B] = { + list match { + case SNil => SNil + case SNode(value, tail) => merge(f(value), tail.flatMap(f)) + } + } +} + +object SingleExample { + + def main(args: Array[String]): Unit = { + val list: SingleLinked[Int] = 1 :: 2 :: 3 :: SNil + + list.foreach(item => print(s"$item\t")) + println() + + list.map(_ + 1).foreach(item => print(s"$item\t")) + println() + + list.flatMap(item => item :: item :: SNil).foreach(item => print(s"$item\t")) + println() + } +} diff --git a/Scala/2-doubly-mutable.scala b/Scala/2-doubly-mutable.scala new file mode 100644 index 0000000..0e62007 --- /dev/null +++ b/Scala/2-doubly-mutable.scala @@ -0,0 +1,71 @@ +/** + * In case of double linked list we have to ignore some principles of functional programming + * and we should make some fields of Node class mutable + * In other case we will have to recreate all list after any change + */ + +sealed trait DoubleLinked[+A] { + def ::[B >: A](value: B): DoubleLinked[B] = { + DoubleLinked.append(value, this) + } + + def foreach[B >: A](f: B => Unit): Unit = { + DoubleLinked.foreach(this)(f) + } + + def map[B](f: A => B): DoubleLinked[B] = { + DoubleLinked.map(this, DNil)(f) + } +} + + +case object DNil extends DoubleLinked[Nothing] +class DNode[A](var prev: DoubleLinked[A], val value: A, var next: DoubleLinked[A]) extends DoubleLinked[A] + + +object DoubleLinked { + def empty[A]: DoubleLinked[A] = DNil + + def apply[A](values: A*): DoubleLinked[A] = values.foldLeft(DoubleLinked.empty[A])((list, item) => item :: list) + + def append[A](value: A, list: DoubleLinked[A]): DoubleLinked[A] = { + val node = new DNode(DNil, value, list) + list match { + case DNil => DNil + case l: DNode[A] => + l.prev = node + } + + node + } + + def foreach[A](list: DoubleLinked[A])(f: A => Unit): Unit = { + list match { + case DNil => + case l: DNode[A] => + f(l.value) + l.next.foreach(f) + } + } + + def map[A, B](list: DoubleLinked[A], prev: DoubleLinked[B])(f: A => B): DoubleLinked[B] = { + list match { + case DNil => DNil + case l: DNode[A] => + new DNode(prev, f(l.value), map(l.next, prev)(f)) + } + } +} + +object DoublyExample { + + def main(args: Array[String]): Unit = { + val list2: DoubleLinked[Int] = 1 :: 2 :: 3 :: DNil + + list2.foreach(item => print(s"$item\t")) + println() + + list2.map(_ + 1).foreach(item => print(s"$item\t")) + println() + } +}