Java Polymorphism and Lambda Calculus, Exams of Programming Languages

The concept of polymorphism in java and lambda calculus with examples. It covers topics such as type erasure, subtyping, and beta-reduction. The document also includes exercises for practicing these concepts.

Typology: Exams

Pre 2010

Uploaded on 07/30/2009

koofers-user-gqu-2
koofers-user-gqu-2 🇺🇸

10 documents

1 / 11

Toggle sidebar

This page cannot be seen from the preview

Don't miss anything!

bg1
CMSC330 Spring 2009 Practice Problems 6 Solutions
1. Programming languages
a. Describe the difference between ad-hoc and parametric polymorphism.
Ad hoc polymorphism applies to code supporting a finite range of types
whose combinations must be specified, parametric polymorphism applies
to code written without mention to type that can transparently support
an arbitrary number of types.
b. Describe the difference between starvation and deadlock.
Deadlocked threads are halted waiting for each other’s locks, whereas
starving threads are waiting for locks from other (non-starving) threads.
c. Describe how functional programming may be used to simulate OOP.
An object may be simulated as a tuple, where each element of the tuple is
a closures representing a method for the object.
d. Describe the difference between HTML and XML.
HTML tags are predefined and presentation-oriented, whereas XML tags
are user defined and are intended for describing data and metadata.
e. Describe the difference between query languages and programming languages.
Query languages are designed to make requests to a database or
information system, whereas programming languages are designed to
express computations that can be performed by a machine.
2. Polymorphism
Consider the following Java classes:
class A { public void a( ) { … } }
class B extends A { public void b( ) { … } }
class C extends B { public void c( ) { … }}
Explain why the following code is or is not legal
a. int count(Set<A> s) { … } … count(new TreeSet<A>( ));
Legal. Actual parameter type (Set<A>) matches formal parameter type
(Set<A>)
b. int count(Set<A> s) { … } … count(new TreeSet<B>( ));
Illegal. Actual parameter type (Set<B>) is not a subclass of formal
parameter type (Set<A>), even though B is a subclass of A.
c. int count(Set s) { … } … count(new TreeSet<A>( ));
Legal. Type erasure will cause formal parameter type (TreeSet<A>) to
become TreeSet, which matches actual parameter type (Set).
d. int count(Set<?> s) { … } … count(new TreeSet<A>( ));
Legal. Actual parameter type (Set<A>) matches formal parameter type
(Set<?>), since ? matches A.
e. int count(Set<? extends A> s) { … } … count(new TreeSet<B>());
Legal. Actual parameter type (Set<B>) matches formal parameter type
(Set<? extends A>), since “? extends A” can match A and its subclasses B
& C (classes that extend A, including A)
pf3
pf4
pf5
pf8
pf9
pfa

Partial preview of the text

Download Java Polymorphism and Lambda Calculus and more Exams Programming Languages in PDF only on Docsity!

CMSC330 Spring 2009 Practice Problems 6 Solutions

  1. Programming languages a. Describe the difference between ad-hoc and parametric polymorphism. Ad hoc polymorphism applies to code supporting a finite range of types whose combinations must be specified, parametric polymorphism applies to code written without mention to type that can transparently support an arbitrary number of types. b. Describe the difference between starvation and deadlock. Deadlocked threads are halted waiting for each other’s locks, whereas starving threads are waiting for locks from other (non-starving) threads. c. Describe how functional programming may be used to simulate OOP. An object may be simulated as a tuple, where each element of the tuple is a closures representing a method for the object. d. Describe the difference between HTML and XML. HTML tags are predefined and presentation-oriented, whereas XML tags are user defined and are intended for describing data and metadata. e. Describe the difference between query languages and programming languages. Query languages are designed to make requests to a database or information system, whereas programming languages are designed to express computations that can be performed by a machine.
  2. Polymorphism Consider the following Java classes: class A { public void a( ) { … } } class B extends A { public void b( ) { … } } class C extends B { public void c( ) { … }} Explain why the following code is or is not legal a. int count(Set s) { … } … count(new TreeSet( )); Legal. Actual parameter type (Set) matches formal parameter type (Set) b. int count(Set s) { … } … count(new TreeSet( )); Illegal. Actual parameter type (Set) is not a subclass of formal parameter type (Set), even though B is a subclass of A. c. int count(Set s) { … } … count(new TreeSet( )); Legal. Type erasure will cause formal parameter type (TreeSet) to become TreeSet, which matches actual parameter type (Set). d. int count(Set s) { … } … count(new TreeSet( )); Legal. Actual parameter type (Set) matches formal parameter type (Set), since? matches A. e. int count(Set s) { … } … count(new TreeSet()); Legal. Actual parameter type (Set) matches formal parameter type (Set), since “? extends A” can match A and its subclasses B & C (classes that extend A, including A)

