Compare commits

...

26 Commits

Author SHA1 Message Date
b7ca6610fc added final exam 2025-05-20 14:00:13 +02:00
ec0e1e8ae4 added final exam preparation 2025-05-19 22:06:05 +02:00
5365eabadd updated README 2025-05-06 14:37:16 +02:00
43e0694d9d added assignment 9 ex 1 2025-05-06 14:32:03 +02:00
c13f9851e3 added lesson 9 2025-05-06 14:31:51 +02:00
bed771a04e added assignment 8 ex 2 2025-05-05 18:43:26 +02:00
6954695a0d added assignment 8 ex 1 2025-05-05 17:35:43 +02:00
a16b70970f added lesson 8 2025-05-05 17:08:21 +02:00
34b1ff39ce minor improvements 2025-04-29 13:01:28 +02:00
e58c399bad added assignment 7 ex 5 2025-04-16 10:26:44 +02:00
95fdbf7abf added assignment 7 ex 4 2025-04-16 07:53:28 +02:00
17c1e4170d added assignment 7 ex 3 2025-04-16 07:41:25 +02:00
d4878015e3 added assignment 7 ex 2 2025-04-15 15:59:25 +02:00
f693d69366 added assignment 7 ex 1 2025-04-15 15:59:16 +02:00
d8b22157c5 added lesson 7 2025-04-15 15:07:26 +02:00
9ad00e6182 corrected / added midterm examples 2025-04-15 13:12:25 +02:00
b53e0677cc fixed minor issue in midterm 2025-04-15 13:08:04 +02:00
056305fd72 added assignment 6 ex 4 2025-04-08 15:52:54 +02:00
f4e417571a added assignment 6 ex 3 2025-04-08 15:35:05 +02:00
4eba7f3587 added assignment 6 ex 2 2025-04-08 15:29:08 +02:00
76a4f50075 added assignment 6 ex 1 2025-04-08 15:03:00 +02:00
41c0b80d8b added lesson 6 2025-04-08 14:53:36 +02:00
3f648b7fc9 fixed fixedPoint func in midterm 2025-04-04 10:35:11 +02:00
84315955f8 updated README 2025-04-01 14:15:47 +02:00
bbfcb31026 added balanceMatch moustache 2025-04-01 14:15:12 +02:00
03c383fb35 added midterm 2025-04-01 14:14:52 +02:00
39 changed files with 1157 additions and 5 deletions

View File

@ -15,11 +15,24 @@
* [Lesson 3 - Data structures](#lesson-3---data-structures)
* [Lesson 4 - Lists and pattern matching](#lesson-4---lists-and-pattern-matching)
* [Lesson 5 - Advanced lists and High order functions](#lesson-5---advanced-lists-and-high-order-functions)
* [Midterm preparation](#midterm-preparation)
* [Midterm](#midterm)
* [Lesson 6 - Tuples and comprehensions](#lesson-6---tuples-and-comprehensions)
* [Lesson 7 - Advanced typing and infinite lists](#lesson-7---advanced-typing-and-infinite-lists)
* [Lesson 8 - Futures and parallel collections](#lesson-8---futures-and-parallel-collections)
* [Lesson 9 - DSLs](#lesson-9---dsls)
* [Final preparation](#final-exam-preparation)
* [Final](#final-exam)
* [Assignments](#assignments)
* [Assignment 1 - Square root](#assignment-1---square-root)
* [Assignment 2 - Map-reduce](#assignment-2---map-reduce)
* [Assignment 3 - Binary tree](#assignment-3---binary-tree)
* [Assignment 4 - Lists and pattern matching](#assignment-4---lists-and-pattern-matching)
* [Assignment 5 - High-order functions on lists](#assignment-5---high-order-functions-on-lists)
* [Assignment 6 - Sequence comprehension and tuples](#assignment-6---sequence-comprehension-and-tuples)
* [Assignment 7 - Advanced typing and infinite lists](#assignment-7---advanced-typing-and-infinite-lists)
* [Assignment 8 - Advanced typing and infinite lists](#assignment-8---advanced-typing-and-infinite-lists)
* [Assignment 9 - DSLs](#assignment-9---dsls)
<!-- TOC -->
@ -58,6 +71,41 @@
### Midterm preparation
[Files](src/MidTermPrep1)
### Midterm
[Files](src/MidTerm1)
### Lesson 6 - Tuples and comprehensions
[Files](src/Lesson6)
- Tuples
- For-comprehension
- Yield
- Flatmap
### Lesson 7 - Advanced typing and infinite lists
[Files](src/Lesson7)
- Types
- Bounds
- Traits
- Variance, covariance and contra-variance
- Infinite sequences
### Lesson 8 - Futures and parallel collections
[Files](src/Lesson8)
- Futures
- Actors
- Parallel collections
### Lesson 9 - DSLs
[Files](src/Lesson9)
- DSL
### Final exam preparation
[Files](src/FinalPrep1)
### Final exam
[Files](src/Final1)
## Assignments
### Assignment 1 - Square root
@ -91,4 +139,23 @@
- Lists
- Map
- Fold
- Zip
- Zip
### Assignment 6 - Sequence comprehension and tuples
[Files](src/Assignment6)
- Tuples
- `for` comprehension
### Assignment 7 - Advanced typing and infinite lists
[Files](src/Assignment7)
- Genericity
- Infinite lazy lists
### Assignment 8 - Advanced typing and infinite lists
[Files](src/Assignment8)
- Parallel collections
- Futures
### Assignment 9 - DSLs
[Files](src/Assignment9)
- DSL

17
src/Assignment6/Ex1.sc Normal file
View File

@ -0,0 +1,17 @@
def flattenList(list: List[Any]): List[Any] = {
list.foldRight(List.empty[Any])(
(e, acc) => {
e match {
case l: List[Any] => flattenList(l) concat acc
case _ => e::acc
}
}
)
}
assert(
flattenList(
List(List(1,1), 2, List(3, List(5, 8)))
) == List(1,1,2,3,5,8)
)

38
src/Assignment6/Ex2.sc Normal file
View File

@ -0,0 +1,38 @@
def isPrime(i: Int): Boolean =
i match {
case i if i <= 1 => false
case 2 => true
case _ => !(2 to (i - 1)).exists(x => i % x == 0)
}
def primeSum(max: Int): List[(Int, Int)] =
for {
i <- (1 to max).toList
j <- (1 to max).toList
if (isPrime(i + j))
} yield (i, j)
def uniquePermutations(permutations: List[(Int, Int)]): List[(Int, Int)] = {
permutations match {
case Nil => Nil
case (a, b)::rest if rest contains(b, a) => uniquePermutations(rest)
case head::rest => head::uniquePermutations(rest)
}
}
def uniquePermutations2(permutations: List[(Int, Int)]): List[(Int, Int)] = {
permutations.foldRight(List.empty[(Int, Int)])(
(e, acc) => {
e match {
case (a, b) if acc contains (b, a) => acc
case _ => e::acc
}
}
)
}
val perms = primeSum(10)
uniquePermutations(perms)
uniquePermutations2(perms)

22
src/Assignment6/Ex3.sc Normal file
View File

@ -0,0 +1,22 @@
val cities = List("Paris", "London", "Berlin", "Lausanne")
val relatives = List("Grandma", "Grandpa", "Aunt Lottie", "Dad")
val travellers = List("Pierre-Andre", "Rachel")
def generatePostcards(cities: List[String], relatives: List[String], travellers: List[String]): List[String] = {
for (t <- travellers;
r <- relatives;
c <- cities) yield s"Dear $r, Wish you were here in $c! Love, $t"
}
def generatePostcards2(cities: List[String], relatives: List[String], travellers: List[String]): List[String] = {
for (t <- travellers;
r <- relatives;
c <- cities;
if r.startsWith("G")) yield s"Dear $r, Wish you were here in $c! Love, $t"
}
val cards: List[String] = generatePostcards(cities, relatives, travellers)
println(cards.mkString("\n"))
val cards2: List[String] = generatePostcards2(cities, relatives, travellers)
println(cards2.mkString("\n"))

39
src/Assignment6/Ex4.sc Normal file
View File

@ -0,0 +1,39 @@
def inCheck(q1: (Int, Int), q2: (Int, Int)) =
q1._1 == q2._1 || // same row
q1._2 == q2._2 || // same column
(q1._1 - q2._1).abs == (q1._2 - q2._2).abs // on diagonal
def isSafe(queen: (Int, Int), queens: List[(Int, Int)]) =
queens forall (q => !inCheck(queen, q))
def queens(n: Int): List[List[(Int, Int)]] = {
def placeQueens(k: Int): List[List[(Int, Int)]] =
if (k == 0)
List(List())
else
for {
queens <- placeQueens(k - 1)
column <- 1 to n
queen = (k, column)
if isSafe(queen, queens)
} yield queen :: queens
placeQueens(n)
}
def printChessBoard(solutions: List[List[(Int, Int)]]): String = {
val sols: List[String] = for ((sol, i) <- solutions.zipWithIndex) yield {
val lines: IndexedSeq[String] = for (y <- 1 to sol.length) yield {
val line: IndexedSeq[String] = {
for (x <- 1 to sol.length) yield {
if (sol contains (y, x)) "" else "_"
}
}
line.mkString("|", "|", "|")
}
s"Solution $i:\n" + lines.mkString("\n")
}
sols.mkString("\n\n")
}
println(printChessBoard(queens(4)))

35
src/Assignment7/Ex1.sc Normal file
View File

@ -0,0 +1,35 @@
trait Stack[+A] {
def push[B >: A](elem: B) : Stack[B] = ElemStack(elem, this)
def top: A
def pop: Stack[A]
}
case class EmptyStack[+A]() extends Stack[A] {
override def top: A = throw new IndexOutOfBoundsException("Stack is empty")
override def pop: Stack[A] = this
}
case class ElemStack[+A](elmt: A, base: Stack[A]) extends Stack[A] {
override def top: A = elmt
override def pop: Stack[A] = base
override def toString: String = elmt.toString + "," + base.toString
}
// Construction, pop and toString
val a = EmptyStack().push("hello").push("world").push("it's fun").pop
assert(a.toString() == "world,hello,EmptyStack()")
// Getting top
val b = EmptyStack().push(1).push(3)
assert(b.top == 3)
// Variance checks
class Foo
class Bar extends Foo
val c: Stack[Bar] = EmptyStack().push(new Bar()).push(new Bar())
assert(c.top.isInstanceOf[Bar] == true)
assert(c.top.isInstanceOf[Foo] == true)
// Variance check 2
val d: Stack[Foo] = EmptyStack().push(new Bar()).push(new Bar())
assert(d.top.isInstanceOf[Foo])

9
src/Assignment7/Ex2.sc Normal file
View File

@ -0,0 +1,9 @@
def intsFrom(n: Int): LazyList[Int] = {
n #:: intsFrom(n + 1)
}
def primeNumbers(list: LazyList[Int]): LazyList[Int] = {
list.head #:: primeNumbers(list.tail.filter(n => n % list.head != 0))
}
val ints: LazyList[Int] = intsFrom(2)
primeNumbers(ints).take(10).toList

12
src/Assignment7/Ex3.sc Normal file
View File

@ -0,0 +1,12 @@
def addStream(s1: LazyList[Int], s2: LazyList[Int]): LazyList[Int] = {
s1 zip s2 map (p => p._1 + p._2)
}
def fibonacci(): LazyList[Int] = {
0 #:: 1 #:: addStream(
fibonacci(),
fibonacci().tail
)
}
fibonacci().take(10).toList

19
src/Assignment7/Ex4.sc Normal file
View File

@ -0,0 +1,19 @@
def THRESHOLD: Double = 0.0001
def sqr(x: Double): Double = x * x
def sqrt_stream(value: Double): LazyList[Double] = {
def helper(target: Double, approx: Double): LazyList[Double] = {
approx #:: helper(target, approx - (sqr(approx) - target) / (2 * approx))
}
helper(value, value)
}
sqrt_stream(2).take(10).toList
def threshold(list: LazyList[Double], thresh: Double) = {
list.zip(list.drop(1)).filter(p => math.abs(p._2 - p._1) < thresh).head._2
}
threshold(sqrt_stream(2), 1e-15)

26
src/Assignment7/Ex5.sc Normal file
View File

@ -0,0 +1,26 @@
/*
1
1 1
2 1
1 2 1 1
1 1 1 2 2 1
3 1 2 2 1 1
Next :
1 3 1 1 2 2 2 1
*/
def nextLine(current: List[Int]) : List[Int] = {
current.foldRight(List.empty[(Int, Int)])((x, acc) => {
(x, acc) match {
case (a, p :: rest) if a == p._2 => (p._1 + 1, p._2) :: rest
case _ => (1, x) :: acc
}
}).flatten(p => List(p._1, p._2))
}
def makeSequence(start: List[Int]): LazyList[List[Int]] = {
start #:: makeSequence(nextLine(start))
}
lazy val sequence: LazyList[List[Int]] = makeSequence(List(1))
sequence.take(7).toList

24
src/Assignment8/Ex1.scala Normal file
View File

@ -0,0 +1,24 @@
package Assignment8
import utils.timeVerbose
import scala.collection.parallel.CollectionConverters._
object Ex1 extends App {
def integrate(a: Double, b: Double, nIntervals: Int, f: (Double => Double)): Double = {
val dx: Double = (b - a) / nIntervals
//val y: Double = (1 until nIntervals).map(i => f(i * dx + a)).sum
//val y: Double = (1 until nIntervals).view.map(i => f(i * dx + a)).sum
val y: Double = (1 until nIntervals).par.map(i => f(i * dx + a)).sum
return (2 * y + f(a) + f(b)) * dx / 2
}
println(integrate(1, 2, 500, math.sin))
println(integrate(0, 1, 500, math.sin _ compose math.cos))
timeVerbose {
val i = integrate(0, 1, math.pow(20, 6).toInt, math.sin)
}
}

62
src/Assignment8/Ex2.scala Normal file
View File

@ -0,0 +1,62 @@
package Assignment8
import net.liftweb.json
import net.liftweb.json.DefaultFormats
import java.net.URI
import scala.concurrent.duration.Duration
import scala.concurrent.{Await, Future}
import scala.sys.process._
import scala.util.{Failure, Success}
object Ex2 extends App {
implicit val ec: scala.concurrent.ExecutionContext = scala.concurrent.ExecutionContext.global
implicit val formats: DefaultFormats.type = DefaultFormats
case class Coin(id: String, icon: String, name: String, symbol: String, rank: Int, price: Double, priceBtc: Double, volume: Double, marketCap: Double, availableSupply: Double, totalSupply: Double, fullyDilutedValuation: Double, priceChange1h: Double, priceChange1d: Double, priceChange1w: Double, redditUrl: String, websiteUrl: String, twitterUrl: String, explorers: List[String])
case class Currency(name: String, rate: Double, symbol: String, imageUrl: String)
val BITCOIN_TO_USD: String = "https://openapiv1.coinstats.app/coins/bitcoin"
val USD_TO_CHF: String = "https://openapiv1.coinstats.app/fiats"
private val API_KEY: String = sys.env.getOrElse("OPENAPI_KEY", "")
def getUrl(url: String): Future[String] = {
Future {
val uri: URI = new URI(url)
val cmd: String = "curl -s -H 'X-API-KEY: " + API_KEY + "' " + uri.toString
cmd.!!
}
}
def extractBitcoinToUSDRate(jsonStr: String): Double = {
val data: Coin = json.parse(jsonStr).extract[Coin]
return data.price
}
def extractUSDToCHFRate(jsonStr: String): Double = {
val data: List[Currency] = json.parse(jsonStr).extract[List[Currency]]
return data.find(currency => currency.name == "CHF")
.map(currency => currency.rate)
.get
}
def getBitcoinToUSD: Future[Double] = {
getUrl(BITCOIN_TO_USD) map extractBitcoinToUSDRate
}
def getUSDToCHF: Future[Double] = {
getUrl(USD_TO_CHF) map extractUSDToCHFRate
}
val f: Future[Double] = for {
btc2usd <- getBitcoinToUSD
usd2chf <- getUSDToCHF
} yield btc2usd * usd2chf
f onComplete {
case Success(value) => println(s"1 BTC == $value CHF")
case Failure(e) => println(s"An error occurred: $e")
}
Await.ready(f, Duration.Inf)
}

View File

@ -0,0 +1,29 @@
import Assignment9.Kelvin.kel2cel
import scala.language.implicitConversions
package object Assignment9 {
sealed trait Temperature {
}
object Temperature {
implicit def cel2kel(celsius: Celsius): Kelvin = new Kelvin(celsius.value + 273.15)
implicit def kel2cel(kelvin: Kelvin): Celsius = new Celsius(kelvin.value - 273.15)
}
case class Celsius(value: Double) extends Temperature {
override def toString: String = s"$value°C"
}
object Celsius {
implicit def val2cel(value: Double): Celsius = new Celsius(value)
}
case class Kelvin(value: Double) extends Temperature {
override def toString: String = s"$value K"
}
object Kelvin {
implicit def kel2cel(value: Double): Kelvin = new Kelvin(value)
}
}

16
src/Assignment9/Ex1.scala Normal file
View File

@ -0,0 +1,16 @@
package Assignment9
import scala.language.implicitConversions
object Ex1 extends App {
val a: Celsius = 30
val b: Kelvin = 30
val c: Kelvin = Celsius(10)
val d: Celsius = c
val e: Temperature = d
println(a) // Should print "30°C"
println(b) // Should print "30 K"
println()
}

View File

@ -0,0 +1,36 @@
package exercises
object Exercise1 extends App {
def dup[A](r: List[Int], l: List[A]): List[A] = {
r.zip(l).flatMap(p => {
List.fill(p._1)(p._2)
})
}
def removeDup[A](l: List[A]): List[A] = {
l match {
case head::tail => {
head::removeDup(tail.filterNot(e => e == head))
}
case _ => l
}
}
def zip[A, B](first: List[A], second: List[B]): List[(A, B)] = {
first match {
case head1::tail1 => {
second match {
case head2::tail2 => {
(head1, head2)::zip(tail1, tail2)
}
case _ => Nil
}
}
case _ => Nil
}
}
def zipWith[A, B, C](xs: List[A], ys: List[B])(f: (A, B) => C): List[C] = {
zip(xs, ys).map((p: (A, B)) => f(p._1, p._2))
}
}

View File

@ -0,0 +1,10 @@
package exercises
object Exercise2 extends App {
def gen(charSet: String, length: Int): List[String] = {
if (length <= 0) List("")
else charSet.toList.flatMap(c => {
gen(charSet, length - 1).map(pwd => c.toString + pwd)
})
}
}

View File

@ -0,0 +1,55 @@
package exercises
object Exercise3 extends App {
sealed abstract class Tree {
def isMirrorOf(other: Tree): Boolean
def isSymmetric(): Boolean
def computeDepth(): Int = {
this match {
case Empty => 1
case Node(left, _, right) => 1 + Math.max(left.computeDepth(), right.computeDepth())
}
}
def traverseBreadthFirst(): List[Int] = {
val depth: Int = computeDepth()
// Construct list of levels
def helper(tree: Tree, curDepth: Int = 0): List[List[Int]] = {
tree match {
// Add empty levels for consistent indices
case Empty => List.fill(depth - curDepth)(List.empty[Int])
case Node(left, elem, right) => {
val leftList: List[List[Int]] = helper(left, curDepth + 1)
val rightList: List[List[Int]] = helper(right, curDepth + 1)
val res: List[List[Int]] = (0 until depth - curDepth - 1).map(i => {
leftList(i) ::: rightList(i)
}).toList
// Add this level
List(elem)::res
}
}
}
helper(this).flatten
}
}
case class Node(left: Tree, elem: Int, right: Tree) extends Tree {
def isMirrorOf(other: Tree): Boolean = {
other match {
case Node(left2, _, right2) => (left isMirrorOf right2) && (right isMirrorOf left2)
case _ => false
}
}
def isSymmetric: Boolean = left isMirrorOf right
}
case object Empty extends Tree {
def isMirrorOf(other: Tree): Boolean = {
other match {
case Empty => true
case _ => false
}
}
def isSymmetric: Boolean = true
}
}

26
src/FinalPrep1/Ex1.sc Normal file
View File

@ -0,0 +1,26 @@
def insertion[T](x: T, xs: List[T]): List[List[T]] = {
return (0 to xs.length).map((i: Int) => {
val p = xs.splitAt(i)
p._1 ::: (x :: p._2)
}).toList
def buildInsertions(x: T, xs: List[T], before: List[T]): List[List[T]] = {
xs match {
case Nil => (before :+ x) :: Nil
case head::tail => (before ::: (x :: xs)) :: buildInsertions(x, tail, before :+ head)
}
}
buildInsertions(x, xs, Nil)
}
insertion(1, List(2,3,4))
def permutation[T](xs: List[T]): List[List[T]] = {
xs match {
case head::tail => permutation(tail) flatMap (perm => insertion(head, perm))
case _ => List(xs)
}
}
permutation(List(1,2,3))

18
src/FinalPrep1/Ex2.sc Normal file
View File

@ -0,0 +1,18 @@
import scala.math.{ceil, min, sqrt}
def fourSquares(n: Int): List[Tuple4[Int, Int, Int, Int]] = {
val tups = for (
d: Int <- ceil(sqrt(n)).toInt to 0 by -1;
c: Int <- min(d, ceil(sqrt(n - d*d))).toInt to 0 by -1;
b: Int <- min(c, ceil(sqrt(n - d*d - c*c))).toInt to 0 by -1;
a: Int <- min(b, ceil(sqrt(n - d*d - c*c - b*b))).toInt to 0 by -1
if (a*a + b*b + c*c + d*d == n)
) yield Tuple4(a, b, c, d)
tups.toList
}
fourSquares(0) // List(Tuple4(0, 0, 0, 0))
fourSquares(3) // List(Tuple4(0, 1, 1, 1))
fourSquares(15) // List(Tuple(1, 1, 2, 3))
fourSquares(88) // List(Tuple4(0, 4, 6, 6), Tuple4(2, 2, 4, 8))

165
src/FinalPrep1/Ex3.sc Normal file
View File

@ -0,0 +1,165 @@
sealed abstract class Tree {
// Additional
def toTree(indent: String = ""): String = indent
// End
def eval(): Double = {
this match {
case Sum(l, r) => l.eval() + r.eval()
case Var(n) => throw new RuntimeException("Cannot evaluate " + this)
case Const(v) => v
case Power(x, y) => Math.pow(x.eval(), y.eval())
case Product(x, y) => x.eval() * y.eval()
}
}
def simplify(): Tree = {
this match {
case Sum(Const(v1), Const(v2)) => Const(v1 + v2)
case Sum(l, r) if l == r => Product(Const(2), l)
case Product(_, Const(0)) | Product(Const(0), _) => Const(0)
case Product(v, Const(1)) => v
case Product(Const(1), v) => v
case Product(Const(v1), Const(v2)) => Const(v1 * v2)
// Additional
case Sum(l, Const(0)) => l
case Sum(Const(0), r) => r
case Product(l, c: Const) => Product(c, l)
case Product(Const(v1), Product(Const(v2), r)) => Product(Const(v1 * v2), r)
case Product(Product(Const(v1), l), Const(v2)) => Product(Const(v1 * v2), l)
case Product(Product(Const(v1), l), Product(Const(v2), r)) => Product(Const(v1 * v2), Product(l, r))
// End
case Power(_, Const(0)) => Const(1)
case Power(v, Const(1)) => v
case _ => this
}
}
def fullSimplify(): Tree = {
(this match {
case Sum(l, r) => Sum(l.fullSimplify(), r.fullSimplify())
case Power(x, y) => Power(x.fullSimplify(), y.fullSimplify())
case Product(x, y) => Product(x.fullSimplify(), y.fullSimplify())
case _ => this
}).simplify()
}
def derive(s: String): Tree = {
val simplified = this.fullSimplify()
(simplified match {
case Const(_) => Const(0)
case Product(c: Const, other) => Product(c, other.derive(s))
case Product(other, c: Const) => Product(other.derive(s), c)
case Sum(l, r) => Sum(l.derive(s), r.derive(s))
// Additional
case Product(l, r) => Sum(
Product(l.derive(s), r),
Product(l, r.derive(s))
)
case Power(b, Const(e)) => Product(Const(e), Power(b, Const(e - 1)))
case Power(b, e) => Product(Product(e, Power(b, Sum(e, Const(-1)))), e.derive(s))
case Var(n) if n == s => Const(1)
// End
case _ => simplified
}).fullSimplify()
}
}
case class Sum(l: Tree, r: Tree) extends Tree {
override def toString(): String =
l.toString() + "+" + r.toString()
// Additional
override def toTree(indent: String = ""): String = {
(indent + "Sum(\n"
+ l.toTree(indent + " ") + ",\n"
+ r.toTree(indent + " ") + "\n"
+ indent + ")")
}
// End
}
case class Var(n: String) extends Tree {
override def toString() = n
// Additional
override def toTree(indent: String = ""): String = {
indent + "Var(" + n + ")"
}
// End
}
case class Const(v: Double) extends Tree {
override def toString() = v.toString
// Additional
override def toTree(indent: String = ""): String = {
indent + "Const(" + v + ")"
}
// End
}
case class Power(x: Tree, y: Tree) extends Tree {
override def toString() = x + "^" + y
// Additional
override def toTree(indent: String = ""): String = {
(indent + "Power(\n"
+ x.toTree(indent + " ") + ",\n"
+ y.toTree(indent + " ") + "\n"
+ indent + ")")
}
// End
}
case class Product(x: Tree, y: Tree) extends Tree {
override def toString() = x + "*" + y
// Additional
override def toTree(indent: String = ""): String = {
(indent + "Sum(\n"
+ x.toTree(indent + " ") + ",\n"
+ y.toTree(indent + " ") + "\n"
+ indent + ")")
}
// End
}
val p = Product(
Sum(
Const(3),
Const(-3)
),
Const(10)
)
p.eval()
p.fullSimplify()
// 23x^3 + 6x^2 -268x + pi
val p = Sum(
Sum(
Sum(
Product(
Power(
Var("x"),
Const(3)
),
Const(23),
),
Product(
Const(6),
Power(
Var("x"),
Const(2)
)
)
),
Product(
Const(-268),
Var("x")
)
),
Const(Math.PI)
)
p.toTree()
p.derive("x").toTree()
p.derive("x")
// (23x^3 + 6x^2 -268x + pi)' = 69x^2 + 12x - 268

View File

@ -0,0 +1,18 @@
(2 to 10).foreach(i =>
(2 to 10)
.filter(j => i % j == 0)
.foreach(j =>
println(s"$i is an integer multiple of $j")
)
)
val positions = for (
col <- 'a' to 'h';
row <- 1 to 8
) yield (col, row)
val whites = for (
col <- 'a' to 'h';
row <- 1 to 8;
if ((col - 'a' + row) % 2 == 0)
) yield (col, row)

40
src/Lesson6/Ex_6.1.sc Normal file
View File

@ -0,0 +1,40 @@
def filter[T](func: T => Boolean, list: List[T]): List[T] = {
list match {
case Nil => Nil
case e::rest if func(e) => e::filter(func, rest)
case _::rest => filter(func, rest)
}
}
def partition[T](func: T => Boolean, list: List[T]): (List[T], List[T]) = {
list match {
case Nil => (List.empty[T], List.empty[T])
case e::rest => {
val part = partition(func, rest)
if (func(e)) {
(e::part._1, part._2)
} else {
(part._1, e::part._2)
}
}
}
}
def partition[T](func: T => Boolean, list: List[T]): (List[T], List[T]) = {
list.foldRight((List.empty[T], List.empty[T]))(
(e: T, prev: (List[T], List[T])) => {
if (func(e)) {
(e::prev._1, prev._2)
} else {
(prev._1, e::prev._2)
}
}
)
}
val b = (1 to 10).toList
filter((x: Int) => x % 2 == 0, b)
partition((x: Int) => x % 2 == 0, b)

29
src/Lesson6/Primes.sc Normal file
View File

@ -0,0 +1,29 @@
def time(f: => Unit => Any): Long = {
val start = System.currentTimeMillis()
f()
val end = System.currentTimeMillis()
end - start
}
def timeVerbose(s: String)(f: => Unit => Any): Unit = {
println(s"[$s] Measuring time...")
val duration = time(f)
println(s"[$s] It took ${duration}ms")
}
def isPrime(i: Int): Boolean =
i match {
case i if i <= 1 => false
case 2 => true
case _ => !(2 until i).exists(x => i%x == 0)
}
def primeSum(max: Int)(isPrimeFunc: Int => Boolean): List[(Int, Int)] = {
for (i <- (1 to max).toList;
j <- (1 to max).toList;
if isPrimeFunc(i + j)) yield (i, j)
}
timeVerbose("Normal Prime"){
primeSum(1000)(isPrime)
}

View File

@ -0,0 +1,25 @@
val q: List[Int] = List(1, 2, 3)
val p: List[Int] = List(4, 5, 6)
// 1.
for (x <- q) yield x * 2
q.map(x => x * 2)
// 2.
for (x <- q if x != 2) yield x * 2
q.filter(x => x !=2).map(x => x * 2)
// 3.
for (x <- q;
y <- p) yield (x, y)
q.flatMap(x => p.map(y => (x, y)))
// 4.
for (x <- q if (x < 2);
y <- p) yield (x, y)
q.filter(x => x < 2).flatMap(x => p.map(y => (x, y)))
for (x <- 1 to 2;
y <- 'a' to 'b') yield (x, y)
(1 to 2).flatMap(x => ('a' to 'b').map(y => (x, y)))

13
src/Lesson6/Tuples.sc Normal file
View File

@ -0,0 +1,13 @@
def merge(x: List[Int], y: List[Int]): List[Int] = {
(x, y) match {
case (list, Nil) => list
case (Nil, list) => list
case (e1::rest1, e2::rest2) =>
if (e1 < e2) e1::merge(rest1, y)
else e2::merge(x, rest2)
}
}
val n1 = List(0, 2, 4, 6)
val n2 = List(1, 3, 5, 7)
merge(n1, n2)

12
src/Lesson7/Daltons.sc Normal file
View File

@ -0,0 +1,12 @@
case class Dalton(n: Int) extends Ordered[Dalton] {
//override def compare(that: Dalton): Int = this.n compare that.n
override def compare(that: Dalton): Int = this.n - that.n
}
val a = Dalton(2); val b = Dalton(3); val c = Dalton(2)
a < b
a > b
a == b
a == c
a >= c

View File

@ -0,0 +1,6 @@
val expr = {
val x = {print("x"); 1}
lazy val y = {print("y"); 2}
def z = {print("z"); 3}
z + y + x + z + y + x
}

11
src/Lesson7/LazyList.sc Normal file
View File

@ -0,0 +1,11 @@
def range(low: Int, high: Int): LazyList[Int] = {
println(s"Calling range with low=$low / high=$high")
if (low >= high) LazyList.empty[Int]
else low #:: range(low + 1, high)
}
range(1, 10)(0)
range(1, 10) map (x => x + 1)
(range(1, 10) map (x => x + 1)).toList

View File

@ -0,0 +1,16 @@
trait Logged {
def log(msg: String)
}
trait ConsoleLogger extends Logged {
override def log(msg: String) = println("[LOG] " + msg)
}
abstract class Person(name: String)
class Customer(n: String) extends Person(n) with Logged {
log(s"Person $n created")
}
val a = new Customer("Patrick Jane") with ConsoleLogger

25
src/Lesson7/Variance.sc Normal file
View File

@ -0,0 +1,25 @@
class Animal(val name: String, val kind: String)
class Cat(name: String) extends Animal(name, "Cat")
class Dog(name: String) extends Animal(name, "Dog")
val anim1: Animal = new Animal("Booboo", "Baboon")
val cat1 = new Cat("Miaou")
// Standard polymorphism
val anim2: Animal = cat1
val dog1: Dog = new Dog("Choucroute")
val anim3: Animal = dog1
class Container[+A](val elems: List[A]) {
def get(i: Int): A = elems(i)
def put[B >: A](elem: B) = new Container(elem::elems)
}
val animalCollection = new Container[Animal](Nil).put(anim1)
val catCollection = new Container[Cat](Nil).put(cat1).put(new Cat("Garfield"))
animalCollection.put(cat1)
val animalCollection2: Container[Animal] = catCollection

19
src/Lesson8/Actors.scala Normal file
View File

@ -0,0 +1,19 @@
package Lesson8
import akka.actor.{Actor, ActorSystem, Props}
object Actors extends App {
case class Greetings(who: String)
class SimplestActor extends Actor {
def receive = {
case Greetings(who) => println(s"Hello $who, pleased to meet you")
}
}
val system = ActorSystem("MySystem")
val simple_greeter = system.actorOf(Props[SimplestActor])
simple_greeter ! Greetings("Dr Who")
}

18
src/Lesson8/Futures.scala Normal file
View File

@ -0,0 +1,18 @@
package Lesson8
import scala.concurrent.Future
import scala.util.{Failure, Success}
object Futures extends App {
implicit val ec: scala.concurrent.ExecutionContext = scala.concurrent.ExecutionContext.global
val f: Future[Int] = Future {
Thread.sleep(650)
3 + 4
}
f onComplete {
case Success(x: Int) => println(s"Computing done, result is $x")
case Failure(ex) => println("Error")
}
}

View File

@ -0,0 +1,15 @@
package Lesson9
import scala.language.{implicitConversions, postfixOps}
object PimpMyLibrary extends App{
/*class PimpedString(s: String) {
def increment: String = new String(s.toCharArray.map(_ + 1))
}
implicit def str2Pimped(s: String): PimpedString = new PimpedString(s)
println("Hal" increment)*/
}

7
src/MidTerm1/Ex1.sc Normal file
View File

@ -0,0 +1,7 @@
val pi: List[Long] = List(3, 1, 4, 1, 5, 9, 2)
val slice: List[Int] = List(4, 1, 5)
pi.indexOfSlice(slice)
//List("Hello", "world", "Scala").foldRight(0)((a, b) => a + b.length)
List("Hello", "world", "Scala").foldLeft(0)((a, b) => a + b.length)

55
src/MidTerm1/Ex2.sc Normal file
View File

@ -0,0 +1,55 @@
import scala.annotation.tailrec
@tailrec
def foldLeft[A, B](list: List[A])(init: B)(f: (B, A) => B): B = {
list match {
case Nil => init
case head::tail => foldLeft(tail)(f(init, head))(f)
}
}
@tailrec
def dropWhile[T](list: List[T])(predicate: T => Boolean): List[T] = {
list match {
case head::tail if predicate(head) => dropWhile(tail)(predicate)
case _ => list
}
}
def predicates[T](list: List[T])(preds: List[T => Boolean]): List[T] = {
list.foldRight(List.empty[T])((e: T, l: List[T]) => {
//if (preds.foldLeft(true)((a, b) => a && b(e))) e::l
if (preds.forall(b => b(e))) e::l
else l
})
}
val l1 = (1 to 10).toList
val f1 = ((a: Int) => a % 2 == 0)
val f2 = ((a: Int) => a > 5)
predicates(l1)(List(f1, f2)) // List(6, 8, 10)
val l2 = ("Hello Scala Echo").toList
val f4 = ((a: Char) => a == 'a' || a == 'e' || a == 'o')
val f3 = ((a: Char) => !a.isUpper)
predicates(l2)(List(f3, f4)) // List('e', 'o', 'a', 'a', 'o')
/*
// Better solution
def predicates[T](list: List[T])(preds: List[T => Boolean]): List[T] = {
preds.foldLeft(list)((acc, fun) => acc.filter(fun))
}
*/
def fixedPoint(f: Int => Int): Int => Int = {
@tailrec
def func(x: Int): Int = {
val y: Int = f(x)
if (x == y) y
else func(y)
}
func
}
fixedPoint(x => if (x % 10 == 0) x else x + 1)(35) // 40
fixedPoint(x => x / 2 + 5)(20) // 10

37
src/MidTerm1/Ex3.sc Normal file
View File

@ -0,0 +1,37 @@
import scala.annotation.tailrec
abstract class Text {
def isEmpty: Boolean = {
this match {
case Chars(cs) => cs.isEmpty
case Concat(t1, t2) => t1.isEmpty && t2.isEmpty
}
}
def head: Char = {
this match {
case Chars(cs) => cs.head
case Concat(t1, t2) => if (t1.isEmpty) t2.head else t1.head
}
}
def tail: Text = {
this match {
case Chars(cs) => Chars(cs.tail)
case Concat(t1, t2) => if (t1.isEmpty) t2.tail else Concat(t1.tail, t2)
}
}
def map(f: Char => Char): Text = {
this match {
case Chars(cs) => Chars(cs.map(f))
case Concat(t1, t2) => Concat(t1.map(f), t2.map(f))
}
}
}
case class Chars(cs: List[Char]) extends Text
case class Concat(t1: Text, t2: Text) extends Text
@tailrec
def equals(t1: Text, t2: Text): Boolean = {
if (t1.isEmpty) t2.isEmpty
else if (t2.isEmpty) false
else (t1.head == t2.head) && equals(t1.tail, t2.tail)
}

View File

@ -14,7 +14,23 @@ def balanceMatch(chars: List[Char]): Boolean = {
checkStep(chars, 0)
}
balanceMatch("(if (x == 0) then max (1, x))".toList)
balanceMatch("I told him (that it's not (yet) done). (But he wasn't listening)".toList)
balanceMatch(")".toList)
balanceMatch("())()".toList)
def balanceMatch2(chars: List[Char]): Boolean = {
@tailrec
def checkStep(chars: List[Char], n: Int): Boolean = {
chars match {
case Nil => n == 0
case _ if n < 0 => false
case '('::rest => checkStep(rest, n + 1)
case ')'::rest => checkStep(rest, n - 1)
case _::rest => checkStep(rest, n)
}
}
checkStep(chars, 0)
}
balanceMatch2("(if (x == 0) then max (1, x))".toList)
balanceMatch2("I told him (that it's not (yet) done). (But he wasn't listening)".toList)
balanceMatch2(")".toList)
balanceMatch2("())()".toList)
balanceMatch2("())(()".toList)
balanceMatch2("(".toList)

View File

@ -0,0 +1,8 @@
def compress[T](list: List[T]): List[T] = {
list.foldRight(List.empty[T])((elmt: T, res: List[T]) => res match {
case head::_ if head == elmt => res
case _ => elmt::res
})
}
compress(List('a', 'a', 'a', 'a', 'b', 'c', 'c', 'a', 'a', 'd', 'e', 'e', 'e', 'e'))

57
src/utils/package.scala Normal file
View File

@ -0,0 +1,57 @@
/**
* Some useful functions for Scala.
*
* @author Pierre-André Mudry
* @version 1.0
*/
import java.io.{BufferedOutputStream, File, FileOutputStream}
import scala.io.{Codec, Source}
package object utils {
/**
* There are functions for micro-benchmarking, but you should not
* rely on those functions for measuring short durations!
*/
// Measure the time for a block of code to run, approximately
def timeVerbose(f: Unit) = {
println("[Time] Start of measure")
val duration = time(f)
println(s"[Time] Block duration was $duration ms\n")
duration
}
// With a customized error message
def timeVerbose(s: String)(f: Unit) = {
println(s"[$s] Start of measure")
val duration = time(f)
println(s"[$s] Block duration was $duration ms\n")
duration
}
// Measure the time for a block of code to run, approximately
def time(f: Unit) = {
val start = System.currentTimeMillis
f // Execute the block
val duration = System.currentTimeMillis - start
duration
}
/**
* A class for reading and writing to files easily
*/
implicit class RichFile(file: File) {
def read() = Source.fromFile(file)(Codec.UTF8).mkString
def write(data: String) {
val fos = new BufferedOutputStream(new FileOutputStream(file))
try {
fos.write(data.getBytes("UTF-8"))
} finally {
fos.close
}
}
}
}