Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 82 additions & 12 deletions 03/practice/src/main/scala/org/spbsu/mkn/scala/MyGenericList.scala
Original file line number Diff line number Diff line change
@@ -1,20 +1,90 @@
package org.spbsu.mkn.scala

import org.spbsu.mkn.scala.MyGenericList._
import scala.annotation.tailrec

sealed trait MyGenericList {
def head: Int
def tail: MyGenericList
def drop(n: Int): MyGenericList
def take(n: Int): MyGenericList
def map(f: Int => Int): MyGenericList
def ::(elem: Int): MyGenericList = ???
sealed trait MyGenericList[+T] {
def head: T

def tail: MyGenericList[T]

def drop(n: Int): MyGenericList[T]

def take(n: Int): MyGenericList[T]

def map[P >: T, S](f: P => S): MyGenericList[S]

def ::[S >: T](elem: S): MyGenericList[S] = MyCons(elem, this)
}

object MyGenericList {
case object MyGenericList {
def undef: Nothing = throw new UnsupportedOperationException("operation is undefined")
def fromSeq(seq: Seq[Int]): MyGenericList = ???
def size(intList: MyGenericList): Int = ???
// extra task: implement sum using foldLeft
// def foldLeft(???)(???): ??? = ???

def fromSeq[T](seq: Seq[T]): MyGenericList[T] = seq.foldRight[MyGenericList[T]](MyNil) { (x, list) => MyCons(x, list) }

def size[T](myList: MyGenericList[T]): Int = {
myList match {
case MyNil => 0
case MyCons(_, list) => 1 + size(list)
}
}

def sum[T: Numeric](myList: MyGenericList[T]): T = {
myList match {
case MyNil => undef
case _ => foldLeft(myList, Numeric[T].zero) { Numeric[T].plus }
}
}

@tailrec
def foldLeft[T, S](myList: MyGenericList[T], initValue: S)(f: (S, T) => S): S = {
myList match {
case MyNil => initValue
case MyCons(x, list) => foldLeft(list, f(initValue, x))(f)
}
}
}

case object MyNil extends MyGenericList[Nothing] {
override def head: Nothing = undef

override def tail: MyGenericList[Nothing] = MyNil

override def drop(n: Int): MyGenericList[Nothing] = {
n match {
case 0 => MyNil
case _ => undef
}
}

override def take(n: Int): MyGenericList[Nothing] = {
n match {
case 0 => MyNil
case _ => undef
}
}

override def map[T, S](f: T => S): MyGenericList[S] = MyNil
}

case class MyCons[T](x: T, list: MyGenericList[T]) extends MyGenericList[T] {
override def head: T = x

override def tail: MyGenericList[T] = list

override def drop(n: Int): MyGenericList[T] = {
n match {
case 0 => this
case _ => list.drop(n - 1)
}
}

override def take(n: Int): MyGenericList[T] = {
n match {
case 0 => MyNil
case _ => MyCons(x, list.take(n - 1))
}
}

override def map[P >: T, S](f: P => S): MyGenericList[S] = MyCons(f(x), list.map(f))
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,49 +5,58 @@ import org.spbsu.mkn.scala.MyGenericList.{fromSeq, size, sum}

class MyGenericListTest extends AnyFunSuite {

// remove after implementing actual MyNil
object MyNil

test("head") {
assert(fromSeq(Seq(1,2,3)).head == 1)
assert(fromSeq(Seq(1, 2, 3)).head == 1)
assert(fromSeq(Seq(1)).head == 1)
assertThrows[UnsupportedOperationException](fromSeq(Seq()).head)
}

test("tail") {
assert(fromSeq(Seq(1,2,3)).tail == fromSeq(Seq(2,3)))
assert(fromSeq(Seq(1, 2, 3)).tail == fromSeq(Seq(2, 3)))
assert(fromSeq(Seq(1)).tail == MyNil)
}

test("drop") {
assert(fromSeq(Seq(1,2,3)).drop(0) == fromSeq(Seq(1,2,3)))
assert(fromSeq(Seq(1,2,3)).drop(2) == fromSeq(Seq(3)))
assert(fromSeq(Seq(1,2,3)).drop(3) == MyNil)
assertThrows[UnsupportedOperationException](fromSeq(Seq(1,2,3)).drop(10))
assert(fromSeq(Seq(1, 2, 3)).drop(0) == fromSeq(Seq(1, 2, 3)))
assert(fromSeq(Seq(1, 2, 3)).drop(2) == fromSeq(Seq(3)))
assert(fromSeq(Seq(1, 2, 3)).drop(3) == MyNil)
assertThrows[UnsupportedOperationException](fromSeq(Seq(1, 2, 3)).drop(10))
}

test("take") {
assert(fromSeq(Seq(1,2,3)).take(0) == MyNil)
assert(fromSeq(Seq(1,2,3)).take(2) == fromSeq(Seq(1,2)))
assert(fromSeq(Seq(1,2,3)).take(3) == fromSeq(Seq(1,2,3)))
assertThrows[UnsupportedOperationException](fromSeq(Seq(1,2,3)).take(10))
assert(fromSeq(Seq(1, 2, 3)).take(0) == MyNil)
assert(fromSeq(Seq(1, 2, 3)).take(2) == fromSeq(Seq(1, 2)))
assert(fromSeq(Seq(1, 2, 3)).take(3) == fromSeq(Seq(1, 2, 3)))
assertThrows[UnsupportedOperationException](fromSeq(Seq(1, 2, 3)).take(10))
}

trait Animal {
val name: String
final val age = 1
}
case class Cat(override val name: String) extends Animal
case class Dog(override val name: String) extends Animal

test("map") {
assert(MyNil.map(_ * 2) == MyNil)
assert(fromSeq(Seq(1,2,3)).map(_ * 2) == fromSeq(Seq(2,4,6)))
assert(fromSeq(Seq(1,2,3)).map(identity) == fromSeq(Seq(1,2,3)))
assert(MyNil.map[Int, Int](_ * 2) == MyNil)
assert(fromSeq(Seq(1, 2, 3)).map[Int, Int](_ * 2) == fromSeq(Seq(2, 4, 6)))
assert(fromSeq(Seq(1, 2, 3)).map[Int, Int](identity) == fromSeq(Seq(1, 2, 3)))

assert(fromSeq(Seq('a', 'b', 'c')).map[Char, Int](x => 26 * (x - 'a')) == fromSeq(Seq(0, 26, 52)))
assert(fromSeq(Seq(Dog("Tuzik"), Cat("Alice"))).map[Animal, String](x => x.name) == fromSeq(Seq("Tuzik", "Alice")))
assert(fromSeq(Seq[Animal](Dog("Bobik"), Dog("Tuzik"))).map[Animal, Int](x => x.age) == fromSeq(Seq(1, 1)))
}

test("size") {
assert(size(MyNil) == 0)
assert(size(fromSeq(Seq(1,2,3))) == 3)
assert(size(fromSeq(Seq(1, 2, 3))) == 3)
}

test("sum") {
assertThrows[UnsupportedOperationException](sum(MyNil))
assert(sum(fromSeq(Seq(1,2,3))) == 6)
assertThrows[UnsupportedOperationException](sum[Int](MyNil))
assert(sum(fromSeq(Seq(1, 2, 3))) == 6)
assert(sum(fromSeq(Seq(1))) == 1)
}

}
assert(sum(fromSeq(Seq(' ', '0'))) == 'P')
}
}