f. int count(Set s) { … } … count(new TreeSet()); Illegal. Actual parameter type (Set) does not match formal parameter type (Set), since “? extends B” can match only B and its subclass C (classes that extend B, including B) g. int count(Set s) { for (A x : s) x.a( ); … } Legal. The actual parameter type (Set) indicates s contains elements of class B or its subclasses. So any element of s may be treated as an object of class B or its subclasses (e.g., C). The for loop treats elements of s as objects of class A, which is a superclass of B, and thus is legal (can use subclass in place of superclass). h. int count(Set s) { for (C x : s) x.c( ); … } Illegal. The actual parameter type (Set) indicates s contains elements of class B or its subclasses. So any element of s may be treated as an object of class B or its subclasses (e.g., C). The for loop treats elements of s as objects of class C, and is illegal since elements of s may be objects of class B (cannot use superclass in place of subclass). i. int count(Set s) { for (A x : s) x.a( ); … } Illegal. The actual parameter type (Set) indicates s contains elements of class B or its superclasses. So any element of s may be treated as an object of class B or its superclasses (e.g., A, Object). The for loop treats elements of s as objects of class A, and is illegal since elements of s may be objects of class Object (cannot use superclass in place of subclass). j. int count(Set s) { for (C x : s) x.c( ); … } Illegal. The actual parameter type (Set) indicates s contains elements of class B or its superclasses. So any element of s may be treated as an object of class B or its superclasses (e.g., A, Object). The for loop treats elements of s as objects of class C, which is not included and thus illegal.

b. Implement MyBarrier using Ruby monitors.

require "monitor.rb"

class MyBarrier def initialize n @num = n @current = 0 @myLock = Monitor.new @myCondition = @myLock.new_cond end

def enter @myLock.synchronize { @current = @current + 1 if @current == @num then @myCondition.broadcast else @myCondition.wait_while { @current < @num } end } end

def reset @myLock.synchronize { @current = 0 } end end

c. Write a Ruby program that creates a barrier for 2 threads, then creates 2 threads that each print out “hello”, enters the barrier, then prints out “goodbye”.

bar = MyBarrier.new 2

t1 = Thread.new { puts "hello" bar.enter puts "goodbye" }

t2 = Thread.new { puts "hello" bar.enter puts "goodbye" }

  1. Lambda calculus Make all parentheses explicit in the following λ-expressions a. λx.xz λy.xy  (λx.((x z) (λy.(x y)))) b. (λx.xz) λy.w λw.wyzx  ((λx.(x z)) (λy.(w (λw.((((w y) z) x)))))) c. λx.xy λx.yx  (λx.((x y) (λx.(y x))))

Find all free (unbound) variables in the following λ-expressions d. λx.x z λy.x y  (λx.((x z) (λy.(x y)))) e. (λx. x z) λy. w λw. w y z x  ((λx.(x z)) (λy.(w (λw.((((w y) z) x)))))) f. λx. x y λx. y x  (λx.((x y) (λx.(y x))))

