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 409 additions and 75 deletions
package typeclasses
case class Person(lastName: String, firstName: String, age: Int)
object Person {
val odersky = Person("Odersky", "Martin", 60)
val curry = Person("Curry", "Haskell", 119)
}
\ No newline at end of file
......@@ -2,73 +2,56 @@ package algebra
import org.scalatest._
import testutil.PendingIfUnimplemented
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
class MonoidsSpec extends FlatSpec with Matchers with AppendedClues with PendingIfUnimplemented {
class MonoidsSpec extends AnyFlatSpec with Matchers with AppendedClues with PendingIfUnimplemented:
"The addditive Int monoid" should "have the right zero element" in {
Monoids.intAddition.zero shouldBe 0
intAddition.zero shouldBe 0
}
it should "combine multiple values correctly" in {
Monoids.intAddition.op(1, 2) shouldBe 3
intAddition.combine(1, 2) shouldBe 3
}
"The multiplicative Int monoid" should "have the right zero element" in {
Monoids.intMultiplication.zero shouldBe 1
intMultiplication.zero shouldBe 1
}
it should "combine multiple values correctly" in {
Monoids.intMultiplication.op(1, 2) shouldBe 2
intMultiplication.combine(1, 2) shouldBe 2
}
"The boolean or monoid" should "have the right zero element" in {
Monoids.booleanOr.zero shouldBe false
booleanOr.zero shouldBe false
}
it should "combine multiple values correctly" in {
Monoids.booleanOr.op(false, true) shouldBe true
Monoids.booleanOr.op(false, false) shouldBe false
booleanOr.combine(false, true) shouldBe true
booleanOr.combine(false, false) shouldBe false
}
"The boolean and monoid" should "have the right zero element" in {
Monoids.booleanAnd.zero shouldBe true
booleanAnd.zero shouldBe true
}
it should "combine multiple values correctly" in {
Monoids.booleanAnd.op(false, true) shouldBe false
Monoids.booleanAnd.op(false, false) shouldBe false
Monoids.booleanAnd.op(true, true) shouldBe true
booleanAnd.combine(false, true) shouldBe false
booleanAnd.combine(false, false) shouldBe false
booleanAnd.combine(true, true) shouldBe true
}
"The option monoid" should "always return the non-empty option" in {
Monoids.optionMonoid[Int].op(Some(3), None) shouldBe Some(3)
Monoids.optionMonoid[Int].op(None, Some(3)) shouldBe Some(3)
optionMonoid[Int].combine(Some(3), None) shouldBe Some(3)
optionMonoid[Int].combine(None, Some(3)) shouldBe Some(3)
}
"The endofunction monoid" should "always give the right zero element" in {
Monoids.endoMonoid[Int].zero(3) shouldBe 3
endoMonoid[Int].zero(3) shouldBe 3
}
it should "combine the functions one way or the other" in {
Monoids.endoMonoid[Int].op(_ / 4, _ * 2)(4) shouldBe 2
}
"the foldMap implementation" should "give the right result" in {
val l = List("1", "2", "3")
Monoids.foldMap(l, new Monoid[Int] {
def zero = 10
def op(a: Int, b: Int) = a + b
})(_.toInt) shouldBe 16
}
"the balanced foldMap implementation" should "give the right result" in {
val l = Vector("1", "2", "3")
Monoids.foldMapBalanced(l, new Monoid[Int] {
def zero = 0
def op(a: Int, b: Int) = a + b
})(_.toInt) shouldBe 6
endoMonoid[Int].combine(_ / 4, _ * 2)(4) shouldBe 2
}
"the bag function" should "count correctly" in {
val words = "a rose is a rose".split(" ")
val words = "a rose is a rose".split(" ").toList
Monoids.bag(words) shouldBe Map("a" -> 2, "rose" -> 2, "is" -> 1)
bag(words) shouldBe Map("a" -> 2, "rose" -> 2, "is" -> 1)
}
}
package applicative
import org.scalatest._
import testutil.PendingIfUnimplemented
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
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))
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
val g: String => String = s => "Hello " + s
val h: Int => String = _.toHexString
val someint = Some(2)
val somestring = Some("world")
optionApplicative.map(someint)(f) shouldBe someint.map(f)
optionApplicative.map(somestring)(g) shouldBe somestring.map(g)
optionApplicative.map(None)(g) shouldBe None.map(g)
optionApplicative.map(None)(g) shouldBe None.map(g)
}
"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
}
"compose" should "create nested element with pure" in {
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 {
try
val ola: Applicative[[a] =>> Option[List[a]]] =
Applicative.compose(using optionApplicative, listApplicative)
val optList = Some(List(1, 2, 3, 4))
ola.map(optList)(_ + 10) shouldBe Some(List(11, 12, 13, 14))
catch case e: StackOverflowError =>
fail("StackOverflowError. Did you override ap or map2?")
}
package applicative
import org.scalatest._
import testutil.PendingIfUnimplemented
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
import Validated.*
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", 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[[a] =>> Validated[String, a]]]
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
}
}
package monads
import org.scalatest._
import testutil.PendingIfUnimplemented
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
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].map(Some(3))(_.toString) shouldBe Some("3")
}
package monads
import org.scalatest._
import testutil.PendingIfUnimplemented
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
class MonadSpec extends AnyFlatSpec with Matchers with AppendedClues with PendingIfUnimplemented:
"map2" should "combine two monadic values" in {
Tuple1(1).map2(Tuple1(2))((a, b) => a + b) shouldBe Tuple1(3)
}
"sequence" should "correctly sequence all values" in {
List(
Tuple1(1),
Tuple1(2),
Tuple1(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)
summon[Monad[Tuple1]].compose(f)(g)(3) shouldBe Tuple1("1.5")
}
given Monad[Tuple1] with
def pure[A](a: A): Tuple1[A] = Tuple1(a)
extension [A](fa: Tuple1[A])
def flatMap[B](f: A => Tuple1[B]): Tuple1[B] = f(fa._1)
package parsers
import org.scalatest._
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 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
wrong <- List(
"Hublandstraße 123 97074 Würzburg",
"Hublandstraße Abc, 97074 Würzburg",
"Hublandstraße, 97074 Würzburg",
"Hublandstraße123,97074Würzburg",
"",
)
do
address.parse(wrong) should matchPattern { case Fail(_,_) => }
}
}
\ No newline at end of file
package parsers
import org.scalatest._
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 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))
}
it should "match the given parser multiple times" in {
many1(string("a")).parse("aaabc") shouldBe Done("bc", NonEmptyList("a", List("a", "a")))
}
it should "fail, if no matching element is found" in {
many1(string("a")).parse("zzz") should matchPattern { case Fail("zzz", _) => }
}
}
\ No newline at end of file
package readerwriter
import org.scalatest._
import testutil.PendingIfUnimplemented
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
class RandomSpec extends AnyFlatSpec with Matchers with AppendedClues with PendingIfUnimplemented:
val initial = Simple(192837465L)
val (r1, i1) = initial.nextInt
val (r2, i2) = r1.nextInt
val (r3, i3) = r2.nextInt
"threeInts" should "have the same result as passing state manually" in {
Randoms.threeInts.run(initial)._2 shouldBe ((i1, i2, i3))
}
it should "result in the same rng state as passing state manually" in {
Randoms.threeInts.run(initial)._1 shouldBe r3
}
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 AnyFlatSpec with Matchers with AppendedClues with PendingIfUnimplemented:
val exampleRequest = Request(
Some("Mister X"),
"de-DE",
"/hello",
Map(),
LocalDate.of(2019,6,26)
)
val noUserRequest = exampleRequest.copy(user = None)
"formatUser" should "read the username or substitute \"anonymous\"" in {
Readers.formatUser.run(exampleRequest) shouldBe "Mister X"
Readers.formatUser.run(noUserRequest) shouldBe "anonymous"
}
"formatTime" should "output the string representation of a request date" in {
Readers.formatTime.run(exampleRequest) shouldBe "2019-06-26"
}
"sayBye" should "contain the correct user name and date" in {
Readers.sayBye.run(exampleRequest) shouldBe "Goodbye Mister X, now is 2019-06-26"
}
package readerwriter
import java.time.LocalDate
import org.scalatest._
import testutil.PendingIfUnimplemented
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
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(
"got 3, tripling plus one",
"got 10, halving",
"got 5, tripling plus one",
"got 16, halving",
"got 8, halving",
"got 4, halving",
"got 2, halving",
"got 1, doing nothing",
)
}
it should "return the right depth" in {
val (_, depth) = Writers.collatzDepth(3).v
depth shouldBe 7
}
"collatzSearch" should "keep a log, together with collatzDepth" in {
val (log, _) = Writers.collatzSearch(1, 5).v
log shouldBe List(
"testing 1",
"got 1, doing nothing",
"depth was 0",
"testing 2",
"got 2, halving",
"got 1, doing nothing",
"depth was 1",
"testing 3",
"got 3, tripling plus one",
"got 10, halving",
"got 5, tripling plus one",
"got 16, halving",
"got 8, halving",
"got 4, halving",
"got 2, halving",
"got 1, doing nothing",
"depth was 7",
"returning 3",
)
}
it should "find the smallest number with at least given depth" in {
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
}
}
}