diff --git a/README.md b/README.md index 7591b688e696c12b93f5a2740a3e7726631774c3..89261a2a4fdb1a5c3e60b9a40f67a059a67637b3 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,9 @@ usually marked with `???`. Lectures not listed here are not migrated to Scala | 4: Laziness | [`laziness`](src/main/scala/laziness/) | `testOnly laziness.*` | 5: Algebras, Laws and monoids | [`algebra`](src/main/scala/algebra/) | `testOnly algebra.*` | 6: Foldables and Functors | [`foldfunc`](src/main/scala/foldfunc/) | `testOnly foldfunc.*` +| 7: Monads | [`monads`](src/main/scala/monads/) | `testOnly monads.*` +| 8: Applicative Functors | [`applicative`](src/main/scala/applicative/) | `testOnly applicative.*` +| 9: An algebraic View on Monads | [`readerwriter`](src/main/scala/readerwriter/) | `testOnly readerwriter.*` ## Usage tips: To keep your local solutions to the exercises when pulling from the repository, diff --git a/src/main/scala/readerwriter/Randoms.scala b/src/main/scala/readerwriter/Randoms.scala index a5cc3ea19aa9e84ea2a290e6c2bef32fa192d578..e1ff2cb040507304a6b781eaa7ba9b441ff7498e 100644 --- a/src/main/scala/readerwriter/Randoms.scala +++ b/src/main/scala/readerwriter/Randoms.scala @@ -1,19 +1,15 @@ package readerwriter -import readerwriter.internal.State, State._ -import util._ +import readerwriter.internal.State, State.* object Randoms: def threeInts: State[RNG, (Int, Int, Int)] = ??? - /*@formatter:off*/ def randomInt: State[RNG, Int] = for rng <- get[RNG] (rng2, i) = rng.nextInt _ <- set(rng2) yield i - /*@formatter:on*/ - def nonNegativeInt: State[RNG, Int] = for i <- randomInt @@ -23,6 +19,8 @@ trait RNG: def nextInt: (RNG, Int) case class Simple(seed: Long) extends RNG: + /** Basically the same formula as in java.util.Random + * See https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/Random.html#next(int) */ def nextInt: (RNG, Int) = val newSeed = (seed * 0x5DEECE66DL + 0xBL) & 0xFFFFFFFFFFFFL val nextRNG = Simple(newSeed) diff --git a/src/main/scala/readerwriter/Readers.scala b/src/main/scala/readerwriter/Readers.scala index 18b7dc9cd8a99b8054b5305a92c8404d228f4ac6..eeae72fa4afca74c9d075a2cae120d79a414d7b7 100644 --- a/src/main/scala/readerwriter/Readers.scala +++ b/src/main/scala/readerwriter/Readers.scala @@ -2,8 +2,7 @@ package readerwriter import java.time.LocalDate -import readerwriter.internal.Reader, Reader._ -import util._ +import readerwriter.internal.Reader, Reader.* final case class Request( user: Option[String], diff --git a/src/main/scala/readerwriter/Writers.scala b/src/main/scala/readerwriter/Writers.scala index 3abbc1a184a37114d8c3ab91cfe1df74307cfa02..3f50ba9de0a9f6a734bfd865925ed50b1df8100c 100644 --- a/src/main/scala/readerwriter/Writers.scala +++ b/src/main/scala/readerwriter/Writers.scala @@ -1,9 +1,7 @@ package readerwriter -import readerwriter.internal.Writer, Writer._ -import util._ - +import readerwriter.internal.Writer, Writer.{*, given} object Writers: /* everything required to use tell and the monad operations @@ -13,7 +11,6 @@ object Writers: def collatzSearch(start: Int, limit: Int): Writer[List[String], Int] = ??? - object CollatzWithoutWriter: def collatzDepth(n: Int): (List[String], Int) = if n == 1 then diff --git a/src/main/scala/readerwriter/internal/Reader.scala b/src/main/scala/readerwriter/internal/Reader.scala index e9a12b9e916d912e95728917fd33eb38656e62d6..f2d6e0c997f45832ea4ebe5beb4c3675e011d880 100644 --- a/src/main/scala/readerwriter/internal/Reader.scala +++ b/src/main/scala/readerwriter/internal/Reader.scala @@ -2,7 +2,7 @@ package readerwriter.internal import applicative.Monad -case class Reader[R, A](run: R => A) +case class Reader[-R, A](run: R => A) object Reader: def ask[R]: Reader[R, R] = Reader(x => x) diff --git a/src/main/scala/readerwriter/internal/State.scala b/src/main/scala/readerwriter/internal/State.scala index ca0ae913b02084027fc5a98b8704d3696fd15ec8..b41c36e237ec0501a4c8b01eb0a1ee5e71e0bc52 100644 --- a/src/main/scala/readerwriter/internal/State.scala +++ b/src/main/scala/readerwriter/internal/State.scala @@ -8,6 +8,9 @@ import applicative.Monad case class State[S, A] private (run: S => (S, A)) case object State: + def get[S]: State[S, S] = State(s => (s, s)) + def set[S](s: S): State[S, Unit] = State(_ => (s, ())) + given stateMonad[S]: Monad[[a] =>> State[S, a]] with def pure[A](a: A): State[S, A] = State(s => (s, a)) extension [A](fa: State[S, A]) @@ -15,6 +18,3 @@ case object State: val (s1, a) = fa.run(s) f(a).run(s1) ) - - def get[S]: State[S, S] = State(s => (s, s)) - def set[S](s: S): State[S, Unit] = State(_ => (s, ())) diff --git a/src/main/scala/readerwriter/internal/Writer.scala b/src/main/scala/readerwriter/internal/Writer.scala index 7e4e0b85637dbebc65393a10f966fbffb34f6a84..1a7ee8d064713c8d0acfca8377d7b7d28d565462 100644 --- a/src/main/scala/readerwriter/internal/Writer.scala +++ b/src/main/scala/readerwriter/internal/Writer.scala @@ -6,6 +6,7 @@ import applicative.Monad final case class Writer[L, A](v: (L, A)) object Writer: + given [A]: Monoid[List[A]] with def zero: List[Nothing] = List.empty def combine(l1: List[A], l2: List[A]): List[A] = l1 ++ l2 diff --git a/src/main/scala/util/package.scala b/src/main/scala/util/package.scala deleted file mode 100644 index b3402eacf8c76a175214803d7825f6a50bde07b2..0000000000000000000000000000000000000000 --- a/src/main/scala/util/package.scala +++ /dev/null @@ -1,6 +0,0 @@ -import applicative.Monad - -package object util: - implicit class MonadOps[F[_] : Monad, A](fa: F[A]): - def flatMap[B](f: A => F[B]): F[B] = implicitly[Monad[F]].flatMap(fa)(f) - def map[B](f: A => B): F[B] = implicitly[Monad[F]].map(fa)(f) diff --git a/src/test/scala/readerwriter/ReaderSpec.scala b/src/test/scala/readerwriter/ReaderSpec.scala index bf036ac6b2d0291476e605bd7dbb2c33db4d39ab..78878e8a63b129f7318f87216c14c3365b2c964f 100644 --- a/src/test/scala/readerwriter/ReaderSpec.scala +++ b/src/test/scala/readerwriter/ReaderSpec.scala @@ -27,6 +27,6 @@ class ReaderSpec extends AnyFlatSpec with Matchers with AppendedClues with Pendi } "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" }