Apply β-reduction to the following λ-expressions as much as possible g. (λz.z) (λy.y y) (λx.x a) // β-reduction = body[sym/replacement] (λz.z) (λy.y y) (λx.x a)  // z[z/(λy.y y)] replace z with λy.y y (λy.y y) (λx.x a)  // y y[y/(λx.x a)] replace y with λx.x a (λx.x a) (λx.x a)  // x a[x/(λx.x a)] replace x with λx.x a (λx.x a) a  a a // x a[x/a] replace x with a h. (λz.z) (λz.z z) (λz.z y) (λz.z) (λz.z z) (λz.z y)  // β-reduction: replace z with λz.z z (λz.z z) (λz.z y)  // β-reduction: replace z with λz.z y (λz.z y) (λz.z y)  // β-reduction: replace z with λz.z y (λz.z y) y  y y // β-reduction: replace z with y i. (λx.λy.x y y) (λa.a) b (λx.λy.x y y) (λa.a) b  // β-reduction: replace x with λa.a (λy.(λa.a) y y) b (^)  // β-reduction: replace y with b (λa.a) b b  b b // β-reduction: replace a with b j. (λx.λy.x y y) (λy.y) y (λx.λy.x y y) (λy.y) y  // α-conversion: rename y to a (λx.λa.x a a) (λy.y) y  // β-reduction: replacing x with λy.y (λa.(λy.y) a a) y  // β-reduction: replacing a with y (λy.y) y y  y y // β-reduction: replacing y with y k. (λx.x x) (λy.y x) z (λx.x x) (λy.y x) z  // β-reduction: replacing x with λy.y x (λy.y x) (λy.y x) z  // β-reduction: replacing y with λy.y x (λy.y x) x z  // β-reduction: replacing y with x x x z l. (λx. (λy. (x y)) y) z (λx. (λy. (x y)) y) z  // α-conversion: rename y to a (λx. (λa. (x a)) y) z  // β-reduction: replacing x with z (λa. (z a)) y  // β-reduction: replacing a with y z y m. ((λx.x x) (λy.y)) (λy.y) ((λx.x x) (λy.y)) (λy.y)  // β-reduction: replacing x with λy.y ((λy.y) (λy.y)) (λy.y)  // β-reduction: replacing y with λy.y (λy.y) (λy.y)  // β-reduction: replacing y with λy.y λy.y

= λx. λy. ((x true) y) false true // β-reduction: x → false = λy. ((false true) y) true // β-reduction: y → true = (false true) true // replace 1st^ false w/ encoding = ((λx.λy.y) false) true // β-reduction: x → false = (λy.y) true // β-reduction: y → true = true // or false true = true c. if false then x else y = y Given: if a then b else c = a b c true = λx.λy.x false = λx.λy.y Proof: if false then x else y // replacing if… w/ encoding = false x y // replacing false w/ encoding = (λx.λy.y) x y // β-reduction: x → x = (λy.y) y // β-reduction: y → y = y // if false then x else y = y d. succ 2 = 3 Given: 2 = λf.λy.f (f y) 3 = λf.λy.f (f (f y)) succ = λz.λf.λy.f (z f y) Proof: succ 2 // replacing succ w/ encoding = (λz.λf.λy.f (z f y)) 2 // β-reduction: z → 2 = λf.λy.f (2 f y) // expanding 2 w/ encoding = λf.λy.f ((λf.λy.f (f y)) f y) // β-reduction: 1st^ f → f = λf.λy.f ((λy.f (f y)) y) // β-reduction: 1st^ y → y = λf.λy.f (f (f y)) // apply encoding for 3 = 3 // succ 2 = 3

