-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
642ee4f
commit 9a43b3d
Showing
17 changed files
with
461 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
sbt.version=1.9.9 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
version: 2 | ||
updates: | ||
- package-ecosystem: "github-actions" | ||
directory: "/" | ||
schedule: | ||
interval: "weekly" | ||
day: "tuesday" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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")) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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))) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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")) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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")) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
Oops, something went wrong.