Compare commits
46 Commits
f66fdac8b4
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
b7ca6610fc
|
|||
|
ec0e1e8ae4
|
|||
|
5365eabadd
|
|||
|
43e0694d9d
|
|||
|
c13f9851e3
|
|||
|
bed771a04e
|
|||
|
6954695a0d
|
|||
|
a16b70970f
|
|||
|
34b1ff39ce
|
|||
|
e58c399bad
|
|||
|
95fdbf7abf
|
|||
|
17c1e4170d
|
|||
|
d4878015e3
|
|||
|
f693d69366
|
|||
|
d8b22157c5
|
|||
|
9ad00e6182
|
|||
|
b53e0677cc
|
|||
|
056305fd72
|
|||
|
f4e417571a
|
|||
|
4eba7f3587
|
|||
|
76a4f50075
|
|||
|
41c0b80d8b
|
|||
|
3f648b7fc9
|
|||
|
84315955f8
|
|||
|
bbfcb31026
|
|||
|
03c383fb35
|
|||
|
eebfe377c7
|
|||
|
8c01471dda
|
|||
|
56f41ecc22
|
|||
|
2f72fbb599
|
|||
|
9eeb59f1e0
|
|||
|
b18b92fb0b
|
|||
|
e9b68c0913
|
|||
|
bba0ee90d4
|
|||
|
34f88cdf28
|
|||
|
1dc768ae51
|
|||
|
a608a602ad
|
|||
|
966767f58c
|
|||
|
7a6168dd50
|
|||
|
f4d0c9adfa
|
|||
|
529e6967c4
|
|||
|
3d87c132b9
|
|||
|
1a567b6b4e
|
|||
|
53c4036f85
|
|||
|
444c83afb2
|
|||
|
3c2e6a7175
|
161
README.md
Normal file
161
README.md
Normal file
@@ -0,0 +1,161 @@
|
||||
<h1>205.1 Functional Programming</h1>
|
||||
|
||||
<p align="center">
|
||||
<img src="icon.svg" width="80" alt="Lambda in the colors of the Scala logo (red)">
|
||||
</p>
|
||||
|
||||
---
|
||||
<h2>Table of Contents</h2>
|
||||
|
||||
|
||||
<!-- TOC -->
|
||||
* [Lessons](#lessons)
|
||||
* [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)
|
||||
* [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 -->
|
||||
|
||||
|
||||
---
|
||||
|
||||
## Lessons
|
||||
|
||||
### Lesson 1 - Evaluation
|
||||
[Files](src/Lesson1)
|
||||
- Call by name / Call by value
|
||||
- State-less functions
|
||||
|
||||
### Lesson 2 - Higher order functions
|
||||
[Files](src/Lesson2)
|
||||
- Curryfication
|
||||
- Recursion
|
||||
- Tail recursion
|
||||
|
||||
### Lesson 3 - Data structures
|
||||
[Files](src/Lesson3)
|
||||
- Functional data structures
|
||||
- Binary tree
|
||||
- Operation precedence
|
||||
|
||||
### Lesson 4 - Lists and pattern matching
|
||||
[Files](src/Lesson4)
|
||||
- List
|
||||
- Pattern matching
|
||||
- Genericity
|
||||
|
||||
### Lesson 5 - Advanced lists and High order functions
|
||||
[Files](src/Lesson5)
|
||||
- Lists
|
||||
- High order functions
|
||||
|
||||
### 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
|
||||
[Files](src/Assignment1)
|
||||
- Recursion
|
||||
- Newton
|
||||
- Tail recursion
|
||||
|
||||
### Assignment 2 - Map-reduce
|
||||
[Files](src/Assignment2)
|
||||
- Fibonacci
|
||||
- Sum
|
||||
- Map-reduce
|
||||
|
||||
### Assignment 3 - Binary tree
|
||||
[Files](src/Assignment3)
|
||||
- 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)
|
||||
|
||||
### Assignment 5 - High-order functions on lists
|
||||
[Files](src/Assignment5)
|
||||
- High-order functions
|
||||
- Lists
|
||||
- Map
|
||||
- Fold
|
||||
- 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
|
||||
126
icon.svg
Normal file
126
icon.svg
Normal file
@@ -0,0 +1,126 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="128"
|
||||
height="128"
|
||||
viewBox="0 0 128 128"
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
sodipodi:docname="icon.svg"
|
||||
inkscape:version="1.4 (e7c3feb100, 2024-10-09)"
|
||||
inkscape:export-filename="icon.png"
|
||||
inkscape:export-xdpi="96"
|
||||
inkscape:export-ydpi="96"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<sodipodi:namedview
|
||||
id="namedview1"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:document-units="mm"
|
||||
showgrid="true"
|
||||
inkscape:zoom="5.7798541"
|
||||
inkscape:cx="63.928949"
|
||||
inkscape:cy="68.773362"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1016"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="27"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="layer1">
|
||||
<inkscape:grid
|
||||
id="grid3"
|
||||
units="px"
|
||||
originx="0"
|
||||
originy="0"
|
||||
spacingx="1"
|
||||
spacingy="1"
|
||||
empcolor="#0099e5"
|
||||
empopacity="0.30196078"
|
||||
color="#0099e5"
|
||||
opacity="0.14901961"
|
||||
empspacing="16"
|
||||
enabled="true"
|
||||
visible="true" />
|
||||
</sodipodi:namedview>
|
||||
<defs
|
||||
id="defs1">
|
||||
<linearGradient
|
||||
id="linearGradient10"
|
||||
inkscape:collect="always">
|
||||
<stop
|
||||
style="stop-color:#4e4e4e;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop10" />
|
||||
<stop
|
||||
style="stop-color:#000000;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop11" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient8"
|
||||
inkscape:collect="always">
|
||||
<stop
|
||||
style="stop-color:#c40000;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop8" />
|
||||
<stop
|
||||
style="stop-color:#ff0000;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop9" />
|
||||
</linearGradient>
|
||||
<rect
|
||||
x="37.92537"
|
||||
y="44.042365"
|
||||
width="295.5732"
|
||||
height="25.93606"
|
||||
id="rect1" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient8"
|
||||
id="linearGradient9"
|
||||
x1="18.422545"
|
||||
y1="64"
|
||||
x2="109.57747"
|
||||
y2="64"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(-1.999545,-1)" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient10"
|
||||
id="linearGradient11"
|
||||
x1="18.422545"
|
||||
y1="64"
|
||||
x2="109.57746"
|
||||
y2="64"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
</defs>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1">
|
||||
<g
|
||||
id="g11"
|
||||
transform="matrix(1.2023042,0,0,1.2023042,-11.745442,-12.346318)">
|
||||
<path
|
||||
style="fill:url(#linearGradient11);fill-opacity:1;stroke:none;stroke-width:1.99937;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 60.310857,20 H 34.422545 v 16 h 16 l 8,16 -40,48 H 37.503412 L 65.57787,66.310651 86.422545,108 109.57746,96.422544 l -7.15534,-14.310651 -8.844251,4.42213 z"
|
||||
id="path3"
|
||||
sodipodi:nodetypes="ccccccccccccc" />
|
||||
<path
|
||||
style="fill:url(#linearGradient9);stroke:none;stroke-width:1.99937;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 58.311312,19 H 32.423 v 16 h 16 l 8,16 -40,48 H 35.503867 L 63.578325,65.310651 84.423,107 l 23.15493,-11.577456 -7.15534,-14.310651 -8.84427,4.42213 z"
|
||||
id="path3-7"
|
||||
sodipodi:nodetypes="ccccccccccccc" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.8 KiB |
90
src/Assignment3/IntSet.sc
Normal file
90
src/Assignment3/IntSet.sc
Normal file
@@ -0,0 +1,90 @@
|
||||
abstract class IntSet() {
|
||||
def add(x: Int): IntSet
|
||||
def contains(x: Int): Boolean
|
||||
def foreach(f: Int => Unit): Unit
|
||||
def union(other: IntSet): IntSet
|
||||
def intersect(other: IntSet): IntSet
|
||||
def excl(x: Int): IntSet
|
||||
def +(x: Int): IntSet = this.add(x)
|
||||
def -(x: Int): IntSet = this.excl(x)
|
||||
}
|
||||
|
||||
class NonEmpty(elem: Int, left: IntSet, right: IntSet) extends IntSet() {
|
||||
def add(x: Int): IntSet = {
|
||||
if (x < elem) new NonEmpty(elem, left add x, right)
|
||||
else if (x > elem) new NonEmpty(elem, left, right add x)
|
||||
else this
|
||||
}
|
||||
|
||||
def contains(x: Int): Boolean =
|
||||
if (x < elem) left contains x
|
||||
else if (x > elem) right contains x
|
||||
else true
|
||||
|
||||
override def toString = "(" + left + "|" + elem + "|" + right + ")"
|
||||
|
||||
def foreach(f: Int => Unit): Unit = {
|
||||
left.foreach(f)
|
||||
f(elem)
|
||||
right.foreach(f)
|
||||
}
|
||||
|
||||
def union(other: IntSet): IntSet =
|
||||
this.left.union(right)
|
||||
.union(other)
|
||||
.add(this.elem)
|
||||
|
||||
def intersect(other: IntSet): IntSet = {
|
||||
val base = if (other.contains(this.elem)) Empty.add(this.elem)
|
||||
else Empty
|
||||
base.union(this.left.intersect(other))
|
||||
.union(this.right.intersect(other))
|
||||
}
|
||||
|
||||
def excl(x: Int): IntSet = {
|
||||
if (x < elem) new NonEmpty(elem, this.left.excl(x), this.right)
|
||||
else if (x > elem) new NonEmpty(elem, this.left, this.right.excl(x))
|
||||
else this.left.union(this.right)
|
||||
}
|
||||
}
|
||||
|
||||
object Empty extends IntSet() {
|
||||
def add(x: Int): IntSet = new NonEmpty(x, Empty, Empty)
|
||||
def contains(x: Int): Boolean = false
|
||||
override def toString = "-"
|
||||
|
||||
def foreach(f: Int => Unit): Unit = {}
|
||||
def union(other: IntSet): IntSet = other
|
||||
def intersect(other: IntSet): IntSet = Empty
|
||||
def excl(x: Int): IntSet = this
|
||||
}
|
||||
|
||||
val t1 = Empty
|
||||
val t2 = t1 add 3
|
||||
val t3 = t1 add 4 add 5 add 2 add 6
|
||||
t3 contains 4
|
||||
|
||||
println(Empty) // prints -
|
||||
println(Empty.add(3)) // prints (-|3|-)
|
||||
println(Empty.add(3).add(2)) // prints ((-|2|-)|3|-)
|
||||
|
||||
val s = Empty.add(3).add(2).add(7).add(1)
|
||||
s.foreach(println)
|
||||
|
||||
(Empty.add(3).add(2).add(6).add(1)) foreach (x => print(x+1 + ", "))
|
||||
// 2, 3, 4, 7,
|
||||
// Because a BST is always sorted
|
||||
|
||||
val s2 = Empty.add(3).add(4).add(6).add(2)
|
||||
|
||||
s.union(s2)
|
||||
s.intersect(s2)
|
||||
|
||||
s2.excl(0)
|
||||
s2.excl(6)
|
||||
s2.excl(2)
|
||||
s2.excl(4)
|
||||
|
||||
val o1 = Empty + 3 + 4 + 12 + 5
|
||||
val o2 = (o1 - 3 - 4)
|
||||
o2 // ((-|5|-)|12|-)
|
||||
60
src/Assignment4/Ex1_Expressions.sc
Normal file
60
src/Assignment4/Ex1_Expressions.sc
Normal 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)
|
||||
22
src/Assignment4/Ex2_Trees.sc
Normal file
22
src/Assignment4/Ex2_Trees.sc
Normal 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)
|
||||
64
src/Assignment4/Ex3_Lists.sc
Normal file
64
src/Assignment4/Ex3_Lists.sc
Normal 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(n²)
|
||||
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)
|
||||
79
src/Assignment4/Ex3_ListsMatch.sc
Normal file
79
src/Assignment4/Ex3_ListsMatch.sc
Normal file
@@ -0,0 +1,79 @@
|
||||
import scala.annotation.tailrec
|
||||
|
||||
|
||||
// Complexity: O(n)
|
||||
@tailrec
|
||||
def last[T](list: List[T]): T = {
|
||||
list.tail match {
|
||||
case Nil => list.head
|
||||
case _ => last(list.tail)
|
||||
}
|
||||
}
|
||||
|
||||
def init[T](list: List[T]): List[T] = {
|
||||
list.tail match {
|
||||
case Nil => Nil
|
||||
case _ => list.head::init(list.tail)
|
||||
}
|
||||
}
|
||||
|
||||
// Complexity: O(n)
|
||||
def concat[T](l1: List[T], l2: List[T]): List[T] = {
|
||||
l1 match {
|
||||
case Nil => l2
|
||||
case _ => l1.head::concat(l1.tail, l2)
|
||||
}
|
||||
}
|
||||
|
||||
// Complexity: O(n²)
|
||||
def reverse[T](list: List[T]): List[T] = {
|
||||
list match {
|
||||
case Nil => Nil
|
||||
case _ => last(list)::reverse(init(list))
|
||||
}
|
||||
}
|
||||
|
||||
// Better -> O(n)
|
||||
/*
|
||||
def reverse[T](list: List[T], res: List[T] = Nil): List[T] = {
|
||||
list match {
|
||||
case Nil => res
|
||||
case _ => reverse(list.tail, list.head::res)
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
def take[T](list: List[T], n: Int): List[T] = {
|
||||
if (n <= 0) Nil
|
||||
else list match {
|
||||
case Nil => Nil
|
||||
case _ => list.head::take(list.tail, n - 1)
|
||||
}
|
||||
}
|
||||
|
||||
@tailrec
|
||||
def drop[T](list: List[T], n: Int): List[T] = {
|
||||
if (n <= 0) list
|
||||
else list match {
|
||||
case Nil => list
|
||||
case _ => drop(list.tail, n - 1)
|
||||
}
|
||||
}
|
||||
|
||||
@tailrec
|
||||
def apply[T](list: List[T], n: Int): T = {
|
||||
n match {
|
||||
case 0 => list.head
|
||||
case _ => 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)
|
||||
24
src/Assignment4/Ex4_Predicates.sc
Normal file
24
src/Assignment4/Ex4_Predicates.sc
Normal 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))
|
||||
36
src/Assignment5/Folds.sc
Normal file
36
src/Assignment5/Folds.sc
Normal file
@@ -0,0 +1,36 @@
|
||||
def areTrue(booleans: List[Boolean]): Boolean = {
|
||||
booleans.foldLeft(true)((acc, value) => acc && value)
|
||||
}
|
||||
|
||||
def lString(strings: List[String]): Int = {
|
||||
strings.foldLeft(0)((len, str) => len + str.length)
|
||||
}
|
||||
|
||||
def longest(strings: List[String]): Int = {
|
||||
strings.foldLeft(0)((maxLen, str) => if (str.length > maxLen) str.length else maxLen)
|
||||
}
|
||||
|
||||
def isPresent[T](list: List[T], target: T): Boolean = {
|
||||
list.foldLeft(false)((res, value) => res || value == target)
|
||||
}
|
||||
|
||||
def flattenList(list: List[Any]): List[Any] = {
|
||||
list.foldRight(List.empty[Any])((elem, acc) => {
|
||||
elem match {
|
||||
case l: List[Any] => flattenList(l).foldRight(acc)((e, l) => e::l)
|
||||
case _ => elem::acc
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
assert(!areTrue(List(true, true, false)))
|
||||
assert(areTrue(List(true, true, true)))
|
||||
|
||||
assert(lString(List("Folding", "is", "fun")) == 12)
|
||||
|
||||
assert(longest(List("What", "is", "the", "longest?")) == 8)
|
||||
|
||||
assert(!isPresent(List(1, 2, 3, 4), 5))
|
||||
assert(isPresent(List(1, 2, 3, 4), 3))
|
||||
|
||||
assert(flattenList(List(List(1, 1), 2, List(3, List(5, 8)))) == List(1, 1, 2, 3, 5, 8))
|
||||
18
src/Assignment5/HOFOnLists.sc
Normal file
18
src/Assignment5/HOFOnLists.sc
Normal file
@@ -0,0 +1,18 @@
|
||||
def lengthStrings(strings: List[String]): List[Int] = {
|
||||
strings map (s => s.length)
|
||||
}
|
||||
|
||||
def dup[T](elem: T, n: Int): List[T] = {
|
||||
(1 to n).toList map (_ => elem)
|
||||
}
|
||||
|
||||
def dot(list1: List[Int], list2: List[Int]): List[Int] = {
|
||||
list1 zip list2 map (p => p._1 * p._2)
|
||||
}
|
||||
|
||||
assert(lengthStrings(List("How","long","are","we?")) == List(3, 4, 3, 3))
|
||||
|
||||
assert(dup("foo", 5) == List("foo", "foo", "foo", "foo", "foo"))
|
||||
assert(dup(List(1,2,3), 2) == List(List(1,2,3), List(1,2,3)))
|
||||
|
||||
assert(dot(List(1,2,3), List(2,4,3)) == List(2,8,9))
|
||||
17
src/Assignment6/Ex1.sc
Normal file
17
src/Assignment6/Ex1.sc
Normal 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
38
src/Assignment6/Ex2.sc
Normal 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
22
src/Assignment6/Ex3.sc
Normal 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
39
src/Assignment6/Ex4.sc
Normal 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
35
src/Assignment7/Ex1.sc
Normal 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
9
src/Assignment7/Ex2.sc
Normal 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
12
src/Assignment7/Ex3.sc
Normal 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
19
src/Assignment7/Ex4.sc
Normal 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
26
src/Assignment7/Ex5.sc
Normal 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
24
src/Assignment8/Ex1.scala
Normal 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
62
src/Assignment8/Ex2.scala
Normal 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)
|
||||
}
|
||||
29
src/Assignment9/Assignment9.scala
Normal file
29
src/Assignment9/Assignment9.scala
Normal 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
16
src/Assignment9/Ex1.scala
Normal 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()
|
||||
}
|
||||
36
src/Final1/Exercise1.scala
Normal file
36
src/Final1/Exercise1.scala
Normal 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))
|
||||
}
|
||||
}
|
||||
10
src/Final1/Exercise2.scala
Normal file
10
src/Final1/Exercise2.scala
Normal 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)
|
||||
})
|
||||
}
|
||||
}
|
||||
55
src/Final1/Exercise3.scala
Normal file
55
src/Final1/Exercise3.scala
Normal 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
26
src/FinalPrep1/Ex1.sc
Normal 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
18
src/FinalPrep1/Ex2.sc
Normal 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
165
src/FinalPrep1/Ex3.sc
Normal 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
|
||||
21
src/Lesson3/Rational.sc
Normal file
21
src/Lesson3/Rational.sc
Normal file
@@ -0,0 +1,21 @@
|
||||
class Rational(n: Int, d: Int) {
|
||||
def num = n
|
||||
def denom = d
|
||||
}
|
||||
|
||||
def add(x: Rational, y: Rational): Rational =
|
||||
new Rational(
|
||||
x.num * y.denom + x.denom * y.num,
|
||||
x.denom * y.denom
|
||||
)
|
||||
|
||||
def stringVersion(x: Rational) = x.num + "/" + x.denom
|
||||
|
||||
val r1 = new Rational(1, 2)
|
||||
r1.num
|
||||
r1.denom
|
||||
|
||||
val r2 = new Rational(3, 4)
|
||||
|
||||
val r3 = add(r1, r2)
|
||||
stringVersion(r3)
|
||||
41
src/Lesson3/Rational2.sc
Normal file
41
src/Lesson3/Rational2.sc
Normal file
@@ -0,0 +1,41 @@
|
||||
import scala.annotation.tailrec
|
||||
|
||||
class Rational(n: Int, d: Int) {
|
||||
require(d != 0)
|
||||
|
||||
@tailrec
|
||||
private def gcd(x: Int, y: Int): Int =
|
||||
if (y == 0) x else gcd(y, x % y)
|
||||
|
||||
private val g: Int = gcd(n, d)
|
||||
def num: Int = n / g
|
||||
def denom: Int = d / g
|
||||
|
||||
|
||||
def +(that: Rational): Rational = new Rational(
|
||||
this.num * that.denom + this.denom * that.num,
|
||||
this.denom * that.denom
|
||||
)
|
||||
|
||||
def unary_- : Rational = new Rational(-num, denom)
|
||||
|
||||
def <(that: Rational): Boolean = this.num * that.denom < that.num * this.denom
|
||||
|
||||
def max(that: Rational): Rational = if (this < that) that else this
|
||||
|
||||
override def toString = if (math.abs(denom) == 1) "" + denom else num + "/" + denom
|
||||
}
|
||||
|
||||
val r1 = new Rational(1, 3)
|
||||
val r2 = new Rational(2, 3)
|
||||
val r3 = r1 + r2
|
||||
|
||||
r3
|
||||
|
||||
-r2
|
||||
|
||||
r2 < r1
|
||||
r2 < r3
|
||||
|
||||
r2.max(r1)
|
||||
r2.max(r3)
|
||||
13
src/Lesson4/Lists.sc
Normal file
13
src/Lesson4/Lists.sc
Normal 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)
|
||||
35
src/Lesson4/PatternMatching.sc
Normal file
35
src/Lesson4/PatternMatching.sc
Normal 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
4
src/Lesson4/Types.sc
Normal file
@@ -0,0 +1,4 @@
|
||||
val a: String = "Hell" + "o" * 50
|
||||
def b(s: String): String = "Hell" + s
|
||||
|
||||
a == b("o" * 50)
|
||||
19
src/Lesson5/Ex5_2.sc
Normal file
19
src/Lesson5/Ex5_2.sc
Normal file
@@ -0,0 +1,19 @@
|
||||
def length[A](x: List[A]): Int = {
|
||||
x.foldRight(0)((elem: A, len: Int) => len + 1)
|
||||
}
|
||||
|
||||
def map[A, B](x: List[A], f: A => B): List[B] = {
|
||||
x.foldRight(List.empty[B])((elem: A, list: List[B]) => f(elem)::list)
|
||||
}
|
||||
|
||||
def dup[A](l: List[A]): List[A] = {
|
||||
l.flatMap(e => List(e, e))
|
||||
}
|
||||
|
||||
def dup2[A](l: List[A]): List[A] = {
|
||||
l.foldRight(List.empty[A])((e, l) => e::e::l)
|
||||
}
|
||||
|
||||
length(1::2::3::4::Nil)
|
||||
map(1::2::3::4::Nil, (x: Int) => x * 2)
|
||||
dup(1::2::3::Nil)
|
||||
18
src/Lesson6/Comprehension.sc
Normal file
18
src/Lesson6/Comprehension.sc
Normal 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
40
src/Lesson6/Ex_6.1.sc
Normal 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
29
src/Lesson6/Primes.sc
Normal 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)
|
||||
}
|
||||
25
src/Lesson6/Translations.sc
Normal file
25
src/Lesson6/Translations.sc
Normal 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
13
src/Lesson6/Tuples.sc
Normal 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
12
src/Lesson7/Daltons.sc
Normal 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
|
||||
6
src/Lesson7/LazyEvaluation.sc
Normal file
6
src/Lesson7/LazyEvaluation.sc
Normal 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
11
src/Lesson7/LazyList.sc
Normal 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
|
||||
16
src/Lesson7/LoggingFactory.sc
Normal file
16
src/Lesson7/LoggingFactory.sc
Normal 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
25
src/Lesson7/Variance.sc
Normal 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
19
src/Lesson8/Actors.scala
Normal 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
18
src/Lesson8/Futures.scala
Normal 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")
|
||||
}
|
||||
}
|
||||
15
src/Lesson9/PimpMyLibrary.scala
Normal file
15
src/Lesson9/PimpMyLibrary.scala
Normal 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
7
src/MidTerm1/Ex1.sc
Normal 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
55
src/MidTerm1/Ex2.sc
Normal 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
37
src/MidTerm1/Ex3.sc
Normal 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)
|
||||
}
|
||||
29
src/MidTermPrep1/Ex1.sc
Normal file
29
src/MidTermPrep1/Ex1.sc
Normal file
@@ -0,0 +1,29 @@
|
||||
import scala.annotation.tailrec
|
||||
|
||||
def foo(x: Int): Int = {
|
||||
println("Foo !")
|
||||
x + 1
|
||||
}
|
||||
|
||||
def bar(x: => Int): Unit = {
|
||||
println("x1=" + x)
|
||||
println("x2=" + x)
|
||||
}
|
||||
|
||||
bar(foo(3))
|
||||
// Foo !
|
||||
// x1=4
|
||||
// Foo !
|
||||
// x2=4
|
||||
|
||||
|
||||
def toUpper(s: String): String = {
|
||||
@tailrec
|
||||
def helper(s: String, res: String): String = {
|
||||
if (s.isEmpty) res
|
||||
else helper(s.tail, res + s.head.toUpper)
|
||||
}
|
||||
helper(s, "")
|
||||
}
|
||||
|
||||
toUpper("hello")
|
||||
36
src/MidTermPrep1/Ex2.sc
Normal file
36
src/MidTermPrep1/Ex2.sc
Normal file
@@ -0,0 +1,36 @@
|
||||
import scala.annotation.tailrec
|
||||
|
||||
def balanceMatch(chars: List[Char]): Boolean = {
|
||||
@tailrec
|
||||
def checkStep(chars: List[Char], n: Int): Boolean = {
|
||||
if (chars.isEmpty) n == 0
|
||||
else if (n < 0) false
|
||||
else checkStep(chars.tail, chars.head match {
|
||||
case '(' => n + 1
|
||||
case ')' => n - 1
|
||||
case _ => n
|
||||
})
|
||||
}
|
||||
checkStep(chars, 0)
|
||||
}
|
||||
|
||||
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)
|
||||
36
src/MidTermPrep1/Ex3.sc
Normal file
36
src/MidTermPrep1/Ex3.sc
Normal file
@@ -0,0 +1,36 @@
|
||||
import scala.annotation.tailrec
|
||||
|
||||
def countTrue(bools: List[Boolean]): Int = {
|
||||
bools.foldLeft(0)((n, bool) => if (bool) n + 1 else n)
|
||||
}
|
||||
|
||||
countTrue(List(true, true, false, true, false, false))
|
||||
|
||||
def remDup[T](list: List[T]): List[T] = {
|
||||
list.foldRight(List.empty[T])((elem: T, res: List[T]) => {
|
||||
if (res.contains(elem)) res
|
||||
else elem::res
|
||||
})
|
||||
}
|
||||
|
||||
def remDup2[T](list: List[T]): List[T] = {
|
||||
list.foldLeft(List.empty[T])((res: List[T], elem: T) => {
|
||||
if (res.contains(elem)) res
|
||||
else res :+ elem
|
||||
})
|
||||
}
|
||||
|
||||
def remDup3[T](list: List[T]): List[T] = {
|
||||
@tailrec
|
||||
def helper(list: List[T], distinct: List[T]): List[T] = {
|
||||
list match {
|
||||
case head::rest if distinct.contains(head) => helper(rest, distinct)
|
||||
case head::rest => helper(rest, distinct :+ head)
|
||||
case Nil => distinct
|
||||
}
|
||||
}
|
||||
helper(list, List.empty[T])
|
||||
}
|
||||
|
||||
remDup(List(5,3,2,4,3,2,3,3)) // List(5,3,2,4)
|
||||
remDup(List("hello", "youpi", "hello", "hello")) // List("hello", "youpi")
|
||||
8
src/MidTermPrep1/Exercices.sc
Normal file
8
src/MidTermPrep1/Exercices.sc
Normal 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
57
src/utils/package.scala
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user