e. (* 1 3) = 3 Given: 1 = λf.λy.f y 3 = λf.λy.f (f (f y)) M * N = λx.(M (N x)) Proof: (* 1 3) // replacing * w/ encoding = λx.(1 (3 x)) // replacing 3 w/ encoding = λx.(1 (λf.λy.f (f (f y)) x)) // β-reduction: 1st^ f → x = λx.(1 (λy.x (x (x y)))) // replacing 1 w/ encoding = λx.((λf.λy.f y) (λy.x (x (x y)))) // β-reduction: 1st^ f w/ λy.x (x (x y)) = λx.(λy.(λy.x (x (x y)))) y // β-reduction: 1st^ y → y = λx.λy.x (x (x y)) // α-conversion: replace x with f = λf.λy.f (f (f y)) // apply encoding for 3 = 3

f. (+ 2 1) = 3 Given: 1 = λf.λy.f y 2 = λf.λy.f (f y) 3 = λf.λy.f (f (f y)) M + N = λx.λy.(M x)((N x) y) Proof: (+ 2 1) // replacing + w/ encoding = λx.λy.(2 x)((1 x) y) // replacing 2 w/ encoding = λx.λy.((λf.λy.f (f y)) x)((1 x) y) // β-reduction: 1st^ f → x = λx.λy.(λy.x (x y))((1 x) y) // replacing 1 w/ encoding = λx.λy.(λy.x (x y))(((λf.λy.f y) x) y) // β-reduction: 1st^ f → x = λx.λy.(λy.x (x y))((λy.x y) y) // β-reduction: 3rd^ y → y = λx.λy.(λy.x (x y))(x y) // β-reduction: 2nd^ y → x y = λx.λy.x (x (x y)) // α-conversion: replace x with f = λf.λy.f (f (f y)) // apply encoding for 3 = 3

g. (Y fact) 2 = 2 // you do not need to expand any operators except fact & Y Given: Y = λf.(λx.f (x x)) (λx.f (x x)) fact = λf. λn.if n = 0 then 1 else n * (f (n-1)) Proof: (Y fact) 2 // replacing Y w/ encoding = (λf.(λx.f (x x)) (λx.f (x x)) fact) 2 // β-reduction: 1st^ f → fact = (λx.fact (x x)) (λx.fact (x x)) 2 // β-reduction: 1st^ x → λx.fact (x x) = (fact ((λx.fact (x x)) (λx.fact (x x)))) 2 // apply encoding for (Y fact) // ((λx.fact (x x)) (λx.fact (x x))) → (Y fact) // we know this is the encoding for (Y fact) from 3rd^ line of proof = (fact (Y fact)) 2 // apply encoding for fact = (λf. λn.if n = 0 then 1 else n * (f (n-1)) (Y fact) 2 // β-reduction: 1st^ f → (Y fact) = (λn.if n = 0 then 1 else n * ((Y fact) (n-1))) 2// β-reduction: n → 2 = if 2=0 then 1 else 2 * ((Y fact) (2-1)) // apply if = 2 * ((Y fact) 1) // showed in class (Y fact) 1 = 1 = 2 * 1 // apply * = 2

  1. Markup languages a. Creating your own XML tags, write an XML document that organizes the following information: 1-hour test on Spanish Monday in Jiménez worth 15%. 1- hour test on Computers Tuesday in CSIC worth 10%. 30-minute test on Computers Friday in AVW worth 5%.

1 hour Spanish Monday Jiménez 15%

1 hour Computers Tuesday CSIC 10%

30 minute Computers Friday AVW 5%

or

1 …

1 …

30 …

  1. Garbage collection Consider the following Java code. Object a, b, c; public foo( ) { a = new Object( ); // object 1 b = new Object( ); // object 2 c = new Object( ); // object 3 a = b; b = c; c = a; } a. What object(s) are garbage when foo( ) returns? Explain why.

Object 1 is garbage there are no longer any references to it within the program. After foo( ) returns, a → object 2, b → object 3, c → object 2.

b. Describe the difference between mark-and-sweep & stop-and-copy.

Mark-and-sweep stops the program to determine what objects are still reachable. Stop-and-copy in addition will move reachable objects to new locations.