Uncategorized
Cienie zdrady: droga do nowego szczęścia
Katarzyna często wyjeżdżała w delegacje. Raz w miesiącu na dwa, trzy dni udawała się do głównego biura firmy w sąsiednim mieście. Jakub przyzwyczaił się do jej nieobecności i nie protestował. Pracowali w różnych firmach, spotykali się wieczorami, spędzali razem weekendy – choć nie zawsze. Jakub miał swoje hobby – myślistwo. Często wyjeżdżał z przyjaciółmi na łono natury. Katarzyna nie miała nic przeciwko, rozumiejąc, że mężczyzna potrzebuje przestrzeni dla siebie.
Ży# CSCI 1102 Computer Science 2
### Fall 2017
—
## Lecture Notes
### Week 4: More Functions and First-Class Values
#### Topics
1. Binary Trees
2. Tail Recursion
3. Processing Pairs and Lists of Pairs
—
## 1. Binary Trees
Here’s a type for binary trees very similar to the type for lists:
„`ocaml
type 'a tree =
| Empty
| Node of 'a * 'a tree * 'a tree
„`
Let’s construct a sample tree:
„`ocaml
let t = Node (4,
Node (2,
Node (1, Empty, Empty),
Node (3, Empty, Empty)),
Node (6,
Node (5, Empty, Empty),
Node (7, Empty, Empty)))
„`
For a more compact representation, we can define a few helper functions:
„`ocaml
let lf x = Node (x, Empty, Empty)
let nd (x, l, r) = Node (x, l, r)
„`
Using these:
„`ocaml
let t = nd (4,
nd (2,
lf 1,
lf 3),
nd (6,
lf 5,
lf 7))
„`
—
In OCaml, trees are persistent data structures — they can’t be changed, i.e., they are *immutable*. For example, suppose we have:
„`ocaml
let t = Node (2, lf 1, lf 3)
„`
and would like to make a new tree by replacing the empty left subtree of `t` with the leaf `lf 4`, i.e., the result should be:
„`ocaml
Node (2, lf 4, lf 3)
„`
We can do this as follows:
„`ocaml
let newT =
match t with
| Empty -> failwith „empty”
| Node (x, _, r) -> Node (x, lf 4, r)
„`
—
### Processing Trees
Let’s write a function to compute the size of a tree, i.e., its number of non-empty nodes.
„`ocaml
let rec size tree =
match tree with
| Empty -> 0
| Node (_, l, r) -> 1 + size l + size r
„`
**Exercise.** Write a function `height : 'a tree -> int` to compute the height of a binary tree. For the purposes of this problem, we’ll take the height of the empty tree to be 0 and the height of a non-empty tree to be the length of the longest path from the root to a leaf.
„`ocaml
let rec height tree =
match tree with
| Empty -> 0
| Node (_, l, r) -> 1 + max (height l) (height r)
„`
Let’s write a function to compute the sum of the nodes of an `int tree`:
„`ocaml
let rec sum tree =
match tree with
| Empty -> 0
| Node (x, l, r) -> x + sum l + sum r
„`
All three of these functions are examples of tree folds.
**Exercise.** [Not required]. Can you write a general-purpose fold function for binary trees analogous to `fold_right` for lists? What would its type be?
—
### The Binary Search Tree (BST) Property
A binary tree is a BST if for any non-empty subtree `Node (x, l, r)`, the values in `l` are all less than `x` and the values in `r` are all greater than `x`. Here’s an OCaml predicate to test whether a tree satisfies the BST property.
„`ocaml
let rec isBST tree =
match tree with
| Empty -> true
| Node (x, l, r) ->
( (isBST l) && (isBST r) &&
(treeMax l) < x && x < (treeMin r) )
```
This uses two helper functions:
```ocaml
let rec treeMax tree =
match tree with
| Empty -> min_int
| Node (x, _, Empty) -> x
| Node (x, _, r) -> treeMax r
let rec treeMin tree =
match tree with
| Empty -> max_int
| Node (x, Empty, _) -> x
| Node (x, l, _) -> treeMin l
„`
**Exercise (Required).** The code above works but is inefficient. Why? Can you correct the code? (Try to avoid computing the min and max twice.)
—
### Processing BSTs
Let’s write a lookup function for BSTs:
„`ocaml
let rec lookup x tree =
match tree with
| Empty -> false
| Node (y, l, r) ->
if x < y then lookup x l
else if x > y then lookup x r
else true
„`
—
## 2. Tail Recursion
Here’s the standard implementation of the factorial function:
„`ocaml
let rec fact n =
if n <= 1 then 1
else n * fact (n - 1)
```
Here's another version:
```ocaml
let fact n =
let rec helper n k =
if n <= 1 then k
else helper (n - 1) (k * n) in
helper n 1
```
This is called a *tail recursive* (or iterative) implementation. The difference between `fact` and `helper` is that, in the recursive case, `helper` applies *itself* tail recursively as the *very last thing it does* whereas `fact` has to perform a multiplication (by `n`) *after* the recursive call.
The iterative version uses an accumulating parameter `k` that keeps track of the multiplications performed so far.
Here's how it works:
```ocaml
fact 4
=> helper 4 1
=> helper 3 (4 * 1)
=> helper 2 (3 * (4 * 1))
=> helper 1 (2 * (3 * (4 * 1)))
=> 2 * (3 * (4 * 1))
=> 24
„`
The key point is that no pending computations are left to perform when the base case is reached — the accumulated value is simply returned. In contrast, a non tail-recursive function would have have to perform a series of pending multiplications on the way back up, so to speak.
The advantage here is that the OCaml compiler can implement tail recursive calls very efficiently by simply reusing the same stack frame for each call.
—
### Converting Non Tail-Recursive Functions to Tail Recursive
Here’s a tail-recursive version of list length:
„`ocaml
let length l =
let rec helper l k =
match l with
| [] -> k
| _ :: t -> helper t (k + 1) in
helper l 0
„`
Let’s try converting the `sum` function:
„`ocaml
let rec sum l =
match l with
| [] -> 0
| h :: t -> h + sum t
let sum l =
let rec helper l k =
match l with
| [] -> k
| h :: t -> helper t (h + k) in
helper l 0
„`
—
Here’s the standard implementation of the `map` function:
„`ocaml
let rec map f l =
match l with
| [] -> []
| h :: t -> (f h) :: map f t
„`
Here is a tail-recursive version:
„`ocaml
let map f l =
let rec helper l k =
match l with
| [] -> List.rev k
| h :: t -> helper t ( (f h) :: k ) in
helper l []
„`
This version, uses the accumulating parameter `k` as an accumulator but it builds up the result in reverse order. The call to `List.rev` reverses the accumulated list in the base case.
**Exercise.** Write a tail-recursive version of `append` and `factorial`.
—
### When is Tail Recursion Useful?
It’s useful when (1) the function in question operates over large data structures (lists, trees, etc.) *and* (2) it is likely to be called repeatedly in a larger computation (so that the efficiency gains are meaningful).
—
## 3. Processing Pairs and Lists of Pairs
### Processing Pairs
Tuples allow for aggregating data more flexibly than lists. The elements of a tuple can be of any type and needn’t be homogeneous (unlike lists). For example:
„`ocaml
let t1 = (true, false)
let t2 = (true,Dziś Katarzyna i Siergiej świętują dziesięć lat małżeństwa, otoczeni rodziną i przyjaciółmi, a ich dom pełen jest śmiechu i miłości.
-
Ciekawostki3 lata agoPrzyszła synowa została u nas na noc. Rano odwiedziła nas moja siostrzenica i okazało się, że ona i narzeczona syna się znają. A następnego dnia przyjechała jego przyszła teściowa razem z córką i urządziły straszną awanturę. Z jakiegoś powodu moja siostrzenica powiedziała synowej, że ja i mój mąż nie będziemy im pomagać po ślubie i jeszcze że chcemy sprzedać samochód naszego syna. W rezultacie ślub się nie odbył
-
Ciekawostki4 lata agoBrat przybiegł wcześnie rano, jak tylko dowiedział się, co zrobili rodzice
-
Rodzina5 lat agoObaj moi synowie są żonaci. Moje synowe diametralnie się od siebie różnią – jedna siedzi z telefonem na kanapie, a druga szykuje jedzenie dla wszystkich. Ilona mieszka z nami i nie chce jej się nic robić. Pewnego dnia nie mogłam się powstrzymać i ją zawstydziłam, mówiąc, że u niej zawsze jest brudno. Teraz nikt w domu ze mną nie rozmawia
-
Historie4 lata ago„To u was można brać prysznic dłużej niż 30 minut?” – usłyszałam od koleżanki, która mieszka w Niemczech
