Compare commits

...

6 Commits

Author SHA1 Message Date
b18b92fb0b updated README 2025-03-11 19:02:12 +01:00
e9b68c0913 added assignment 4 ex 4 2025-03-11 18:58:48 +01:00
bba0ee90d4 added assignment 4 ex 3 2025-03-11 18:55:03 +01:00
34f88cdf28 added assignment 4 ex 2 2025-03-11 15:49:58 +01:00
1dc768ae51 added assignment 4 ex 1 2025-03-11 15:46:12 +01:00
a608a602ad added lesson 4 2025-03-11 15:46:02 +01:00
8 changed files with 237 additions and 0 deletions

View File

@@ -13,10 +13,12 @@
* [Lesson 1 - Evaluation](#lesson-1---evaluation)
* [Lesson 2 - Higher order functions](#lesson-2---higher-order-functions)
* [Lesson 3 - Data structures](#lesson-3---data-structures)
* [Lesson 4 - Lists and pattern matching](#lesson-4---lists-and-pattern-matching)
* [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)
<!-- TOC -->
@@ -41,6 +43,12 @@
- Binary tree
- Operation precedence
### Lesson 4 - Lists and pattern matching
[Files](src/Lesson4)
- List
- Pattern matching
- Genericity
## Assignments
### Assignment 1 - Square root
@@ -60,3 +68,10 @@
- Int set
- Binary tree
- Union / intersection / foreach
### Assignment 4 - Lists and pattern matching
[Files](src/Assignment4)
- Expression interpreter
- Binary tree
- List functions
- Predicates (any / every)

View File

@@ -0,0 +1,60 @@
sealed abstract class Expr
case class Number(n: Int) extends Expr
case class Sum(e1: Expr, e2: Expr) extends Expr
case class Product(e1: Expr, e2: Expr) extends Expr
def eval(e: Expr): Int = e match {
case Number(n) => n
case Sum(e1, e2) => eval(e1) + eval(e2)
case Product(e1, e2) => eval(e1) * eval(e2)
}
def show(e: Expr): String = e match {
case Number(n) => n.toString
case Sum(e1, e2) => show(e1) + " + " + show(e2)
case Product(e1, e2) => {
val left: String = e1 match {
case Sum(e1a, e1b) => "(" + show(e1) + ")"
case _ => show(e1)
}
val right: String = e2 match {
case Sum(e2a, e2b) => "(" + show(e2) + ")"
case _ => show(e2)
}
left + " * " + right
}
}
val e1: Expr = Sum(Number(1), Sum(Number(2), Number(3)))
eval(e1)
show(e1)
val e2: Expr = Sum(
Number(2),
Product(
Number(3),
Sum(
Number(4),
Number(5)
)
)
)
eval(e2)
show(e2)
val expr0 = Sum(Product(Number(2), Number(3)), Number(4))
println("Expr0: " + show(expr0)) // Expr0: 2*3+4
assert(eval(expr0) == 10)
val expr1 = Product(Number(4), Number(12))
println("Expr1: " + show(expr1)) // Expr1: 4*12
assert(eval(expr1) == 48)
val expr2 = Product(Sum(Number(2), Number(3)), Number(4))
println("Expr2: " + show(expr2)) // Expr2: (2+3)*4
assert(eval(expr2) == 20)
val expr3 = Product(Number(2), Sum(Number(3), Number(4)))
println("Expr3: " + show(expr3)) // Expr3: 2*(3+4)
assert(eval(expr3) == 14)

View File

@@ -0,0 +1,22 @@
sealed abstract class BinaryTree
case class Leaf(value: Int) extends BinaryTree
case class Node(left: BinaryTree, right: BinaryTree) extends BinaryTree
def leafSum(tree: BinaryTree): Int = {
tree match {
case Leaf(value) => value
case Node(left, right) => leafSum(left) + leafSum(right)
}
}
def min(a: Int, b: Int): Int = if (a < b) a else b
def smallest(tree: BinaryTree): Int = {
tree match {
case Leaf(value) => value
case Node(left, right) => min(smallest(left), smallest(right))
}
}
assert(leafSum(Node(Node(Leaf(3), Leaf(8)), Leaf(5))) == 16)
assert(smallest(Node(Node(Leaf(3), Leaf(5)), Leaf(-5))) == -5)

View File

@@ -0,0 +1,64 @@
import scala.annotation.tailrec
// Complexity: O(n)
@tailrec
def last[T](list: List[T]): T = {
if (list.isEmpty) throw new NoSuchElementException()
if (list.tail.isEmpty) list.head
else last(list.tail)
}
def init[T](list: List[T]): List[T] = {
if (list.isEmpty) list
else if (list.tail.isEmpty) Nil
else list.head::init(list.tail)
}
// Complexity: O(n)
def concat[T](l1: List[T], l2: List[T]): List[T] = {
if (l1.isEmpty) l2
else l1.head::concat(l1.tail, l2)
}
// Complexity: O()
def reverse[T](list: List[T]): List[T] = {
if (list.isEmpty) Nil
else last(list)::reverse(init(list))
}
// Better -> O(n)
/*
def reverse[T](list: List[T], res: List[T] = Nil): List[T] = {
if (list.isEmpty) res
else reverse(list.tail, list.head::res)
}
*/
def take[T](list: List[T], n: Int): List[T] = {
if (list.isEmpty || n <= 0) Nil
else list.head::take(list.tail, n - 1)
}
@tailrec
def drop[T](list: List[T], n: Int): List[T] = {
if (list.isEmpty || n <= 0) list
else drop(list.tail, n - 1)
}
@tailrec
def apply[T](list: List[T], n: Int): T = {
if (list.isEmpty) throw new NoSuchElementException()
else if (n == 0) list.head
else apply(list.tail, n - 1)
}
assert(last(List(1,2,3)) == 3)
assert(init(List(1,2,3)) == List(1,2))
assert(concat(List(1,2,3), List(4,5,6)) == List(1,2,3,4,5,6))
assert(reverse(List(1,2,3)) == List(3,2,1))
assert(take(List(1,2,3), 2) == List(1,2))
assert(drop(List(1,2,3), 2) == List(3))
assert(drop(List(1,2,3), 4) == Nil)
assert(apply(List(1,2,3), 2) == 3)

View File

@@ -0,0 +1,24 @@
import scala.annotation.tailrec
@tailrec
def any[T](p: T => Boolean)(l: List[T]): Boolean = {
if (l.isEmpty) false
else if (p(l.head)) true
else any(p)(l.tail)
}
@tailrec
def every[T](p: T => Boolean)(l: List[T]): Boolean = {
if (l.isEmpty) true
else if (!p(l.head)) false
else every(p)(l.tail)
}
val a = List(1, 2, 3, 4, 5)
assert(!any((x: Int) => x == 12)(a))
assert(any((x: Int) => x > 4)(a))
val a = List(1, 2, 3, 4, 5)
val b = List(2, 4, 6, 8, 10)
assert(!every((x: Int) => (x % 2) == 0)(a))
assert(every((x: Int) => (x % 2) == 0)(b))

13
src/Lesson4/Lists.sc Normal file
View File

@@ -0,0 +1,13 @@
def insert(x: Int, xs: List[Int]): List[Int] = {
if (xs.isEmpty) x::Nil
else if (x < xs.head) x::xs
else xs.head::insert(x, xs.tail)
}
def isort(xs: List[Int]): List[Int] = {
if (xs.isEmpty) Nil
else insert(xs.head, isort(xs.tail))
}
isort(7::3::9::2::Nil)

View File

@@ -0,0 +1,35 @@
def patFoo(value: Any): Boolean = {
value match {
case a: Int => a % 4 == 0
case c: Char => c.isUpper
case b: Boolean => true
case _ => false
}
}
abstract class Expr
case class Number(n: Int) extends Expr
case class Sum(e1: Expr, e2: Expr) extends Expr
def eval(e: Expr): Int = e match {
case Number(n) => n
case Sum(e1, e2) => eval(e1) + eval(e2)
}
def show(e: Expr): String = e match {
case Number(n) => n.toString
case Sum(e1, e2) => "(" + show(e1) + " + " + show(e2) + ")"
}
patFoo(23)
patFoo(24)
patFoo('a')
patFoo('A')
patFoo(false)
patFoo(true)
patFoo("Hello")
patFoo(null)
val e: Expr = Sum(Number(3), Sum(Number(4), Number(5)))
eval(e)
show(e)

4
src/Lesson4/Types.sc Normal file
View File

@@ -0,0 +1,4 @@
val a: String = "Hell" + "o" * 50
def b(s: String): String = "Hell" + s
a == b("o" * 50)