Skip to content
Snippets Groups Projects
Commit 2ab69e12 authored by Alexander Gehrke's avatar Alexander Gehrke
Browse files

Begin conversion to Scala 3

- Changed build settings
- Changed kind-projector code to new lambda syntax
- Applied automatic syntax rewrites
parent 0cf1eca2
No related branches found
No related tags found
No related merge requests found
Showing
with 55 additions and 102 deletions
name := "short-exercises"
organization := "de.uniwue.fp"
organization := "de.un.1iwue.fp"
version := "0.1-SNAPSHOT"
scalaVersion := "2.13.1"
scalaVersion := "3.1.1"
scalacOptions ++= Seq(
"-deprecation",
"-encoding", "UTF-8",
"-feature",
"-unchecked",
"-Xlint",
"-Wdead-code",
"-Wnumeric-widen",
"-Wvalue-discard",
"-Wunused:patvars,privates,locals,params,-imports",
"-Ypatmat-exhaust-depth", "40",
"-language:higherKinds",
"-language:implicitConversions",
)
resolvers += Resolver.sonatypeRepo("releases")
addCompilerPlugin("org.typelevel" %% "kind-projector" % "0.11.0" cross CrossVersion.full)
// Disallow some language construcs
// your bonus exercises will have to compile with these options
addCompilerPlugin("org.wartremover" %% "wartremover" % "2.4.5" cross CrossVersion.full)
addCompilerPlugin("org.wartremover" %% "wartremover" % "3.0.2" cross CrossVersion.full)
scalacOptions ++= Seq(
"-P:wartremover:traverser:org.wartremover.warts.AsInstanceOf",
"-P:wartremover:traverser:org.wartremover.warts.IsInstanceOf",
......@@ -36,5 +28,6 @@ scalacOptions ++= Seq(
"-P:wartremover:traverser:org.wartremover.warts.While",
)
libraryDependencies += "org.scalactic" %% "scalactic" % "3.1.1"
libraryDependencies += "org.scalatest" %% "scalatest" % "3.1.1" % "test"
libraryDependencies += "org.scalactic" %% "scalactic" % "3.2.11"
libraryDependencies += "org.scalatest" %% "scalatest" % "3.2.11" % "test"
libraryDependencies += "org.typelevel" %% "cats-core" % "2.7.0"
sbt.version=1.3.5
sbt.version=1.6.2
package algebra
trait Monoid[A] {
trait Monoid[A]:
def op(a1: A, a2: A): A
def zero: A
}
package algebra
object Monoids {
object Monoids:
def intAddition: Monoid[Int] = new Monoid[Int] {
def zero = ???
def op(a: Int, b: Int): Int = ???
......@@ -32,4 +32,3 @@ object Monoids {
def bag[A](as: IndexedSeq[A]): Map[A, Int] = ???
}
package applicative
trait Applicative[F[_]] {
trait Applicative[F[_]]:
def pure[A](a: A): F[A]
def ap[A, B](ff: F[A => B])(fa: F[A]): F[B] = map2(ff, fa)((f, a) => f(a))
......@@ -16,9 +16,9 @@ trait Applicative[F[_]] {
// implement pure first
// then write the signature for ap and map2
// then implement one of them
def compose[G[_]](implicit G: Applicative[G]): Applicative[Lambda[a => F[G[a]]]] = {
def compose[G[_]](implicit G: Applicative[G]): Applicative[[a] =>> F[G[a]]] =
val F = this
new Applicative[Lambda[a => F[G[a]]]] {
new Applicative[[a] =>> F[G[a]]] {
def pure[A](a: A): F[G[A]] = ???
//note: when you are done implementing this, the test for ap/map2 will result in a StackOverflow until you implement one of them
......@@ -28,5 +28,3 @@ trait Applicative[F[_]] {
// or
// override def map2... = ???
}
}
}
package applicative
trait Monad[F[_]] extends Applicative[F] {
trait Monad[F[_]] extends Applicative[F]:
def flatMap[A, B](fa: F[A])(f: A => F[B]): F[B] = flatten(map(fa)(f))
def flatten[A](fa: F[F[A]]): F[A] = flatMap(fa)(identity)
override def map[A, B](fa: F[A])(f: A => B): F[B] = flatMap(fa)(f andThen pure)
override def map2[A, B, C](fa: F[A], fb: F[B])(f: (A, B) => C): F[C] = flatMap(fa)(a => map(fb)(b => f(a,b)))
}
......@@ -4,9 +4,7 @@ sealed trait Validated[+E, +A]
case class Valid[+A](a:A) extends Validated[Nothing, A]
case class Invalid[+E](head: E, tail: List[E] = List()) extends Validated[E, Nothing]
object Validated {
implicit def validatedApplicative[E]: Applicative[Validated[E, +?]] = new Applicative[Validated[E,+?]] {
object Validated:
given validatedApplicative[E]: Applicative[[a] =>> Validated[E, a]] with
def pure[A](a: A) = Valid(a)
// add map2 or ap here
}
}
package datastructures
sealed trait List[+A] {
def head = this match {
sealed trait List[+A]:
def head = this match
case Nil => sys.error("head of empty list")
case Cons(a, _) => a
}
def tail: List[A] = ???
......@@ -13,12 +12,10 @@ sealed trait List[+A] {
def setHead[AA >: A](head: AA): List[AA] = ???
def foldLeft[B](z: B)(f: (B, A) => B): B = ???
}
case object Nil extends List[Nothing]
case class Cons[+A](elem: A, rest: List[A]) extends List[A]
object List {
object List:
def apply[A](as: A*): List[A] =
if (as.isEmpty) Nil
if as.isEmpty then Nil
else Cons(as.head, apply(as.tail: _*))
}
package datastructures
object Parametricity {
object Parametricity:
// with our compiler settings from build.sbt, there are even less
// possibilities to do something wrong here without the compiler complaining
def para[A,B,C](a: A, b: B)(f: (A,B) => C): C = ???
}
package errors
sealed trait Either[+E, +A] {
def map[B](f: A => B): Either[E, B] = this match {
sealed trait Either[+E, +A]:
def map[B](f: A => B): Either[E, B] = this match
case Left(e) => Left(e)
case Right(a) => Right(f(a))
}
def flatMap[EE >: E, B](f: A => Either[EE, B]): Either[EE, B] = this match{
def flatMap[EE >: E, B](f: A => Either[EE, B]): Either[EE, B] = this match
case Left(e) => Left(e)
case Right(a) => f(a)
}
def map2[EE >: E, B, C](other: Either[EE, B])(f: (A, B) => C): Either[EE, C] = ???
}
final case class Left[+E](value: E) extends Either[E, Nothing]
final case class Right[+A](value: A) extends Either[Nothing, A]
package errors
sealed trait Option[+A] {
sealed trait Option[+A]:
def map[B](f: A => B): Option[B] = ???
def getOrElse[B >: A](default: => B): B = ???
......@@ -8,11 +8,9 @@ sealed trait Option[+A] {
def flatMap[B](f: A => Option[B]): Option[B] = ???
def filter[B](f: A => Boolean): Option[A] = ???
}
final case class Some[+A](get: A) extends Option[A]
case object None extends Option[Nothing]
object Option {
object Option:
def sequence[A](list: List[Option[A]]): Option[List[A]] = ???
}
package errors
object Team {
object Team:
val persons = List(
Person("Dagobert", "Finanzabteilung"),
Person("Donald", "Spassabteilung"),
......@@ -13,7 +13,6 @@ object Team {
persons.find(_.name == name).fold(None: Option[Person])(a => Some(a))
def getTeam(name1: String, name2: String): Option[Team] = ???
}
final case class Person(
name: String,
......
package laziness
sealed trait LazyList[+A] {
sealed trait LazyList[+A]:
// uncomment to be able to use cons(h, t) and empty directly
// imports methods from the companion object
//import LazyList._
......@@ -16,31 +16,26 @@ sealed trait LazyList[+A] {
// Methods shown during lecture
def headOption: Option[A] = this match {
def headOption: Option[A] = this match
case Cons(h, _) => Some(h())
case Empty => None
}
def exists(p: A => Boolean): Boolean = this match {
def exists(p: A => Boolean): Boolean = this match
case Cons(x, xs) => p(x()) || xs().exists(p)
case Empty => false
}
def foldRight[B](z: => B)(f: (A, => B) => B): B = this match {
def foldRight[B](z: => B)(f: (A, => B) => B): B = this match
case Cons(x, xs) => f(x(), xs().foldRight(z)(f))
case Empty => z
}
}
case object Empty extends LazyList[Nothing]
case class Cons[+A](h: () => A, t: () => LazyList[A]) extends LazyList[A]
object LazyList { // companion object
object LazyList: // companion object
def fibs: LazyList[Int] = {
def fibs: LazyList[Int] =
// tip: write a recursive def here and call it with some start values
???
}
def unfold[A, S](z: S)(f: S => Option[(A, S)]): LazyList[A] = ???
......@@ -49,18 +44,16 @@ object LazyList { // companion object
// Methods shown during Lecture
def cons[A](h: => A, t: => LazyList[A]): LazyList[A] = {
def cons[A](h: => A, t: => LazyList[A]): LazyList[A] =
lazy val head = h
lazy val tail = t
Cons(() => head, () => tail)
}
def empty[A]: LazyList[A] = Empty
def apply[A](as: A*): LazyList[A] =
if (as.isEmpty) empty
if as.isEmpty then empty
else cons(as.head, apply(as.tail: _*))
val ones: LazyList[Int] = cons(1, ones)
}
package monads
trait Monad[F[_]] {
trait Monad[F[_]]:
def pure[A](a: A): F[A]
def flatMap[A, B](fa: F[A])(f: A => F[B]): F[B]
......@@ -9,14 +9,11 @@ trait Monad[F[_]] {
def sequence[A](fas: List[F[A]]): F[List[A]] = ???
def compose[A, B, C](f: A => F[B])(g: B => F[C]): A => F[C] = ???
}
trait Functor[F[_]] {
trait Functor[F[_]]:
def map[A, B](a: F[A])(f: A => B): F[B]
}
object Functor {
object Functor:
def functorFromMonad[F[_]](M: Monad[F]): Functor[F] = new Functor[F] {
def map[A, B](a: F[A])(f: A => B): F[B] = ???
}
}
package monads
final case class Id[A](value: A)
object Id {
object Id:
// No tests. If it compiles, it's correct.
implicit val idMonad = new Monad[Id] {
given Monad[Id] with
def pure[A](a: A): Id[A] = ???
def flatMap[A, B](fa: Id[A])(f: A => Id[B]): Id[B] = ???
}
}
......@@ -5,10 +5,9 @@ import parsers.lib.Parsers._
import parsers.lib.ToParserOps._
import parsers.lib._
object Combinators {
object Combinators:
/* Implement many1, which matches at least one element, returning a NonEmptyList.
* If no element is found, the parser should fail. You may use any other parsers and combinators we have defined.
*/
def many1[A](p: Parser[A]): Parser[NonEmptyList[A]] = ???
}
......@@ -9,7 +9,7 @@ case class Contact(name:String, address: Address, phone: Option[Phone])
case class Address(street: String, number: Int, postCode: Int, city: String)
case class Phone(prefix: String, suffix:String)
object ContactParser {
object ContactParser:
/* This parser should parse strings of the form
* <street> <number>, <postCode> <city>
......@@ -17,4 +17,3 @@ object ContactParser {
* Each whitespace in the pattern above should be present (one or more whitespace characters).
*/
def address: Parser[Address] = ???
}
......@@ -4,22 +4,19 @@ package parsers.lib
* We only have a single function, representing the parsing of a string. So we can declare parsers by writing a
* function literal for such a function
*/
trait Parser[+A] {
trait Parser[+A]:
def parse(input: String): ParseResult[A]
}
object Parser {
object Parser:
implicit val parserMonad: Monad[Parser] = new Monad[Parser] {
def pure[A](a: A): Parser[A] = success(a)
def flatMap[A, B](fa: Parser[A])(f: A => Parser[B]): Parser[B] =
input => fa.parse(input) match {
input => fa.parse(input) match
case Done(rest, a) => f(a).parse(rest)
case Fail(rest, msg) => Fail(rest, msg)
}
}
def success[A](a: A): Parser[A] = input => Done(input, a)
def fail[A](message: String): Parser[A] = input => Fail(input, message)
}
package parsers.lib
trait ParserOps[A] {
trait ParserOps[A]:
val self: Parser[A]
def | [B>:A](pb: Parser[B]): Parser[B] = Parsers.or(self, pb)
def ~[B](next: => Parser[B]): Parser[(A, B)] = Parsers.andThen(self, next)
def many: Parser[List[A]] = Parsers.many(self)
}
object ToParserOps {
object ToParserOps:
implicit def toParserOps[A](p: Parser[A]): ParserOps[A] =
new ParserOps[A] {
val self: Parser[A] = p
}
}
......@@ -4,29 +4,27 @@ import Monad._
import scala.util.matching.Regex
import ToParserOps._
trait Parsers {
trait Parsers:
def char(c: Char): Parser[Char]
def string(s: String): Parser[String]
def regex(r: Regex): Parser[String]
def digits: Parser[String]
def int: Parser[Int]
}
object Parsers extends Parsers {
object Parsers extends Parsers:
def string(s: String): Parser[String] =
input =>
if(input.startsWith(s)) Done(input.substring(s.length), s)
if input.startsWith(s) then Done(input.substring(s.length), s)
else Fail(input, s"""expected "$s"""")
def char(c: Char): Parser[Char] = string(c.toString).map(_.charAt(0))
def regex(r: Regex): Parser[String] =
input =>
r.findPrefixOf(input) match {
r.findPrefixOf(input) match
case Some(m) => Done(input.substring(m.length), m)
case None => Fail(input, s""""expected match for "$r"""")
}
def digits: Parser[String] = regex("[0-9]+".r)
......@@ -34,21 +32,20 @@ object Parsers extends Parsers {
def or[A](pa: Parser[A], pb: Parser[A]): Parser[A] =
input =>
pa.parse(input) match {
pa.parse(input) match
case Done(rest, out) => Done(rest, out)
case Fail(_, _) => pb.parse(input)
}
def andThen[A,B](p: Parser[A], next: => Parser[B]): Parser[(A, B)] = for {
def andThen[A,B](p: Parser[A], next: => Parser[B]): Parser[(A, B)] = for
a <- p
b <- next
} yield (a,b)
yield (a,b)
def many[A](p: Parser[A]): Parser[List[A]] = (
for {
for
a <- p
tail <- many(p)
} yield a :: tail
yield a :: tail
) | Monad[Parser].pure(Nil)
def manyN[A](p: Parser[A], n: Int): Parser[List[A]] =
......@@ -60,6 +57,5 @@ object Parsers extends Parsers {
/** Match any number of non-whitespace characters */
val word: Parser[String] = regex(raw"\S*".r)
}
// address.parse("Hublandstraße 123, 97074 Würzburg") ==
// Done("", Address("Hublandstraße", 123, 97074, "Würzburg"))
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment