From 9a43b3d11856966234cd85633427be217bff322b Mon Sep 17 00:00:00 2001 From: Nithin Gowda <79574931+Nithingowda16@users.noreply.github.com> Date: Mon, 18 Mar 2024 10:15:24 +0530 Subject: [PATCH] Add files via upload --- SCALA/GITHUB/PROJECT/build.properties | 1 + SCALA/GITHUB/dependbot.yml | 7 ++ SCALA/SRC/MAIN/SCALA/TEST/MYSUITE.scala | 9 ++ SCALA/SRC/MAIN/SCALA/build.sbt | 10 +++ SCALA/SRC/MAIN/SCALA/contextfunctions.scala | 40 +++++++++ SCALA/SRC/MAIN/SCALA/conversion.scala | 34 ++++++++ SCALA/SRC/MAIN/SCALA/enumtypes.scala | 39 +++++++++ SCALA/SRC/MAIN/SCALA/giveinstances.scala | 32 +++++++ SCALA/SRC/MAIN/SCALA/intersection.scala | 26 ++++++ SCALA/SRC/MAIN/SCALA/main.scala | 31 +++++++ SCALA/SRC/MAIN/SCALA/multiversal.scala | 35 ++++++++ SCALA/SRC/MAIN/SCALA/parameteruntupling.scala | 15 ++++ SCALA/SRC/MAIN/SCALA/patternmatching.scala | 83 +++++++++++++++++++ SCALA/SRC/MAIN/SCALA/structuraltypes.scala | 26 ++++++ SCALA/SRC/MAIN/SCALA/traitparmas.scala | 19 +++++ SCALA/SRC/MAIN/SCALA/typelamdas.scala | 15 ++++ SCALA/SRC/MAIN/SCALA/uniontypes.scala | 39 +++++++++ 17 files changed, 461 insertions(+) create mode 100644 SCALA/GITHUB/PROJECT/build.properties create mode 100644 SCALA/GITHUB/dependbot.yml create mode 100644 SCALA/SRC/MAIN/SCALA/TEST/MYSUITE.scala create mode 100644 SCALA/SRC/MAIN/SCALA/build.sbt create mode 100644 SCALA/SRC/MAIN/SCALA/contextfunctions.scala create mode 100644 SCALA/SRC/MAIN/SCALA/conversion.scala create mode 100644 SCALA/SRC/MAIN/SCALA/enumtypes.scala create mode 100644 SCALA/SRC/MAIN/SCALA/giveinstances.scala create mode 100644 SCALA/SRC/MAIN/SCALA/intersection.scala create mode 100644 SCALA/SRC/MAIN/SCALA/main.scala create mode 100644 SCALA/SRC/MAIN/SCALA/multiversal.scala create mode 100644 SCALA/SRC/MAIN/SCALA/parameteruntupling.scala create mode 100644 SCALA/SRC/MAIN/SCALA/patternmatching.scala create mode 100644 SCALA/SRC/MAIN/SCALA/structuraltypes.scala create mode 100644 SCALA/SRC/MAIN/SCALA/traitparmas.scala create mode 100644 SCALA/SRC/MAIN/SCALA/typelamdas.scala create mode 100644 SCALA/SRC/MAIN/SCALA/uniontypes.scala diff --git a/SCALA/GITHUB/PROJECT/build.properties b/SCALA/GITHUB/PROJECT/build.properties new file mode 100644 index 0000000..4d5f78c --- /dev/null +++ b/SCALA/GITHUB/PROJECT/build.properties @@ -0,0 +1 @@ +sbt.version=1.9.9 \ No newline at end of file diff --git a/SCALA/GITHUB/dependbot.yml b/SCALA/GITHUB/dependbot.yml new file mode 100644 index 0000000..7a38c2b --- /dev/null +++ b/SCALA/GITHUB/dependbot.yml @@ -0,0 +1,7 @@ +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + day: "tuesday" \ No newline at end of file diff --git a/SCALA/SRC/MAIN/SCALA/TEST/MYSUITE.scala b/SCALA/SRC/MAIN/SCALA/TEST/MYSUITE.scala new file mode 100644 index 0000000..2f27ec4 --- /dev/null +++ b/SCALA/SRC/MAIN/SCALA/TEST/MYSUITE.scala @@ -0,0 +1,9 @@ +// For more information on writing tests, see +// https://scalameta.org/munit/docs/getting-started.html +class MySuite extends munit.FunSuite { + test("example test that succeeds") { + val obtained = 42 + val expected = 42 + assertEquals(obtained, expected) + } +} \ No newline at end of file diff --git a/SCALA/SRC/MAIN/SCALA/build.sbt b/SCALA/SRC/MAIN/SCALA/build.sbt new file mode 100644 index 0000000..f61fe2d --- /dev/null +++ b/SCALA/SRC/MAIN/SCALA/build.sbt @@ -0,0 +1,10 @@ +lazy val root = project + .in(file(".")) + .settings( + name := "scala3-example-project", + description := "Example sbt project that compiles using Scala 3", + version := "0.1.0", + scalaVersion := "3.3.3", + scalacOptions ++= Seq("-deprecation"), + libraryDependencies += "org.scalameta" %% "munit" % "0.7.29" % Test + ) \ No newline at end of file diff --git a/SCALA/SRC/MAIN/SCALA/contextfunctions.scala b/SCALA/SRC/MAIN/SCALA/contextfunctions.scala new file mode 100644 index 0000000..2e95358 --- /dev/null +++ b/SCALA/SRC/MAIN/SCALA/contextfunctions.scala @@ -0,0 +1,40 @@ +import scala.concurrent.{ExecutionContext, Future} +import scala.util.Try + +/** + * Context Functions: + * - https://dotty.epfl.ch/docs/reference/contextual/context-functions.html + * - https://www.scala-lang.org/blog/2016/12/07/implicit-function-types.html + */ +object ContextFunctions: + + object context: + // type alias Contextual + type Contextual[T] = ExecutionContext ?=> T + + // sum is expanded to sum(x, y)(ctx) + def asyncSum(x: Int, y: Int): Contextual[Future[Int]] = Future(x + y) + + def asyncMult(x: Int, y: Int)(using ctx: ExecutionContext) = Future(x * y) + + object parse: + + type Parseable[T] = GivenInstances.StringParser[T] ?=> Try[T] + + def sumStrings(x: String, y: String): Parseable[Int] = + val parser = summon[GivenInstances.StringParser[Int]] + val tryA = parser.parse(x) + val tryB = parser.parse(y) + + for + a <- tryA + b <- tryB + yield a + b + + def test(): Unit = + import ExecutionContext.Implicits.global + context.asyncSum(3, 4).foreach(println) + context.asyncMult(3, 4).foreach(println) + + println(parse.sumStrings("3", "4")) + println(parse.sumStrings("3", "a")) diff --git a/SCALA/SRC/MAIN/SCALA/conversion.scala b/SCALA/SRC/MAIN/SCALA/conversion.scala new file mode 100644 index 0000000..a80dda6 --- /dev/null +++ b/SCALA/SRC/MAIN/SCALA/conversion.scala @@ -0,0 +1,34 @@ +import scala.language.implicitConversions + +/** + * Conversions: https://dotty.epfl.ch/docs/reference/contextual/conversions.html + */ +object Conversion: + + case class IntWrapper(a: Int) extends AnyVal + case class DoubleWrapper(b: Double) extends AnyVal + + def convert[T, U](x: T)(using converter: Conversion[T, U]): U = converter(x) + + given IntWrapperToDoubleWrapper: Conversion[IntWrapper, DoubleWrapper] = new Conversion[IntWrapper, DoubleWrapper] { + override def apply(i: IntWrapper): DoubleWrapper = DoubleWrapper(i.a.toDouble) + } + // Or: + // given IntWrapperToDoubleWrapper: Conversion[IntWrapper, DoubleWrapper] = + // (i: IntWrapper) => DoubleWrapper(i.a.toDouble) + + def useConversion(using f: Conversion[IntWrapper, DoubleWrapper]) = + val y: IntWrapper = IntWrapper(4) + val x: DoubleWrapper = y + x + + /* Not working anymore. + def useConversion(implicit f: A => B) = { + val y: A = ... + val x: B = a // error under Scala 3 + } + */ + + def test(): Unit = + println(useConversion) + println(convert(IntWrapper(42))) \ No newline at end of file diff --git a/SCALA/SRC/MAIN/SCALA/enumtypes.scala b/SCALA/SRC/MAIN/SCALA/enumtypes.scala new file mode 100644 index 0000000..b5c1025 --- /dev/null +++ b/SCALA/SRC/MAIN/SCALA/enumtypes.scala @@ -0,0 +1,39 @@ +/** + * Enum Types: https://dotty.epfl.ch/docs/reference/enums/adts.html + */ +object EnumTypes: + + enum ListEnum[+A]: + case Cons(h: A, t: ListEnum[A]) + case Empty + + + enum Planet(mass: Double, radius: Double): + private final val G = 6.67300E-11 + def surfaceGravity = G * mass / (radius * radius) + def surfaceWeight(otherMass: Double) = otherMass * surfaceGravity + + case Mercury extends Planet(3.303e+23, 2.4397e6) + case Venus extends Planet(4.869e+24, 6.0518e6) + case Earth extends Planet(5.976e+24, 6.37814e6) + case Mars extends Planet(6.421e+23, 3.3972e6) + case Jupiter extends Planet(1.9e+27, 7.1492e7) + case Saturn extends Planet(5.688e+26, 6.0268e7) + case Uranus extends Planet(8.686e+25, 2.5559e7) + case Neptune extends Planet(1.024e+26, 2.4746e7) + end Planet + + def test(): Unit = + val emptyList = ListEnum.Empty + val list = ListEnum.Cons(1, ListEnum.Cons(2, ListEnum.Cons(3, ListEnum.Empty))) + println("Example 1: \n"+emptyList) + println(s"${list}\n") + + def calculateEarthWeightOnPlanets(earthWeight: Double) = + val mass = earthWeight/Planet.Earth.surfaceGravity + for p <- Planet.values do + println(s"Your weight on $p is ${p.surfaceWeight(mass)}") + + println("Example 2:") + calculateEarthWeightOnPlanets(80) + end test \ No newline at end of file diff --git a/SCALA/SRC/MAIN/SCALA/giveinstances.scala b/SCALA/SRC/MAIN/SCALA/giveinstances.scala new file mode 100644 index 0000000..3475d04 --- /dev/null +++ b/SCALA/SRC/MAIN/SCALA/giveinstances.scala @@ -0,0 +1,32 @@ +import scala.util.{Success, Try} + +/** + * Implied Instances: https://dotty.epfl.ch/docs/reference/contextual/givens.html + */ +object GivenInstances: + + sealed trait StringParser[A]: + def parse(s: String): Try[A] + + object StringParser: + + def apply[A](using parser: StringParser[A]): StringParser[A] = parser + + private def baseParser[A](f: String => Try[A]): StringParser[A] = new StringParser[A] { + override def parse(s: String): Try[A] = f(s) + } + + given stringParser: StringParser[String] = baseParser(Success(_)) + given intParser: StringParser[Int] = baseParser(s => Try(s.toInt)) + + given optionParser[A](using parser: => StringParser[A]): StringParser[Option[A]] = new StringParser[Option[A]] { + override def parse(s: String): Try[Option[A]] = s match + case "" => Success(None) // implicit parser not used. + case str => parser.parse(str).map(x => Some(x)) // implicit parser is evaluated at here + } + + def test(): Unit = + println(summon[StringParser[Option[Int]]].parse("21")) + println(summon[StringParser[Option[Int]]].parse("")) + println(summon[StringParser[Option[Int]]].parse("21a")) + println(summon[StringParser[Option[Int]]](using StringParser.optionParser[Int]).parse("42")) diff --git a/SCALA/SRC/MAIN/SCALA/intersection.scala b/SCALA/SRC/MAIN/SCALA/intersection.scala new file mode 100644 index 0000000..278e91f --- /dev/null +++ b/SCALA/SRC/MAIN/SCALA/intersection.scala @@ -0,0 +1,26 @@ +/** + * Intersection Types: https://dotty.epfl.ch/docs/reference/new-types/intersection-types.html + */ +object IntersectionTypes: + + sealed trait X: + def x: Double + def tpe: X + + sealed trait Y: + def y: Double + def tpe: Y + + type P = Y & X + type PP = X & Y + + final case class Point(x: Double, y: Double) extends X with Y: + override def tpe: X & Y = ??? + + def test(): Unit = + def euclideanDistance(p1: X & Y, p2: X & Y) = + Math.sqrt(Math.pow(p2.y - p1.y, 2) + Math.pow(p2.x - p1.x, 2)) + + val p1: P = Point(3, 4) + val p2: PP = Point(6, 8) + println(euclideanDistance(p1, p2)) diff --git a/SCALA/SRC/MAIN/SCALA/main.scala b/SCALA/SRC/MAIN/SCALA/main.scala new file mode 100644 index 0000000..e748fe3 --- /dev/null +++ b/SCALA/SRC/MAIN/SCALA/main.scala @@ -0,0 +1,31 @@ +@main +def Main(args: String*): Unit = + runExample("Trait Params")(TraitParams.test()) + + runExample("Enum Types")(EnumTypes.test()) + + runExample("Context Functions")(ContextFunctions.test()) + + runExample("Given Instances")(GivenInstances.test()) + + runExample("Conversion")(Conversion.test()) + + runExample("Union Types")(UnionTypes.test()) + + runExample("Intersection Types")(IntersectionTypes.test()) + + runExample("Type Lambda")(TypeLambdas.test()) + + runExample("Multiversal Equality")(MultiversalEquality.test()) + + runExample("Parameter Untupling")(ParameterUntupling.test()) + + runExample("Structural Types")(StructuralTypes.test()) + + runExample("Pattern Matching")(PatternMatching.test()) +end Main + +private def runExample(name: String)(f: => Unit): Unit = + println(Console.MAGENTA + s"$name example:" + Console.RESET) + f + println() \ No newline at end of file diff --git a/SCALA/SRC/MAIN/SCALA/multiversal.scala b/SCALA/SRC/MAIN/SCALA/multiversal.scala new file mode 100644 index 0000000..2da7c0b --- /dev/null +++ b/SCALA/SRC/MAIN/SCALA/multiversal.scala @@ -0,0 +1,35 @@ +import scala.language.strictEquality + +/** + * Multiversal Equality: https://dotty.epfl.ch/docs/reference/contextual/multiversal-equality.html + * scala.CanEqual definition: https://github.com/lampepfl/dotty/blob/master/library/src/scala/CanEqual.scala + */ +object MultiversalEquality: + + def test(): Unit = + // Values of types Int and String cannot be compared with == or !=, + // unless we add the derived delegate instance like: + given CanEqual[Int, String] = CanEqual.derived + println(3 == "3") + + // By default, all numbers are comparable, because of; + // given canEqualNumber as CanEqual[Number, Number] = derived + println(3 == 5.1) + + // By default, all Sequences are comparable, because of; + // given canEqualSeq[T, U](using eq: CanEqual[T, U]) as CanEqual[Seq[T], Seq[U]] = derived + println(List(1, 2) == Vector(1, 2)) + + class A(a: Int) + class B(b: Int) + + val a = A(4) + val b = B(4) + + // scala.language.strictEquality is enabled, therefore we need some extra delegate instances + // to compare instances of A and B. + given CanEqual[A, B] = CanEqual.derived + given CanEqual[B, A] = CanEqual.derived + + println(a != b) + println(b == a) diff --git a/SCALA/SRC/MAIN/SCALA/parameteruntupling.scala b/SCALA/SRC/MAIN/SCALA/parameteruntupling.scala new file mode 100644 index 0000000..889c367 --- /dev/null +++ b/SCALA/SRC/MAIN/SCALA/parameteruntupling.scala @@ -0,0 +1,15 @@ +/** + * Parameter Untupling: https://dotty.epfl.ch/docs/reference/other-new-features/parameter-untupling.html + */ +object ParameterUntupling: + + def test(): Unit = + val xs: List[String] = List("d", "o", "t", "t", "y") + + /** + * Current behaviour in Scala 2.12.2 : + * error: missing parameter type + * Note: The expected type requires a one-argument function accepting a 2-Tuple. + * Consider a pattern matching anonymous function, `{ case (s, i) => ... }` + */ + xs.zipWithIndex.map((s, i) => println(s"$i: $s")) diff --git a/SCALA/SRC/MAIN/SCALA/patternmatching.scala b/SCALA/SRC/MAIN/SCALA/patternmatching.scala new file mode 100644 index 0000000..1c316a6 --- /dev/null +++ b/SCALA/SRC/MAIN/SCALA/patternmatching.scala @@ -0,0 +1,83 @@ +/** + * Pattern Matching: https://dotty.epfl.ch/docs/reference/changed-features/pattern-matching.html + */ +object PatternMatching: + + object booleanPattern: + + object Even: + def unapply(s: String): Boolean = s.length % 2 == 0 + + + object productPattern: + + class Person(name: String, age: Int) extends Product: + // if we not define that, it will give compile error. + // we change the order + def _1 = age + def _2 = name + + // Not used by pattern matching: Product is only used as a marker trait. + def canEqual(that: Any): Boolean = ??? + def productArity: Int = ??? + def productElement(n: Int): Any = ??? + + object Person: + def unapply(a: (String, Int)): Person = Person(a._1, a._2) + + + object seqPattern: + + // adapted from https://danielwestheide.com/blog/the-neophytes-guide-to-scala-part-2-extracting-sequences/ + object Names: + def unapplySeq(name: String): Option[Seq[String]] = + val names = name.trim.split(" ") + if names.size < 2 then None + else Some(names.last :: names.head :: names.drop(1).dropRight(1).toList) + + + object namePattern: + + class Name(val name: String): + def get: String = name + def isEmpty = name.isEmpty + + object Name: + def unapply(s: String): Name = Name(s) + + + def test(): Unit = + import booleanPattern.* + + "even" match + case s @ Even() => println(s"$s has an even number of characters") + case s => println(s"$s has an odd number of characters") + + // https://dotty.epfl.ch/docs/reference/changed-features/vararg-splices.html + def containsConsecutive(list: List[Int]): Boolean = list match + case List(a, b, xs*) => a == b || containsConsecutive(b :: xs.toList) + case Nil | List(_, _*) => false + + println(containsConsecutive(List(1, 2, 3, 4, 5))) + println(containsConsecutive(List(1, 2, 3, 3, 5))) + + import productPattern.* + ("john", 42) match + case Person(n, a) => println(s"name: $n, age: $a") + + import seqPattern.* + + def greet(fullName: String) = fullName match + case Names(lastName, firstName, _*) => "Good morning, " + firstName + " " + lastName + "!" + case _ => "Welcome! Please make sure to fill in your name!" + + println(greet("Alan Turing")) + println(greet("john")) + println(greet("Wolfgang Amadeus Mozart")) + + import namePattern.* + "alice" match + case Name(n) => println(s"name is $n") + case _ => println("empty name") + +end PatternMatching \ No newline at end of file diff --git a/SCALA/SRC/MAIN/SCALA/structuraltypes.scala b/SCALA/SRC/MAIN/SCALA/structuraltypes.scala new file mode 100644 index 0000000..60be80b --- /dev/null +++ b/SCALA/SRC/MAIN/SCALA/structuraltypes.scala @@ -0,0 +1,26 @@ +/** + * Structural Types: https://dotty.epfl.ch/docs/reference/changed-features/structural-types.html + */ +object StructuralTypes: + + case class Record(elems: (String, Any)*) extends Selectable: + def selectDynamic(name: String): Any = elems.find(_._1 == name).get._2 + + type Person = Record { + val name: String + val age: Int + } + + val person = Record("name" -> "Emma", "age" -> 42, "salary" -> 320L).asInstanceOf[Person] + + val invalidPerson = Record("name" -> "John", "salary" -> 42).asInstanceOf[Person] + + def test(): Unit = + println(person.name) + println(person.age) + + println(invalidPerson.name) + // age field is java.util.NoSuchElementException: None.get + //println(invalidPerson.age) + +end StructuralTypes \ No newline at end of file diff --git a/SCALA/SRC/MAIN/SCALA/traitparmas.scala b/SCALA/SRC/MAIN/SCALA/traitparmas.scala new file mode 100644 index 0000000..b204a7e --- /dev/null +++ b/SCALA/SRC/MAIN/SCALA/traitparmas.scala @@ -0,0 +1,19 @@ +/** + * Trait Parameters: https://dotty.epfl.ch/docs/reference/other-new-features/trait-parameters.html + */ +object TraitParams: + + trait Base(val msg: String) + class A extends Base("Hello") + class B extends Base("Dotty!") + + // Union types only exist in Scala 3, so there's no chance that this will accidentally be compiled with Scala 2 + private def printMessages(msgs: (A | B)*) = println(msgs.map(_.msg).mkString(" ")) + + def test(): Unit = + printMessages(new A, new B) + + // Sanity check the classpath: this won't run if the Scala 3 jar is not present. + val x: Int => Int = identity + x(1) +end \ No newline at end of file diff --git a/SCALA/SRC/MAIN/SCALA/typelamdas.scala b/SCALA/SRC/MAIN/SCALA/typelamdas.scala new file mode 100644 index 0000000..1703bcc --- /dev/null +++ b/SCALA/SRC/MAIN/SCALA/typelamdas.scala @@ -0,0 +1,15 @@ +/** + * Type Lambdas: https://dotty.epfl.ch/docs/reference/new-types/type-lambdas.html + */ +object TypeLambdas: + + type M = [X, Y] =>> Map[Y, X] + + type Tuple = [X] =>> (X, X) + + def test(): Unit = + val m: M[String, Int] = Map(1 -> "1") + println(m) + + val tuple: Tuple[String] = ("a", "b") + println(tuple) diff --git a/SCALA/SRC/MAIN/SCALA/uniontypes.scala b/SCALA/SRC/MAIN/SCALA/uniontypes.scala new file mode 100644 index 0000000..eda711c --- /dev/null +++ b/SCALA/SRC/MAIN/SCALA/uniontypes.scala @@ -0,0 +1,39 @@ +/** + * Union Types: https://dotty.epfl.ch/docs/reference/new-types/union-types.html + */ +object UnionTypes: + + sealed trait Division + final case class DivisionByZero(msg: String) extends Division + final case class Success(double: Double) extends Division + + // You can create type aliases for your union types (sum types). + type DivisionResult = DivisionByZero | Success + + sealed trait List[+A] + case object Empty extends List[Nothing] + final case class Cons[+A](h: A, t: List[A]) extends List[A] + + private def safeDivide(a: Double, b: Double): DivisionResult = + if b == 0 then DivisionByZero("DivisionByZeroException") else Success(a / b) + + private def either(division: Division) = division match + case DivisionByZero(m) => Left(m) + case Success(d) => Right(d) + + def test(): Unit = + val divisionResultSuccess: DivisionResult = safeDivide(4, 2) + + // commutative + val divisionResultFailure: Success | DivisionByZero = safeDivide(4, 0) + + // calling `either` function with union typed value. + println(either(divisionResultSuccess)) + + // calling `either` function with union typed value. + println(either(divisionResultFailure)) + + val list: Cons[Int] | Empty.type = Cons(1, Cons(2, Cons(3, Empty))) + val emptyList: Empty.type | Cons[Any] = Empty + println(list) + println(emptyList)