Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • intro-to-fp/short-exercises
  • s472501/short-exercises
  • s410344/short-exercises
3 results
Show changes
Showing
with 170 additions and 96 deletions
......@@ -2,16 +2,17 @@ package applicative
import org.scalatest._
import testutil.PendingIfUnimplemented
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
class ApplicativeSpec extends FlatSpec with Matchers with AppendedClues with PendingIfUnimplemented {
implicit val optionApplicative = new Applicative[Option] {
class ApplicativeSpec extends AnyFlatSpec with Matchers with AppendedClues with PendingIfUnimplemented:
given optionApplicative: Applicative[Option] with
override def pure[A](a: A): Option[A] = Some(a)
override def ap[A, B](ff: Option[A => B])(fa: Option[A]): Option[B] = ff.flatMap(f => fa.map(f))
}
implicit val listApplicative = new Applicative[List] {
given listApplicative: Applicative[List] with
override def pure[A](a: A): List[A] = List(a)
override def ap[A, B](ff: List[A => B])(fa: List[A]): List[B] = ff.flatMap(f => fa.map(f))
}
"map" should "work the same when implemented via ap" in {
val f: Int => Int = i => i * 3
......@@ -28,22 +29,25 @@ class ApplicativeSpec extends FlatSpec with Matchers with AppendedClues with Pen
}
"map2" should "combine two monadic values" in {
optionApplicative.map2(Some(1), Some(2))((a, b) => a + b) shouldBe Some(3)
optionApplicative.map2(Option.empty[Int], Some(2))((a, b) => a + b) shouldBe None
optionApplicative.map2(Some(2), Option.empty[Int])((a, b) => a + b) shouldBe None
optionApplicative.map2(Some(1))(Some(2))((a, b) => a + b) shouldBe Some(3)
optionApplicative.map2(Option.empty[Int])(Some(2))((a, b) => a + b) shouldBe None
optionApplicative.map2(Some(2))(Option.empty[Int])((a, b) => a + b) shouldBe None
}
"compose" should "create nested element with pure" in {
val ola: Applicative[Lambda[a => Option[List[a]]]] = optionApplicative.compose(listApplicative)
val ola: Applicative[[a] =>> Option[List[a]]] =
Applicative.compose(using optionApplicative, listApplicative)
ola.pure(5) shouldBe Some(List(5))
}
it should "implement map2 or ap correctly" in {
val ola: Applicative[Lambda[a => Option[List[a]]]] = optionApplicative.compose(listApplicative)
try
val ola: Applicative[[a] =>> Option[List[a]]] =
Applicative.compose(using optionApplicative, listApplicative)
val optList = Some(List(1, 2, 3, 4))
val optList = Some(List(1, 2, 3, 4))
ola.map(optList)(_ + 10) shouldBe Some(List(11, 12, 13, 14))
ola.map(optList)(_ + 10) shouldBe Some(List(11, 12, 13, 14))
catch case e: StackOverflowError =>
fail("StackOverflowError. Did you override ap or map2?")
}
}
......@@ -2,25 +2,28 @@ package applicative
import org.scalatest._
import testutil.PendingIfUnimplemented
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
import Validated.*
class ValidatedSpec extends FlatSpec with Matchers with AppendedClues with PendingIfUnimplemented {
class ValidatedSpec extends AnyFlatSpec with Matchers with AppendedClues with PendingIfUnimplemented:
"map2" should "accumulate errors" in {
type VSI = Validated[String, Int]
val valid1: VSI = Valid(1)
val valid2: VSI = Valid(2)
val invalidA: VSI = Invalid("A")
val invalidB: VSI = Invalid("B")
val invalidA: VSI = Invalid("A", Nil)
val invalidB: VSI = Invalid("B", Nil)
val invalidAB: VSI = Invalid("A", List("B"))
val invalidABAB: VSI = Invalid("A", List("B", "A", "B"))
val strErrorApplicative = implicitly[Applicative[Validated[String, +?]]]
val strErrorApplicative = implicitly[Applicative[[a] =>> Validated[String, a]]]
??? //remove, when you have overridden map2 or ap
strErrorApplicative.map2(valid1, valid2)((a, b) => a + b) shouldBe Valid(3)
strErrorApplicative.map2(invalidA, valid2)((a, b) => a + b) shouldBe invalidA
strErrorApplicative.map2(valid1, invalidB)((a, b) => a + b) shouldBe invalidB
strErrorApplicative.map2(invalidA, invalidB)((a, b) => a + b) shouldBe invalidAB
strErrorApplicative.map2(invalidAB, invalidAB)((a, b) => a + b) shouldBe invalidABAB
try
strErrorApplicative.map2(valid1)(valid2)((a, b) => a + b) shouldBe Valid(3)
strErrorApplicative.map2(invalidA)(valid2)((a, b) => a + b) shouldBe invalidA
strErrorApplicative.map2(valid1)(invalidB)((a, b) => a + b) shouldBe invalidB
strErrorApplicative.map2(invalidA)(invalidB)((a, b) => a + b) shouldBe invalidAB
strErrorApplicative.map2(invalidAB)(invalidAB)((a, b) => a + b) shouldBe invalidABAB
catch case e: StackOverflowError =>
fail("StackOverflowError. Did you override ap or map2?")
}
}
......@@ -2,21 +2,23 @@ package datastructures
import org.scalatest._
import testutil.PendingIfUnimplemented
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
class ListSpec extends FlatSpec with Matchers with AppendedClues with PendingIfUnimplemented {
class ListSpec extends AnyFlatSpec with Matchers with AppendedClues with PendingIfUnimplemented:
val numbers = List(1 to 5: _*)
val single = List(1)
val strings = List("a", "b", "c")
"A list" should "have a tail function that removes the first element" in {
numbers.tail shouldBe List(2, 3, 4, 5)
single.tail shouldBe Nil
single.tail shouldBe List.Nil
a[RuntimeException] should be thrownBy List().tail
}
it should "have a init function that removes the last element" in {
numbers.init shouldBe List(1, 2, 3, 4)
single.init shouldBe Nil
single.init shouldBe List.Nil
a[RuntimeException] should be thrownBy List().init
}
......@@ -29,4 +31,3 @@ class ListSpec extends FlatSpec with Matchers with AppendedClues with PendingIfU
strings.foldLeft("X")(_ + _) should not be "Xcba" withClue ", this looks like a right fold with flipped args"
strings.foldLeft("X")(_ + _) shouldBe "Xabc"
}
}
\ No newline at end of file
......@@ -2,12 +2,14 @@ package errors
import org.scalatest._
import testutil.PendingIfUnimplemented
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
class EitherSpec extends FlatSpec with Matchers with AppendedClues with PendingIfUnimplemented {
val l1: Either[Int, Int] = Left(1)
val l2: Either[Int, Int] = Left(2)
val r1: Either[Int, Int] = Right(1)
val r2: Either[Int, Int] = Right(2)
class EitherSpec extends AnyFlatSpec with Matchers with AppendedClues with PendingIfUnimplemented:
val l1: Either[Int, Int] = Either.Left(1)
val l2: Either[Int, Int] = Either.Left(2)
val r1: Either[Int, Int] = Either.Right(1)
val r2: Either[Int, Int] = Either.Right(2)
"Either" should "have a map2 method which correctly combines two values" in {
l1.map2(r1)((a, b) => a+b) shouldBe l1
......@@ -15,5 +17,4 @@ class EitherSpec extends FlatSpec with Matchers with AppendedClues with PendingI
r1.map2(r1)((a, b) => a+b) shouldBe r2
l1.map2(l2)((a, b) => a+b) shouldBe l1
}
}
......@@ -2,8 +2,12 @@ package errors
import org.scalatest._
import testutil.PendingIfUnimplemented
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
class OptionSpec extends FlatSpec with Matchers with AppendedClues with PendingIfUnimplemented {
import Option.{Some, None}
class OptionSpec extends AnyFlatSpec with Matchers with AppendedClues with PendingIfUnimplemented:
"An option" should "have a map function which transforms it's content" in {
Some(3).map(_ + 1) shouldBe Some(4)
}
......@@ -29,5 +33,4 @@ class OptionSpec extends FlatSpec with Matchers with AppendedClues with PendingI
Option.sequence(List(Some(1), Some(2))) shouldBe Some(List(1,2))
Option.sequence(List(Some(1), None)) shouldBe None
}
}
......@@ -2,10 +2,11 @@ package errors
import org.scalatest._
import testutil.PendingIfUnimplemented
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
class TeamSpec extends FlatSpec with Matchers with AppendedClues with PendingIfUnimplemented {
class TeamSpec extends AnyFlatSpec with Matchers with AppendedClues with PendingIfUnimplemented:
"getTeam" should "return both persons ore none" in {
Team.getTeam("blar", "Dagobert") shouldBe None
Team.getTeam("Daniel", "Dagobert") shouldBe Some((Team.persons(2), Team.persons(0)))
getTeam("blar", "Dagobert") shouldBe Option.None
getTeam("Daniel", "Dagobert") shouldBe Option.Some((persons(2), persons(0)))
}
}
package foldfunc
import org.scalatest._
import testutil.PendingIfUnimplemented
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
import algebra.Monoid
@SuppressWarnings(Array("org.wartremover.warts.All"))
class FoldableSpec extends AnyFlatSpec with Matchers with AppendedClues with PendingIfUnimplemented:
"foldMap" should "work when mapping to a string" in {
given Monoid[String] with
def zero = ""
def combine(a:String, b:String) = a + b
Foldable.foldMap(List(1,2,3))(_.toString) shouldBe "123"
}
"toList" should "be able to convert any foldable to a list" in {
given Foldable[Vector] with
extension [A](as: Vector[A])
def foldRight[B](z: B)(f: (A,B) => B): B = as.foldRight(z)(f)
def foldLeft[B](z: B)(f: (B,A) => B): B = as.foldLeft(z)(f)
val input = Vector(1,2,3)
val expected = List(1,2,3)
//uncomment the variant that you have implemented
// Function on companion
//Foldable.toList(input) shouldBe expected
// Extension method
//input.toList shouldBe expected
}
package foldfunc
import org.scalatest._
import testutil.PendingIfUnimplemented
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
@SuppressWarnings(Array("org.wartremover.warts.All"))
class FunctorSpec extends AnyFlatSpec with Matchers with AppendedClues with PendingIfUnimplemented:
"The Functor instance for Option" should "be available as given" in {
"summon[Functor[Option]]" should compile
}
package typeclasses
package foldfunc
import org.scalatest._
import testutil.PendingIfUnimplemented
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
@SuppressWarnings(Array("org.wartremover.warts.All"))
class ShowSpec extends FlatSpec with Matchers with AppendedClues with PendingIfUnimplemented {
"The Show instance for Person" should "be available in implicit scope" in {
"implicitly[Show[Person]]" should compile
class ShowSpec extends AnyFlatSpec with Matchers with AppendedClues with PendingIfUnimplemented:
"The Show instance for Person" should "be available as a given" in {
"summon[Show[Person]]" should compile
}
it should "display in format\"[firstName] [lastName] is [age] years old\"" in {
// uncomment as soon as you pass the above test
//implicitly[Show[Person]].show(People.odersky) shouldBe "Martin Odersky is 60 years old"
//People.odersky.show shouldBe "Martin Odersky is 62 years old"
}
}
......@@ -2,19 +2,21 @@ package laziness
import org.scalatest._
import testutil.PendingIfUnimplemented
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
class StreamSpec extends FlatSpec with Matchers with AppendedClues with PendingIfUnimplemented {
class LazyListSpec extends AnyFlatSpec with Matchers with AppendedClues with PendingIfUnimplemented:
import Stream._
import LazyList._
/*
* Note that equivalence checking on streams does not work.
* Note that equivalence checking on lazy lists does not work.
* Therefore it is important, that your toList implementation works for most later tests.
*/
"A stream" should "be convertable to a list" in {
Stream(1, 2, 3).toList shouldBe List(1, 2, 3)
Stream.empty.toList shouldBe List()
"A LazyList" should "be convertable to an eagerly evaluated list" in {
LazyList(1, 2, 3).toList shouldBe List(1, 2, 3)
LazyList.empty.toList shouldBe List()
}
it should "have a take method that keeps only a certain number of elements" in {
......@@ -24,7 +26,7 @@ class StreamSpec extends FlatSpec with Matchers with AppendedClues with PendingI
}
it should "have a drop method that removes a certain number of elements from the start" in {
Stream(1, 2, 3, 4).drop(1).toList shouldBe List(2, 3, 4)
LazyList(1, 2, 3, 4).drop(1).toList shouldBe List(2, 3, 4)
ones.drop(17).headOption should contain(1)
}
......@@ -33,12 +35,11 @@ class StreamSpec extends FlatSpec with Matchers with AppendedClues with PendingI
fibs.take(8).toList shouldBe List(0, 1, 1, 2, 3, 5, 8, 13)
}
"unfold" should "should generate streams from a function while stopping on None" in {
val alphabet = unfold('a')(s => if(s <= 'z') Some((s, (s+1).toChar)) else None)
"unfold" should "should generate lazy lists from a function while stopping on None" in {
val alphabet = unfold('a')(s => if s <= 'z' then Some((s, (s+1).toChar)) else None)
alphabet.toList shouldBe ('a' to 'z').toList
}
"fibsViaUnfold" should "result in the same values as fibs without unfold" in {
fibsViaUnfold.take(10).toList shouldBe fibs.take(10).toList
}
}
......@@ -2,13 +2,15 @@ package monads
import org.scalatest._
import testutil.PendingIfUnimplemented
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
class MonadFunctorSpec extends FlatSpec with Matchers with AppendedClues with PendingIfUnimplemented {
given Monad[Option] with
def pure[A](a: A): Option[A] = Some(a)
extension [A](fa: Option[A]) def flatMap[B](f: A => Option[B]): Option[B] = fa.flatMap(f)
class MonadFunctorSpec extends AnyFlatSpec with Matchers with AppendedClues with PendingIfUnimplemented:
"functorFromMonad" should "return a working functor" in {
Functor.functorFromMonad[Option](new Monad[Option] {
def pure[A](a: A): Option[A] = Some(a)
def flatMap[A, B](fa: Option[A])(f: A => Option[B]): Option[B] =
fa.flatMap(f)
}).map[Int, String](Some(3))(_.toString) shouldBe Some("3")
Functor.functorFromMonad[Option].map(Some(3))(_.toString) shouldBe Some("3")
}
}
......@@ -2,30 +2,30 @@ package monads
import org.scalatest._
import testutil.PendingIfUnimplemented
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
class MonadSpec extends FlatSpec with Matchers with AppendedClues with PendingIfUnimplemented {
class MonadSpec extends AnyFlatSpec with Matchers with AppendedClues with PendingIfUnimplemented:
"map2" should "combine two monadic values" in {
tupleMonad.map2(Tuple1(1), Tuple1(2))((a, b) => a + b) shouldBe Tuple1(3)
Tuple1(1).map2(Tuple1(2))((a, b) => a + b) shouldBe Tuple1(3)
}
"sequence" should "correctly sequence all values" in {
tupleMonad.sequence(List(
List(
Tuple1(1),
Tuple1(2),
Tuple1(3)
)) shouldBe Tuple1(List(1,2,3))
).sequence shouldBe Tuple1(List(1,2,3))
}
"compose" should "correctly compose monad functions" in {
val f: Int => Tuple1[Double] = a => Tuple1(a/2.0)
val g: Double => Tuple1[String] = a => Tuple1(a.toString)
tupleMonad.compose(f)(g)(3) shouldBe Tuple1("1.5")
summon[Monad[Tuple1]].compose(f)(g)(3) shouldBe Tuple1("1.5")
}
val tupleMonad = new Monad[Tuple1] {
given Monad[Tuple1] with
def pure[A](a: A): Tuple1[A] = Tuple1(a)
def flatMap[A, B](fa: Tuple1[A])(f: A => Tuple1[B]): Tuple1[B] =
f(fa._1)
}
}
extension [A](fa: Tuple1[A])
def flatMap[B](f: A => Tuple1[B]): Tuple1[B] = f(fa._1)
......@@ -5,14 +5,16 @@ import parsers.ContactParser.address
import parsers.lib.Parsers._
import parsers.lib._
import testutil.PendingIfUnimplemented
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
class AddressParserSpec extends FlatSpec with Matchers with AppendedClues with PendingIfUnimplemented {
class AddressParserSpec extends AnyFlatSpec with Matchers with AppendedClues with PendingIfUnimplemented {
"The address parser" should "match an address of the form <street> <number>, <code> <city>" in {
address.parse("Hublandstraße 123, 97074 Würzburg") shouldBe Done("",Address("Hublandstraße", 123, 97074, "Würzburg"))
}
it should "not accept other formats" in {
for {
for
wrong <- List(
"Hublandstraße 123 97074 Würzburg",
"Hublandstraße Abc, 97074 Würzburg",
......@@ -20,8 +22,7 @@ class AddressParserSpec extends FlatSpec with Matchers with AppendedClues with P
"Hublandstraße123,97074Würzburg",
"",
)
} {
do
address.parse(wrong) should matchPattern { case Fail(_,_) => }
}
}
}
\ No newline at end of file
......@@ -5,8 +5,10 @@ import parsers.Combinators.many1
import parsers.lib.Parsers._
import parsers.lib._
import testutil.PendingIfUnimplemented
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
class Many1Spec extends FlatSpec with Matchers with AppendedClues with PendingIfUnimplemented {
class Many1Spec extends AnyFlatSpec with Matchers with AppendedClues with PendingIfUnimplemented {
"the many1 combinator" should "match a single match of the given parser" in {
many1(string("a")).parse("abc") shouldBe Done("bc", NonEmptyList("a", Nil))
}
......
......@@ -2,8 +2,10 @@ package readerwriter
import org.scalatest._
import testutil.PendingIfUnimplemented
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
class RandomSpec extends FlatSpec with Matchers with AppendedClues with PendingIfUnimplemented {
class RandomSpec extends AnyFlatSpec with Matchers with AppendedClues with PendingIfUnimplemented:
val initial = Simple(192837465L)
val (r1, i1) = initial.nextInt
val (r2, i2) = r1.nextInt
......@@ -15,4 +17,3 @@ class RandomSpec extends FlatSpec with Matchers with AppendedClues with PendingI
it should "result in the same rng state as passing state manually" in {
Randoms.threeInts.run(initial)._1 shouldBe r3
}
}
......@@ -3,8 +3,10 @@ package readerwriter
import org.scalatest._
import testutil.PendingIfUnimplemented
import java.time.LocalDate
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
class ReaderSpec extends FlatSpec with Matchers with AppendedClues with PendingIfUnimplemented {
class ReaderSpec extends AnyFlatSpec with Matchers with AppendedClues with PendingIfUnimplemented:
val exampleRequest = Request(
Some("Mister X"),
"de-DE",
......@@ -25,7 +27,6 @@ class ReaderSpec extends FlatSpec with Matchers with AppendedClues with PendingI
}
"sayBye" should "contain the correct user name and date" in {
Readers.sayBye.run(exampleRequest) shouldBe "Goodbye Mister X, today is 2019-06-26"
Readers.sayBye.run(exampleRequest) shouldBe "Goodbye Mister X, now is 2019-06-26"
}
}
......@@ -4,8 +4,10 @@ import java.time.LocalDate
import org.scalatest._
import testutil.PendingIfUnimplemented
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
class WriterSpec extends FlatSpec with Matchers with AppendedClues with PendingIfUnimplemented {
class WriterSpec extends AnyFlatSpec with Matchers with AppendedClues with PendingIfUnimplemented:
"collatzDepth" should "keep a log of the search" in {
val (log, _) = Writers.collatzDepth(3).v
log shouldBe List(
......@@ -53,5 +55,4 @@ class WriterSpec extends FlatSpec with Matchers with AppendedClues with PendingI
val (_, res) = Writers.collatzSearch(1, 5).v
res shouldBe 3
}
}
......@@ -6,10 +6,8 @@ import org.scalatest._
* Mix into a test suite to mark tests for ??? methods as "pending" instead of "failed"
*/
trait PendingIfUnimplemented extends TestSuiteMixin { this: TestSuite =>
abstract override def withFixture(test: NoArgTest): Outcome = {
super.withFixture(test) match {
abstract override def withFixture(test: NoArgTest): Outcome =
super.withFixture(test) match
case Failed(_: NotImplementedError) => Pending
case other => other
}
}
}
package typeclasses
import org.scalatest._
import testutil.PendingIfUnimplemented
@SuppressWarnings(Array("org.wartremover.warts.All"))
class FunctorSpec extends FlatSpec with Matchers with AppendedClues with PendingIfUnimplemented {
"The Functor instance for Option" should "be available in implicit scope" in {
"implicitly[Functor[Option]]" should compile
}
}