Advertisement
Guest User

Untitled

a guest
Jul 24th, 2017
90
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 14.45 KB | None | 0 0
  1. # Week 1
  2.  
  3. ## lecture "Recap: Functions and Pattern Matching"
  4.  
  5. recursive function + case classes + pattern matching: example JSON printer (Scala -> JSON)
  6. pattern matching in Scala SDK: `PartialFunction` is a Trait with `def isDefinedAt(x: A): Boolean`
  7.  
  8. ## lecture "Recap: Collections"
  9. * `Iterable` (base class)
  10. * `Seq`
  11. * `IndexedSeq` concrete implems below :
  12. * `Vector`
  13. * etc.
  14. * `LinearSeq` concrete implems below :
  15. * `List` : concrete implem
  16. * etc.
  17. * `Set`
  18. * etc.
  19. * `Map`
  20. * etc.
  21.  
  22. All collections have *`map`, `flatMap`, `filter`, `foldLeft`, `foldRight`*
  23. Idealized implementation of these functions use pattern matching.
  24.  
  25. *For expressions*:
  26. * are interesting for simplifying combinations of `map`, `flatMap` and `filter`.
  27. * can use pattern matching in the left-hand side. Example:
  28. ```scala
  29. val data: List[JSON] = ...
  30. for {
  31. JObj(bindings) <- data // implicit filter
  32. JSeq(phones) = bindings("phoneNumbers")
  33. JObj(phone) <- phones
  34. JStr(digits) = phone("number")
  35. if digits starstWith "212"
  36. } yield (bindings("lastname"))
  37. ```
  38.  
  39. ## lecture "Lecture 1.1 - Queries with For"
  40.  
  41. For expressions used as a DSL for database queries.
  42.  
  43. ```scala
  44. case classe Book(title: String, authors: List[String])
  45.  
  46. // mini database:
  47. val book: List[Book] = List(
  48. Book(title="Effective Java", authors = List("Joshua Bloch"))
  49.  
  50. # queries:
  51. // find books whose author's name is "Bird"
  52. for (b <- books ; a <- b.authors if a startsWith "Bird")
  53. yield b.title
  54.  
  55.  
  56. // find names of all authors who have written at least 2 books
  57. {
  58. for {
  59. b1 <- books
  60. b2 <- books
  61. // if b1 != b2 # would return dupes
  62. if b1.title < b2.title
  63. a1 <- b1.authors
  64. a2 <- b2.authors
  65. if a1 == a2
  66. } yield a1
  67. } distinct // otherwise, would return dupes
  68.  
  69. // or better, fix our model so that we don't need to use distinct in queries:
  70. val book: List[Book] = Set( # use a Set instead of a List
  71. Book(title="Effective Java", authors = List("Joshua Bloch"))
  72. ```
  73.  
  74. ## lecture "Translation of For"
  75.  
  76. `map`, `flatMap` and `filter` can be implemented with for expressions.
  77. But the compiler implement for expresions with higher-order functions `map`, `flatMap` and `filter`.
  78.  
  79. ```scala
  80.  
  81. // case 1:
  82. for (x <- e1) yield e2
  83. // is translated to: e1.map(x => e2)
  84.  
  85. // case 2:
  86. for (x <- e1 if f; s) yield e2
  87. // is translated to: for (x <- e1.withFilter(x => f); s) yield e2
  88. // withFilter is a lazy variant of filter that does not produce intermediate list
  89.  
  90. // case 3:
  91. for (x <- e1; y <- e2; s) yield e3
  92. // is translated to:
  93. // e1.flatMap(x => for (y <- e2; s) yield e3)
  94. // and the translation continues...
  95. ```
  96.  
  97. This translation is not onyly done for collections.
  98. It is useful for parsers, databases, etc.
  99. Examples :
  100. - ScalaQuery and Slick Scala libraries
  101. - Microsoft LINQ (C#)
  102. If you provide `map`, `flatMap` and `filter` in your own type, you can use for expressions.
  103.  
  104. ## Functional random generators
  105. Another *use of for expressions*: random value generator (strings, numbers, etc.)
  106. ```
  107. trait Generator[T+] {
  108. def generate: T
  109. }
  110.  
  111. val integers = new Generator[Int] {
  112. val rand = new java.util.Random
  113. def generate = rand.nextInt()
  114. }
  115.  
  116. val booleans = new Generator[Boolean] {
  117. def generate = integers.generate > 0
  118. }
  119.  
  120. val pairs = new Generator[(Int, Int)] {
  121. def generate = (integers.generate, integers.generate)
  122. }
  123.  
  124. //etc.
  125. ```
  126.  
  127. How to reduce boiler-plate code?
  128. ```
  129. trait Generator[T+] {
  130.  
  131. self => // alias for 'this'
  132.  
  133. def generate: T
  134.  
  135. def map[S](f: T => S): Generator[S] {
  136. def generate = f(self.generate) // this.generate would lead to never-ending recursive call
  137. // other way : f(Generator.this.generate
  138. }
  139.  
  140. def flatMap[S](f: T => Generator[S]: Generator[S] = new Generator[S] {
  141. def generate = f(self.generate).generate
  142. }
  143.  
  144. }
  145.  
  146. val booleans = for (x <- integers) yield x > 0
  147.  
  148. val pairs = for{
  149. x <- t
  150. y <- u
  151. } yield (x, y)
  152. ```
  153.  
  154. ```
  155. def single ...
  156.  
  157. def oneOf[T](xs: T*) { //vararg
  158. }
  159.  
  160. def lists: Generators[List[Int]] = for{
  161. isEmpty <- booleans
  162. list <- if (isEmpty) emptyLits else nonEmptyLists
  163. } yield list
  164.  
  165. def emptyList = single(Nil)
  166.  
  167. def nonEmptyLists = for {
  168. head <- integers
  169. tail <- lists
  170. } yield head :: tail
  171. ```
  172.  
  173. example: *tree generator*
  174. application: *random testing* via property-based testing (cf. ScalaCheck library)
  175.  
  176. ## Monads
  177. *Monad* is a design pattern
  178. A monad M is a parametric type M[T]:
  179. - with 2 operations: *`flatMap`* (or *`bind`*) and *`unit`*
  180. having both of them gives `map` operation
  181. - that statify *laws*
  182.  
  183. Examples:
  184. List is a monad with unit(x) = List(x)
  185. Set is a monad with unit(x) = Set(x)
  186. Option is a monad with unit(x) = Some(x)
  187. Generator is a monad with unit(x) = single(x)
  188.  
  189. *3 laws*:
  190. - *associativity*: the result of two `bind` calls does not depend of their order ; ex: (x + y) + z = x + (y + z)
  191. `(m flatMap f) flatMap g == m flatMap ((x => f(x) flatMap g))`
  192. - *left unit*: `unit(x) flatMap f == f(x)`
  193. - *right unit*: `m flatMap unit == m`
  194.  
  195. *Monoid* is a simple form of monad that does not return anything
  196.  
  197. Examples:
  198. `Option` is a monad
  199. `Try` is not a monad (left unit law fails)
  200.  
  201. Additional law: "monads with zero" also define `withFilter`
  202.  
  203.  
  204. # Week 2
  205.  
  206. ## Structural Induction on Trees
  207. Proving session on trees:
  208.  
  209. To prove a property P(t) for all trees t of a certain type, we'll need to:
  210. - show that P(l) holds for all leaves l
  211. - for each type of internal nodes t with subtrees s1, ..., sn, show that:
  212. P(s1) ^ ... ^ P(sn) implies P(t)
  213.  
  214. Example: `IntSets`
  215.  
  216. ## Stream
  217. *Streams* are like lists with tail evaluated on demand (lazily)
  218. => short and elegant notation (/ recursive)
  219.  
  220. Example: find the second prime number between 1000 and 10000
  221. ```scala
  222. ((1000 to 10000) filter isPrime)(1)
  223. ```
  224.  
  225. see `#::` that applies to streams (because `::` produces a list, not a stream)
  226.  
  227. Implem:
  228. ```scala
  229.  
  230. trait Stream[+A] extends Seq[A] {
  231. def isEmpty: Boolean
  232. def head: A
  233. def tail: Stream[A]
  234. }
  235.  
  236. object Stream {
  237.  
  238. // note: the only difference with list is the type of the 2nd parameter:
  239. def cons[T] (hd: T, tl: => Stream[T]) = new Stream[T] {
  240. def isEmpty = false
  241. def head = hd
  242. def tail = tl
  243. }
  244.  
  245. val empty = new Stream[Nothing] {
  246. def isEmpty = true
  247. def head = throw new NoSuchElementException("empty head")
  248. def tail = throw new NoSuchElementException("empty tail")
  249. }
  250.  
  251. }
  252.  
  253. class Stream[T+] {
  254.  
  255. def filter(p: T => Boolean): Stream[T] {
  256. if (isEmpty) this
  257. elseif (p(head)) cons(head, tail.filter(p))
  258. else tail.filter(p)
  259. }
  260.  
  261. }
  262. ```
  263.  
  264. ## lecture "Lazy evaluation"
  265.  
  266. Previous implem has an issue: if tail is called several times, stream will be recomputed.
  267. Solution: store th 1st tail evaluation
  268.  
  269. Haskell uses lazy evaluation, by default.
  270.  
  271. Scala:
  272. - uses strict evaluation, by default.
  273. - allows lazy with `lazy val"
  274.  
  275. ```
  276. lazy val x = expr
  277. ```
  278.  
  279. Fix in our Stream implem:
  280. ```
  281. def cons[T] (hd: T, tl: => Stream[T]) = new Stream[T] {
  282. def head = hd
  283. lazy val tail = tl
  284. }
  285. ```
  286.  
  287. ## lecture "Case study: infinite streams"
  288.  
  289. ex:
  290. ```scala
  291.  
  292. // all integers:
  293. def from(n: Int): Stream[Int] = n #:: from(n+1)
  294.  
  295. val naturalNumbers = from()
  296. val multiplesOf4 = nats maps (_ * 4)
  297. // etc.
  298. ```
  299.  
  300. ### Usage #1 : Prime numbers via the *Sieve of Eratosthenes*
  301. ```scala
  302. def sieve(: Stream[Int]): Stream[Int}
  303. s.head #:: sieve(s.tail filter (_ % s.head != 0))
  304.  
  305. val primes = sieves(from(2))
  306. ```
  307.  
  308. ### Usage #2 : square roots
  309. ```scala
  310.  
  311. def srtStream(x: Double): Stream[Double] = {
  312.  
  313. def improve(guess: Double) = (guess + x / guess) / 2
  314. lazy val guesses: Stream[Double] = 1 #:: (guesses map improve)
  315. guesses
  316. }
  317.  
  318. def isGoodEnough(guess: Double, x: Double) =
  319. math.abs((guess * guess - x) / x) < 0.0001
  320.  
  321. sqrtStream(4) filter (isGoodEnough(_, 4))
  322. ```
  323.  
  324. ## lecture "Case study: Water pouring problem"
  325.  
  326. cf. "Design of computer programs" (more imperative solution in Python)
  327.  
  328. How to use:
  329. - a glass of 4 cl.
  330. - a glass of 9 cl.
  331. - a big jar
  332. to fill to mesure 6 cl ?
  333.  
  334. Our model:
  335. Glass: Int
  336. State: Vector[Int]
  337. Moves:
  338. Empty(glass)
  339. Fill(glass)
  340. Pour(from, to)
  341.  
  342. ```scala
  343. class Pouring(capacity: Vector[Int]) {
  344.  
  345. type State = Vector[Int]
  346. val initialState = capacity map (x => 0)
  347.  
  348. trait {
  349. def change(state: State): State
  350. }
  351. case class Empty(glass: Int) extends Move {
  352. def change(state: State) = state updated (glass, 0)
  353. }
  354. case class Fill(glass: Int) extends Move {
  355. def change(state: State) = state updated (glass, capacity(glass))
  356. }
  357. case class Pour(from: Int, to: Int) extends Move {
  358. def change(state: State) = {
  359. val amount = state(from) min (capacityt(to) - state(to))
  360. state updated (from, state(from) - amount) updated (to, state(to) + amount)
  361. }
  362. }
  363.  
  364. val glasses = 0 until capacity.length
  365.  
  366. val moves =
  367. (for (g <- glasses) yield Empty(g)) ++
  368. (for (g <- glasses) yield Fill(g)) ++
  369. (for (from <- glasses; to <- glasses if from != to) yield Pour(from, to)
  370.  
  371. }
  372.  
  373. class Path(history: List[Move], val endState: State) {
  374. def extend(move: Move) = new Path(move :: history, move change endState)
  375. override def toString = (history.reverse mkString " ") + "--> " + endState
  376. }
  377.  
  378. val initialPath = new Path(Nil, initialState)
  379.  
  380. def from(path: Set[Path], explored: Set[Path]): Stream[Set[Path]] =
  381. if (paths.isEmpty) Stream.empty
  382. else {
  383. val more = for {
  384. path <- paths
  385. next <- moves map path.extend
  386. } yield next
  387. if (!explored contains next.endState)
  388. paths #:: from(more)
  389. }
  390.  
  391. val pathSets = from(Set(initialPath), explored ++ (more map (_.endState)), Set(inialState)
  392. def solution(target: Int) Stream[Path] =
  393. for {
  394. pathSet <- pathSets
  395. path <- pathSet
  396. if (path.endState contains targer)
  397. } yield path
  398.  
  399.  
  400. object Test {}
  401. val problem = new Pouring(Vector(4, 7))
  402. problem.moves
  403.  
  404. problem.solutions(6)
  405. }
  406. ```
  407.  
  408. Guidelines:
  409. - name everything you can (do not use "single-letter variables like mathematicians")
  410. - put operations into natural scopes i.e. change method inside Move class)
  411. - keep degrees of freedom for future refinements
  412.  
  413.  
  414. # Week 3: Functions and State
  415.  
  416. ## lecture Functions and State
  417. Until now, we wrote pure functions with immutable data.
  418. => `side-effet free`
  419. But how to work with *mutable state*? When *time is important*?
  420.  
  421. Substitution model:
  422. programs can be evaluated by *rewriting* (function applications).
  423. All rewritings that terminate *lead to the same result* (cf. Church-Rosser theorem of lambda-calculus).
  424.  
  425. Stateful Objects:
  426. Changes over time => state
  427. An object has state if its behavior is influenced by its history.
  428. Ex : a bank transaction depends on the state of bank accounts.
  429.  
  430. State implementation:
  431. Via variables and assignments
  432. ```
  433. class BankAccount {
  434.  
  435. private var balance = 0
  436.  
  437. def deposit(amount: Int): Unit =
  438. if (amount > 0) balance = balance + amount
  439.  
  440. def withdraw(amount: Int): Int =
  441. if (0 < amount && amount <= balance) {
  442. balance = balance - amount
  443. balance
  444. } else throw new Error("insufficient funds")
  445.  
  446. val account = new BankAccount
  447. account deposit 50
  448. account withdraw 20 # OK
  449. account deposit 40 # Error, different result
  450. ```
  451.  
  452. ## lecture "Identity and change"
  453. When are objects the same?
  454.  
  455. On values, yes (cf. referential transparency:
  456. ```
  457. val a = E
  458. val b = E
  459. ```
  460.  
  461. But with variables and mutable state, no:
  462. ```
  463. val account1 = new BankAccount
  464. val account2 = new BankAccount
  465. ```
  466.  
  467. Being the same = `operational equivalence`.
  468. i.e. no possible (black box) test can distinguish between them.
  469. ```
  470. test(account1, account2)
  471. ```
  472.  
  473. The substitution model cannot be used with assignments (or it becomes very complicated).
  474.  
  475. ## lecture "loops"
  476.  
  477. Loops: main feature in imperative programming.
  478. In FP:
  479. - `while` loops are modeled with recursive functions. (tail recursive)
  480. - classical `for` loops cannot be modeled via higher-order function (because of nested variable)
  481. Scala has for-expressions like `for (i <- 1 until 3) ...` (cf. Collections#foreach)
  482.  
  483. ## lecture "Extended Example: Discrete Event Simulation"
  484. Use mutable variables to simulate changing quantities in real world.
  485. Also structure a system with layers, in particular with a Domain Specific Language.
  486.  
  487. Example: digital circuit simulator
  488. Use wires to combine base components that a have a reaction time (delay):
  489. - inverter
  490. - AND gate
  491. - OR gate
  492.  
  493. half-adder (HA)
  494.  
  495. ```
  496.  
  497. // components with side effects
  498. def inverter(input: Wire, output: Wire): Unit
  499. def andGate(a1: Wire, a2: Wire, output: Wire): Unit
  500. def orGate(a1: Wire, a2: Wire, output: Wire): Unit
  501.  
  502.  
  503. def halfAdder(a: Wire, b: Wire, s: Wire, c: Wire): Unit = {
  504. val d, e = new Wire // internal wires
  505. orGate(a, b, d)
  506. andGate(a, b, c)
  507. inverter(c, e)
  508. andGate(d, e, s)
  509. }
  510.  
  511. def fullAdder(a: Wire, b: Wire, cin: Wire, sum: Wire):, cout: Wire): Unit = {
  512. val s, c1, c2 = new Wire // internal wires
  513. halfAdder(b, cin, s, c1)
  514. halfAdder(a, s, sum, c2)
  515. orGate(c1, c2, cout)
  516. }
  517. ```
  518.  
  519. ## lecture "Discrete Event Simulation: API and Usage"
  520. Implementation of class Wire and its functions.
  521.  
  522. A discrete event simulator performs *actions* at a given *moment*.
  523.  
  524. An action is a function:
  525. ```
  526. type Action = () => Unit
  527. ```
  528.  
  529. Time is simulated.
  530.  
  531. Layers: user -> circuits (higher-level components) -> gates (wires & base components)-> (abstract) simulation
  532.  
  533. ```
  534. trait Simulation {
  535. def currentTime: Int = ???
  536. def afterDelay(delay: Int)(block: => Unit): Unit ???
  537. def run(): Unit = ???
  538.  
  539. class Wire {
  540.  
  541. private var sigVal = false; // current value
  542. private var actions: List[Action] = List()
  543.  
  544. def getSignal: Boolean = sigVal
  545.  
  546. def setSignal(s: Boolean): Unit =
  547. if (s != sigVal) {
  548. sigVal = s
  549. actions foreach (_())
  550. }
  551.  
  552. def addAction(a: Action): Unit = {
  553. actions = a :: actions
  554. a()
  555. }
  556. }
  557.  
  558. def inverter(input: Wire, output: Wire) : Unit = {
  559. def invertAction(): Unit = {
  560. val inputSig = input.getSignal
  561. afterDelay(InverterDelay) { output setSignal !inputSig }
  562. }
  563. input addAction invertAction
  564. }
  565.  
  566. def andGate(in1: Wire, in2: Wire, output: Wire) : Unit = {
  567. def andAction(): Unit = {
  568. val in1Sig = in1.getSignal
  569. val in2Sig = in2.getSignal
  570. afterDelay(AndGateDelay) { output setSignal (in1Sig && in2Sig) }
  571. }
  572. in1 addAction andAction
  573. in2 addAction andAction
  574. }
  575.  
  576. def orGate(in1: Wire, in2: Wire, output: Wire) : Unit = {
  577. def orAction(): Unit = {
  578. afterDelay(OrGateDelay) { output setSignal (in1.getSignal | in2.getSignal) }
  579. }
  580. in1 addAction orAction
  581. in2 addAction orAction
  582. }
  583. ```
  584.  
  585.  
  586. ## lecture "Discrete Event Simulation: implement and test"
  587.  
  588. Simulation trait has an *agenda* of actions to perform.
  589.  
  590. ```
  591. trait Simulation {
  592. type Action = () => Unit
  593.  
  594. case class Event(time: Int, action: Action) # case class => easy to pattern-match on
  595.  
  596. private type Agenda = List[Event]
  597. private var agenda: Agenda = List()
  598.  
  599. private var curtime = 0
  600. def currentTime: Int = curtime
  601.  
  602. def afterDelay(delay: Int)(block => Unit) {
  603. val item = Event(curentTime + delay, () => block)
  604. agenda = inster(agenda, item)
  605. }
  606. }
  607. ```
  608.  
  609. ## Summary:
  610.  
  611. State & assignments => more complicated (we lose referential transparency and substituion model)
  612. but programs are simpler and concise.
  613. => trade-off
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement