10
1 Assignment 4 - Solution Question 1 // The key point to take into account is that the values can be obtained from the promises // in any order but we still want to resolve an array of values where all the // values vali appear in position i. function all(promises : Array<Promise<any>>) : Promise<Array<any>> { return new Promise((resolve, reject) => { let values = new Array(promises.length), pending = promises.length; if (promises.length === 0) resolve(values); // The forEach function argument receives an optional arg i // which is the position of the element in the array promises.forEach((promise: Promise<any>, i: number) => { // Trigger the internal promise i promise.then(value => { values[i] = value; pending -= 1; if (pending === 0) resolve(values); }) .catch(err => { reject(err); }); }); }); }

Assignment 4 - Solution - BGUppl172/wiki.files/ex4-solution.pdf · 1 Assignment 4 - Solution Question 1 // The key point to take into account is that the values can be obtained from

Embed Size (px)

Citation preview

1

Assignment 4 - Solution

Question 1

// The key point to take into account is that the values can be obtained from the promises

// in any order but we still want to resolve an array of values where all the

// values vali appear in position i.

function all(promises : Array<Promise<any>>) : Promise<Array<any>> {

return new Promise((resolve, reject) => {

let values = new Array(promises.length),

pending = promises.length;

if (promises.length === 0)

resolve(values);

// The forEach function argument receives an optional arg i

// which is the position of the element in the array

promises.forEach((promise: Promise<any>, i: number) => {

// Trigger the internal promise i

promise.then(value => {

values[i] = value;

pending -= 1;

if (pending === 0)

resolve(values);

})

.catch(err => { reject(err); });

});

});

}

2

Question 2

A1

We say that two given lazy lists / generators are equivalent if their ith application yields the same value

for any i > 0.

A2

In the first chapter (https://www.cs.bgu.ac.il/~ppl172/wiki.files/class/book/ppl17_chapter1.pdf, p. 24),

we proved that f1 and g1 functions are equivalent:

f1 = compose(filter(isEven),map(cube)) g1 = compose(map(cube), filter(isEven)) Since∀i ∈ N, isEven(i) = isEven(square(i)), the proof also holds for the functions f2,g2

f2 = compose(filter(isEven),map(square)) g2 = compose(map(square), filter(isEven))

It is sufficient to show that for each i>0, the i-th application of evenSquares1 yields the i-th item in the list provided by f2, and that for each i>0, the i-th application of evenSquares2 returns the i-th item in the list provided by g2. i.e, it is enough to show that:

• The i-th application of mapGen(square) yields the i-th item in the list provided by map(square) for the natural numbers.

• The i-th application of mapGen(square) yields the i-th item in the list provided by map(square) for the even numbers.

• The i-th application of filterGen(isEven) yields the i-th item in the list provided by filter(isEven) for the natural numbers.

• The i-th application of filterGen(isEven) yields the i-th item in the list provided by filter(isEven) for the squared numbers.

The above four claims are established by induction on the number of generator applications. A3 We show that both fibs1 and fibs2 yield in the i-th application the i-th Fibonacci number: Proposition 1: In the n-th application of fibs1, the parameters a and b are the n-th and (n+1)-th Fibonacci numbers. Base i=1: fibs1 is instantiated with a = 0 = fib1, b = 1 = fib2

Induction step: if the proposition holds for i=n, in the n-th application a = fibn and b= fibn+1. According to the code of fibs1, the n+1 application will yield b [(cons b (…))], which is, according to the induction assumption, fibn+1

Proposition 2: In the i-th application of fibs2 the number yield is the i-th Fibonacci number. Base i=1, i=2: in the first application fibs2 yields 0 = fib1. in the second application fibs2 yields 1 = fib2. Induction step: the (n+1)-th application of fibs2 yields the sum of the (n-1)-th and (n-2)-th applications, which are according to the induction assumption fibn-1 and fibn-2, which is by definition fibn

3

B

function* integersFrom(n) {

for (;; n++) {

yield n;

}

}

function* take(numberToTake, generator) {

for (let i = 0; i < numberToTake; ++i) {

const {done, value} = generator.next();

if (done) return;

else yield value;

}

}

function* filterGen(generator, filterFunc) {

for (let x of generator) {

if (filterFunc(x)) {

yield x;

}

}

}

function first(generator) {

return generator.next().value;

}

function* sieve(generator) {

// At each invocation of the sieve generator, a new prime is returned

// and the sieve is wrapped in another filter.

for (let sieve = generator, n = first(generator); n = first(sieve);) {

sieve = filterGen(sieve, x=> (x % n) !== 0);

yield n;

}

}

for (n of take(10, sieve(integersFrom(2)))) {

console.log(n);

}

4

Question 3 A1

1: (define append$

2: (lambda (x y cont)

3: (if (empty? x)

4: (cont y)

5: (append$ (cdr x) y

6: (lambda (append-res) ; cont2

7: (cont (cons (car x) append-res)))))))

A2 Proposition: For any lists lst1 and lst2 and a continuation procedure cont, (append$ lst1 lst2 cont) = (cont

(append lst1 lst2)).

Proof: By induction on the length of lst1

Base: For the case of a lst1 of length 0 [the empty list], the value of (append lst1 lst2) is lst2, and the

value of (append$ lst1 lst2 cont) is (cont lst2), which implies (append$ lst1 lst2 cont) = (cont (append lst1

lst2)).

Induction step: We assume the proposition holds for lst1 of length n, and show the proposition holds for

lst1 of a length n+1.

(a) According to the code, the value of (append lst1 lst2) is (cons (car lst1) (append (cdr lst1) lst2)).

(b) According to the code ,the value of (append$ lst1 lst2 cont) is (append$ (cdr lst1) lst2 cont2), where

cont2 is the continuation procedure defined in lines 6-7.

Since the first operand of (append$ (cdr lst1) lst2 cont2) is a list of length n, according to the induction

assumption: (cont2 (append (cdr lst1) lst2)) = (append$ (cdr lst1) lst2 cont2).

(cont (cons (car lst1) (append (cdr lst1) lst2))) = (append$ (cdr lst1) lst2 cont2) ;;; code of cont 2

(cont (append lst1 lst2)) = (append$ (cdr lst1) lst2 cont2) ;;; (a)

(cont (append lst1 lst2)) = (append$ lst1 lst2 cont) ;;; (b)

B

(define leaf? (lambda (x) (not (list? x))))

; Type: [Tree * Tree * [Tree ->T1] * [Pair->T2] -> T1 U T2

(define equal-trees$

(lambda (tree1 tree2 succ fail)

(cond

((and (empty? tree1) (empty? tree2))

(succ '()))

((and (empty? tree1) (not (empty? tree2)))

(fail (cons tree1 tree2))

; Acceptable alternative 1: (fail (list tree1 tree2))

; Acceptable alternative 2: (if (leaf? tree2) (fail(cons tree1 tree2)) (fail (cons tree1 (car tree2))))

; Acceptable alternative 3: (if (leaf? tree2) (fail(list tree1 tree2)) (fail (list tree1 (car tree2))))

)

((and (not (empty? tree1)) (empty? tree2))

5

(fail (cons tree1 tree2))

; Acceptable alternative 1: (fail (list tree1 tree2))

; Acceptable alternative 2: (if (leaf? tree1) (fail (cons tree1 tree2)) (fail (cons (car tree1) tree2)))

; Acceptable alternative 3: (if (leaf? tree1) (fail (list tree1 tree2)) (fail (list (car tree1) tree2)))

)

((and (leaf? tree1) (leaf? tree2))

(succ (cons tree1 tree2)))

((and (leaf? tree1) (not (leaf? tree2)))

(fail (cons tree1 tree2)))

((and (not (leaf? tree1)) (leaf? tree2))

(fail (cons tree1 tree2)))

(else (equal-trees$ (car tree1) (car tree2)

(lambda (suc-car)

(equal-trees$ (cdr tree1) (cdr tree2)

(lambda (suc-cdr)

(succ (cons suc-car suc-cdr)))

fail))

fail)))))

6

Question 4

A

append([], Xs, Xs).

append([X|Xs], Y, [X|Zs] ) :- append(Xs, Y, Zs).

member(X, [X|_]).

member(X, [_|Ys]) :- member(X, Ys).

not_member(_, []).

not_member(X, [Y|Ys]):- X \= Y, not_member(X,Ys).

noDups(L1,L2):- list2set(L1,[],L2).

list2set([X|Xs],Acc,Ys):-not_member(X,Acc),append(Acc,[X],Z),list2set(Xs,Z,Ys).

list2set([X|Xs],Acc,Ys):-member(X,Acc),list2set(Xs,Acc,Ys).

list2set([],Acc,Acc).

B

1. unify[p(v(v(d(1),M,ntuf3),X)), p(v(d(B),v(B,ntuf3),KtM))]

- Same predicates (p), same arity (1)

-> equations = { p(v(v(d(1),M,ntuf3),X)) = p(v(d(B),v(B,ntuf3),KtM))}

- Compound terms, Same predicate (p), same arity (1)

-> split equation

-> equations = { v(v(d(1),M,ntuf3),X) = v(d(B),v(B,ntuf3),KtM)}

- Compound terms, Same predicate (v), Different arities (2,3)

-> Failure

2. unify[p(v(v(d(1),M,ntuf3),X)),p(v(d(B),v(B,ntuf3),ntuf3))]

- Same predicates (p), same arity (1)

-> equations = { p(v(v(d(1),M,ntuf3),X)) = p(v(d(B),v(B,ntuf3),ntuf3))}

- Compound terms, Same predicate (p), same arity (1)

-> split equation

-> equations = { v(v(d(1),M,ntuf3),X) = v(d(B),v(B,ntuf3),ntuf3)}

- Compound terms, Same predicate (v), Different arities (2,3)

-> Failure

7

3. unify[p(v(v(d(M),M,ntuf3),X)), p(v(d(B),v(B,ntuf3),KtM))]

- Same predicates (p), same arity (1)

-> equations = { p(v(v(d(M),M,ntuf3),X)) = p(v(d(B),v(B,ntuf3),KtM))}

- Compound terms, Same predicate (p), same arity (1)

-> split equation

-> equations = { v(v(d(M),M,ntuf3),X) = v(d(B),v(B,ntuf3),KtM)}

- Compound terms, Same predicate (v), Different arities (2,3)

-> Failure

4. unify[p(v(v(d(1),M,p),X)),p(v(d(B),v(B,ntuf3),KtM))]

- Same predicates (p), same arity (1)

-> equations = { p(v(v(d(1),M,p),X)) = p(v(d(B),v(B,ntuf3),KtM))}

- Compound terms, Same predicate (p), same arity (1)

-> split equation

-> equations = { v(v(d(1),M,p),X) = v(d(B),v(B,ntuf3),KtM)}

- Compound terms, Same predicate (v), Different arities (2,3)

-> Failure

8

C1 unary_plus([1|X], [1,1|Y], [1,1,1|X])

9

10

C2

Is this a success or a failure proof tree?

See definitions from the material (p.352):

Finite success proof tree: A finite tree with a successful path.

(Finite) Failure proof tree: A finite tree with no successful path.

Infinite success proof tree: An infinite tree with a successful path.

Infinite failure proof tree: An infinite tree with no successful path. Dangerous to explore.

This tree is an infinite success proof tree.

C3 Is this tree finite or infinite?

This tree has an infinite number of success nodes and an infinite number of failure nodes.

The query corresponds to the equation:

unary_plus([1|X], [1,1|Y], [1,1,1|X])

X+1 + Y+2 = X+3

which results in:

X+Y+3 = X+3

It has an infinite number of success answers:

{X=0, Y=0}

{X=1, Y=0}

{X=2, Y=0}

...

Which are encoded as unary numbers as:

X=[], Y=[]

X=[1], Y=[]

X=[1,1], Y=[]

...