Starting from:

$24.99

CS2030S Lab 6: Lazy Solution


Prerequisite
• Caught up to Unit 32 of Lecture Notes
• Completed Lab 5
Files
The following functional interfaces are already provided:
• cs2Ø39s.fp.Action
• cs2B39s. fp.lmmutator
• cs2Ø39s.fp.Constant
• cs2Ø39s.fp.Combiner
• This is a new functional interface to combine two values into one.
• If Immutator takes in only one value, Combiner takes in two values.
Additionally, the following interfaces are already provided as well:
• cs2B3Øs. fp.Actionab1e
• cs2Ø39s. fp.lmmutatorable
Copy your implementation of Actually over before you get started with Lab 6. A skeleton for Lazy<T> and Memo<T> are provided for your. Additionally, you are given the simple and non-lazy implementation of Boolean expression:
• Cond . java : an interface abstracting a boolean condition that can be evaluated
• Bool. java : a boolean value
• And . java : a conjunction Or . java : a disjunction
• Not. java : a negation
The files Test 1 . java , Test2 . java , etc., as well as CS2Ø3ûSTest . java , are provided for testing. You can edit them to add your test cases, but they will not be submitted.
Being Lazy and Smarter
Programming languages such as Scala support lazy values, where the expression that produces a lazy value is not evaluated until the value is needed. Lazy value is useful for cases where producing the value is expensive, but the value might not eventually be used. Java, however, does not provide a similar abstraction. So, you are going to build one.
This task is divided into several stages. You are highly encouraged to read through all the stages to see how the different levels are related.
You are required to design a Lazy and Memo classes as part of the cs2û3es . fp package with one field. You are not allowed to add additional fields to Lazy .
1 public class Lazy<T> / * implements Immutatorab1e<T> (for later) * / {
2 private Constant<? extends T > init ;
3
4
public class Memo<T> extends Lazy<T> {
2 private value;
3
4
The Basics of Being Lazy
The idea of being lazy is that we do not compute unless we really really really need to. When do we need to compute the value? Simple, that is when we try to get the value.
Define a generic Lazy<T> class to encapsulate a value with the following operations such that for each derive the most flexible type:
• protected constructor protected . . . > c) that takes in a constant that produces the value when needed.
• static from(T v) method that instantiate the Lazy object with the given value using the protected constructor above.
• static . . . > c) method that takes in a constant that produces the value when needed and instantiate the Lazy object.
• get() method that is called when the value is needed. Compute the value and return.
• toString() : returns the string representation of the value.
j shell> import cs2Ø3Øs.fp . Constant
2
3 j shell> import cs2Ø3ûs.fp.Lazy
4 j shell> Lazy<lnteger> mod 1 - Lazy. from(2û3Ø)
5 j shell> mod 1 .get( )
6
7 2939
8 j shell> Lazy<String> mod2 Lazy. from( () 'I cs2e3es I ' )
9
19
1 1 j shell>
mod2 . get()
'I cs293es I '
12
13 j shell>
Lazy<String> hello Lazy. System . out . print In( "world !
14
15 >
return "hello'
16
17
18 j shell> world !
hello
" hello'
19 j shell> hello . get( )
29
21 world !
'I
'I hello
22 j shell> hello .get( ) // note "world ! is printed again
23 world !
24 'I hello '
You can test your code by running the Test 1 . java provided. The following should compile without errors or warnings. Make sure your code follows the CS2030S Java style and can generate the documentation without error.
$ javac cs2û39s/fp/*java
2 $ javac -Xlint : rawtypes Test 1 . java
3 $ java Test 1
4 $ java -jar Ncs2Ø3es/bin/checksty1e.jar -c -acs2Ø3es/bin/cs2Ø3e_checks.xm1 5 Lazy. java
$ javadoc -quiet -private -d docs cs2Ø3Ês/fp/Lazy.java
Smarter Lazy
The smarter idea of being lazy is that if we have computed the value before (i.e., called get( ) ) then we do not compute the value again. This is called memoization (the word comes from memo and not a typo from memorization). Since we already have an
, when we try perform a computation and the current value might still be uninitialised we treat this like a failure. In order to prevent this failure, we first produce the value using a Constant to initialise the value. Now, this is no longer a failure but a success!
Take note of the following constraints:
• Avoid using the Actually: : unwrap method and avoid access the classes
Actually . Success<T> or Actually . Failure directly.
• Since Actually has internalized try-catch (which kind of mimics if-else ) checks for whether the value is there or not, you must not use any form of conditional statements and/or try-catch to compare if value has been initialised or not.
• You are not allowed to use any raw types.
• You don't need any @SuppressWarnings for this lab, but if you do, it must be used responsibly.
Define a generic Memo<T> class to encapsulate a value with the following operations such that for each derive the most flexible type:
• you should not have public constructor.
• static from(T v) method that initializes the Memo object with the given value. In this case, the Memo is already initialised (i.e., already computed).
• static from(Constant< . . > c) method that takes in a constant that produces the value when needed. In this case, the Memo is uninitialised.
• get() method that is called when the value is needed. If the value is already available return that value; otherwise, compute the value and return it. The computation should only be done once for the same value.
• toString() : returns " ? " if the value is not yet available; returns the string representation of the value otherwise.
Note that for our class to be immutable and to make the memoization of the value transparent, toString should call get() and should never return "?" . We break the rules of immutability and encapsulation here, just so that it is easier to debug and test the laziness of your implementation.
jshell> import cs2Ø39s.fp.Constant
2 jshell> import cs293Ês.fp.Memo
3
4 jshell> Memo<lnteger> mod 1 - Memo. from(2û3Ø)
5 jshell> mod 1
6 mod 1 2839

7 j shell> mod 1 .get( )
8 2939
9
19 j shell> Memo<String> mod2 Memo . from( ( ) 'I cs2oes" )
11 j shell> mod2
12 mod2
13 j shell> mod2 . get()
14
15 'I cs2e3es I '
16 j shell> Memo<String> hello Memo .
17 System. out . print "world! " ) •
18
19 return "hello'
28 j shell> hello
21 hello
22 j shell> hello . get( ) 23 world !
"
24 " hello
25 j shell> hello .get( ) // note "world ! " is NOT printed again
26 " hello'
You can test your code by running the Test2 . java provided. The following should compile without errors or warnings. Make sure your code follows the CS2030S Java style and can generate the documentation without error.
$ javac cs2û3Øs/fp/*java
2 $ javac -X lint : rawtypes Test2.java
3 $ java Test2
4 $ java -jar
5 Memo . java
$ javadoc -quiet -private -d docs cs2Ø3ûs/fp/Memo.java
Implementing Immutatorable and Adding Next
Now let's implement Immutatorable interface to our Lazy and Memo as well as adding next method. To do this, add the transform and next method to both Lazy and Memo . First, for Lazy .
Add the transform method to Lazy . Additionally, add the next method (we did not have an interface for this for simplicity). Remember that Lazy should not evaluate anything until get() is called, so the function f passed into Lazy through transform and next should not be evaluated until get() is called. The result should not be cached (i.e., memoized).
Next, add the transform and next method to Memo . These two methods should override the methods from Lazy . This should limit the type of the input parameter. But the return type here should be as specific as method overriding allows. Remember that Memo should cache the result. In other words, they should only be evaluated once, so that function must not be called again.
j shell> import cs293es . fp . Constant
2 j shell> importfp . Immutator
3 j shell> importfp . Lazy
4 j shell> import cs2Ø3Ês.fp . Memo
5
6 j shell> Constant<String> password - o - > "123456 1
7
8 j shell> Lazy<String> lazy Lazy. from(password)
9 j shell> lazy
19 lazy 123456
11 jshell> lazy. transform(str -> str.substring(û, 1 ) )
12
13
14 jshell> Memo<String> memo Memo . from(password) 1 5 jshell> memo. transform(str -> str .substring(e, 1 ) )
16 jshell> memo
18 memo
19 jshell> memo. transform(str -> str .substring(e, 1 ) ) •get ( )
29
21 jshell> memo
22 memo 123456
23 j shell> memo . get()
24
25 " 123456 "
26 j shell> Immutator<lnteger, String> len str
27 System . out . print " length" ) ;
28
29
39 return str . length( ) ;
31 j shell> Lazy<lnteger> lazyLen lazy. transform(len)
32
33
34 j shell> length lazyLen lazyLen

35
36 j shell> length
lazyLen . get()
6
38
39
49
41 j shell> length
lazyLen . get()
6
42 j shell> Memo<lnteger> memoLen memo. transform(len)
43
44 j shell> memoLen memoLen

45
46
47 j shell> length
memoLen . get ( )
6
48
49 j shell>
memoLen . get ( )
6
51
52 j shell> stepl Memo<lnteger>
stepl - Memo . from(lûlû)
53 j shell> Memo<lnteger> step2 - stepl . transform(i -> i * 2)
54 step2
55 j shell> Memo<lnteger> step3 step2.next(i -> Memo. from(i + 18) )
56 step3
57 j shell> step3 . get()
58
59 j shell> step2 // to get() step3 need to get() step2
69 step2 2928
61 j shell> stepl // to get() step2 need to get() stepl 62 stepl
63
64 j shell> Memo<lnteger> noErr Memo . from(û)
65 noErr
66 j shell> Memo<lnteger> err noErr.transform(x -> l /x)
67 err
68 j shell> // if you run err .get( ) , you will get an exception
You c 6 without errors or warnings. Make sure your code follows the CS2030S Java style and can generate the documentation without error.
$ javac cs2Ø39s/fp/*java
2 $ javac -Xlint : rawtypes Test3 .java
3 $ java Test3
4 $ java -jar
5 Lazy. java
6 $ javadoc -quiet -private -d docs cs2Ø3ûs/fp/Lazy.java
7 $ java -jar -c evcs2Ø3es/bin/cs2Ø3e_checks.xm1
Memo . java
$ javadoc -quiet -private -d docs cs293ûs/fp/Memo.java
Combine
We have provided an interface called Combiner<R, S, T> in cs2Û3ûs . fp , with a single combine method to combine two values, of type S and T respectively, into a result of type R .
j shell> import cs2û3ûs.fp . Combiner
2 j shell> import cs2Ø3ûs.fp . Memo
3
4 j shell> Memo<lnteger> twenty, thirty, modlnt
5 twenty null
6 thirty null
7 modlnt null
8
9 j shell> twenty Memo . from( ( )
19 twenty
11 j shell> thirty Memo .
12 thirty
13
14 j shell> Combiner<String, Integer, Integer> concat (x,
15 System . out . print " combine") ;
16 return x.toString( ) + y.toString( ) ;
18
19 j shell> modlnt twenty. combine(thirty, (x, y)
29 modlnt
21 j shell> Memo<String> modStr twenty . combine(thirty, concat)
22 modStr
23
24 j shell> modStr . get( )
25 combine
26
27 j shell> twenty
28 twenty = 29
29 j shell> thirty
39 thirty 39
31
32 j shell> modlnt
33 modlnt
34
35 j shell> Combiner<String, Integer, Double> comb -> x.toString( ) +
36 Y. toString( )
j shell> Memo<String> s - modInt.combine(Memo.from(e.1 ) , comb)
38 s
39 j shell>
s .get( )
"2639 + e. I l
41 j shell> modlnt
42 modlnt
43
44 j shell> Memo<lnteger> x - Memo. from(l )
45 j shell> for (int i e ; i < 19 ; i ++) {
46 final Memo<lnteger> y - x; // final just to ensure it is
47 unchanged
48 final int j - i ;
49 > x - Memo. from( ( ) > { System.out.println(j ) ; return y.get( ) +
59 y.get( ) ; D ;
51
52 j shell> x. get( ) ;
53 9
54 8
55 7
56 6
57 5
58 4
59 3
69 2
1924
You can test your code by running the Test4. java provided. The following should compile without errors or warnings. Make sure your code follows the CS2030S Java style and can generate the documentation without error.
1 $ javac cs2û39s/fp/*java
2 $ javac -X lint : rawtypes Test4.java
3 $ java Test4
4 $ java -jar -c evcs2Ø3es/bin/cs2Ø3e_checks.xm1
5 Lazy. java 6 $ javadoc -quiet -private -d docs cs293ûs/fp/Lazy.java
7 $ java -jar Ncs293es/bin/checksty1e.jar -c -acs2Ø3es/bin/cs2Ø3e_checks.xm1
Memo . java
$ javadoc -quiet -private -d docs cs2Ø3Øs/fp/Memo.java
Boolean Algebra
The Memo class can be used to build a function with short-circuit operation.
Consider a boolean expression with 4 classes abstracted into an interface Cond . java :
• And . java : conjunction of two boolean expressions, created from And(Cond IVa1, Cond rVa1) to mean IVa1 && rVa1 .
• Or. java : disjunction of two boolean expressions, created from Or (Cond IVa1, Cond rVal) to mean IVa1 1 1 rVa1 .
• Not . java : negation of a boolean expression, created from Not (Cond val) to mean ! val .
Creating an instance of boolean expression above requires us to have fully evaluated the arguments. As such, when we call the eval method, all the values have actually been evaluated. But remember that the operation && and I I are actually short-circuit operation. In particular, false && X and true I I X should not evaluate the value X since the result will already be false and true respectively.
But suppose x takes very long to evaluate. Short-circuit operation will simply return the result without evaluating the value of x and that saves us time. This is exactly what we want to do. We want to avoid evaluating this X whenever possible. Study the code below to understand how the classes work. You do not really have to know how negation method neg works. But if you are interested in it, you can look up De Morgan's Law.
j shell> /open Cond.java
2 j shell> /open Bool.java
3 j shell> /open And. java
4 j shell> /open Or. java
5
6 j shell> /open Not. java
7 j shell> Constant<B001ean> t new Constant<>() {
8 public Boolean init( ) {
9
19
11 return true;
12 j shell> Constant<B001ean> f - new Constant<>() {
13 public Boolean init( ) {
14 String res 15 for (int i=e ; i<leeeee;
16
17
18 return false ;
19
29
21 j shell> // the following line will take some time to run
22 j shell> Cond cond - new And(new Or (new Bool(t) , new Bool(f) ) , new Not (new
23 Not (new Bool(t) ) ) )
24 cond
25
26 j shell>
cond . neg()
27
28 j shell>
cond.neg() .neg()
29 j shell> cond . eval( )
38 true
31 j shell> cond.neg() . eval( )
32 false
33 j shell>
cond.neg() .neg() .eval( ) true
Change the boolean expression implementation above such that a value is only evaluated when it is truly needed. You should use Memo class in your changes.
Hint: you only need to make minimal changes. Neither a new field nor a new function is necessary. If done correctly, the following sample run below should run very quickly.
j shell> /open Cond.java 2 j shell> /open Bool.java
3 j shell> /open And. java
4 j shell> /open Or. java
5 j shell> /open Not. java
6
7 j shell> Constant<B001ean> t new Constant<>() {
8 public Boolean init( ) {
9 return true;
19
11
12 j shell> Constant<B001ean> f - new Constant<>() {
13 public Boolean init( ) {
14 String res
15 for (int i=Û; i<1ûØûûØ,• i++) {
16 res i ;
17
18 return false ;
19
29
21 j shell> // the following line will run very quickly
22 j shell> Cond cond - new And(new Or (new Bool(t) , new Bool(f) ) , new Not (new
23 Not (new Bool(t) ) ) )
24 cond
25 jshell> cond .neg( )
26
27 j shell> cond.neg() .neg()
28
29 j shell> cond . eval( )
39 true
31 j shell> cond . neg()
32
33 j shell> cond.neg() .neg()

You can test your code by running the Test5 . java provided. The following should compile without errors or warnings. Make sure your code follows the CS2030S Java style but there is no need to generate javadoc.
$ javac cs2Ø3Øs/fp/*java
2 $ javac -Xlint : rawtypes Test5.java 3 $ java Test5
Following CS2030S Style Guide
You should make sure that your code follows the given Java style guide.
Grading
This lab is worth 12 marks and contributes 3% to your final grade. The marking scheme is as follows:
• Documentation: 2 marks
• Everything Else: 10 marks
We will deduct 1 mark for each unnecessary use of @SuppressWarnings and each raw type. @SuppressWarnings should be used appropriately and not abused to remove compilation warnings.
Note that general style marks are no longer awarded will only be awarded for documentation. You should know how to follow the prescribed Java style by now. We will still deduct up to 2 marks if there are serious violations of styles. In other words, if you have no documentation and serious violation of styles, you will get deducted 4 marks.
Submission
Similar to Lab 5, submit the files inside the directory cs2030s/fp along with the other file without the need for folder. Your cs2030s/fp should only contain the following files:
Action . java
Actionable . java
Actually . java
Combiner . java
Constant . java
Immutator . java
Immutatorable . java
Lazy. java
Memo . java
Additionally, you must submit the file Lab6 . h . Otherwise, you CodeCrunch submission will not run.

More products