feat: add lab7
This commit is contained in:
parent
4ee04937da
commit
86e5d543b2
76
Lab7/CS2030STest.java
Normal file
76
Lab7/CS2030STest.java
Normal file
@ -0,0 +1,76 @@
|
||||
import java.net.URI;
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
import javax.tools.DiagnosticCollector;
|
||||
import javax.tools.SimpleJavaFileObject;
|
||||
import javax.tools.ToolProvider;
|
||||
import java.io.PrintStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
|
||||
public class CS2030STest {
|
||||
|
||||
private static final String ANSI_RESET = "\u001B[0m";
|
||||
private static final String ANSI_RED = "\u001B[31m";
|
||||
private static final String ANSI_GREEN = "\u001B[32m";
|
||||
|
||||
public void expect(String test, Object output, Object expect) {
|
||||
System.out.print(test);
|
||||
if ((expect == null && output == null) || output.equals(expect)) {
|
||||
System.out.println(".. " + ANSI_GREEN + "ok" + ANSI_RESET);
|
||||
} else {
|
||||
System.out.println(".. " + ANSI_RED + "failed" + ANSI_RESET);
|
||||
System.out.println(" expected: " + expect);
|
||||
System.out.println(" got this: " + output);
|
||||
}
|
||||
}
|
||||
|
||||
public static String clean(String txt) {
|
||||
String res = "";
|
||||
for (int i=0; i<txt.length(); i++) {
|
||||
if (txt.charAt(i) != '\r' && txt.charAt(i) != '\n') {
|
||||
res += txt.charAt(i);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
public void expectPrint(String test, Object expect, ByteArrayOutputStream baos, PrintStream old) {
|
||||
System.out.flush();
|
||||
System.setOut(old);
|
||||
expect(test, CS2030STest.clean(baos.toString()), expect);
|
||||
}
|
||||
|
||||
public void expectCompile(String test, String statement, boolean success) {
|
||||
System.out.print(test);
|
||||
|
||||
class JavaSourceFromString extends SimpleJavaFileObject {
|
||||
final String code;
|
||||
|
||||
JavaSourceFromString(String code) {
|
||||
super(URI.create("string:///TempClass.java"), Kind.SOURCE);
|
||||
this.code = "class TempClass {void foo(){" + code + ";}}";
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getCharContent(boolean ignoreEncodingErrors) {
|
||||
return code;
|
||||
}
|
||||
}
|
||||
|
||||
boolean noError = ToolProvider
|
||||
.getSystemJavaCompiler()
|
||||
.getTask(null, null, new DiagnosticCollector<>(), null, null,
|
||||
List.of(new JavaSourceFromString(statement)))
|
||||
.call();
|
||||
|
||||
if (noError != success) {
|
||||
System.out.println(".. " + ANSI_RED + "failed" + ANSI_RESET);
|
||||
if (!success) {
|
||||
System.out.println(" expected compilation error but it compiles fine.");
|
||||
} else {
|
||||
System.out.println(" expected the statement to compile without errors but it does not.");
|
||||
}
|
||||
} else {
|
||||
System.out.println(".. " + ANSI_GREEN + "ok" + ANSI_RESET);
|
||||
}
|
||||
}
|
||||
}
|
76
Lab7/EagerList.java
Normal file
76
Lab7/EagerList.java
Normal file
@ -0,0 +1,76 @@
|
||||
import cs2030s.fp.Immutator;
|
||||
import cs2030s.fp.Combiner;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A wrapper around an eagerly evaluated list that
|
||||
* can be generated with a lambda expression.
|
||||
*
|
||||
* @author Adi Yoga S. Prabawa
|
||||
* @version CS2030S AY 22/23 Sem 1
|
||||
*/
|
||||
class EagerList<T> {
|
||||
/** The wrapped java.util.List object */
|
||||
private List<T> list;
|
||||
|
||||
/**
|
||||
* A private constructor to initialize the list to the given one.
|
||||
*
|
||||
* @param list The given java.util.List to wrap around.
|
||||
*/
|
||||
private EagerList(List<T> list) {
|
||||
this.list = list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the content of the list. Given x and a lambda f,
|
||||
* generate the list of n elements as [x, f(x), f(f(x)), f(f(f(x))),
|
||||
* ... ]
|
||||
*
|
||||
* @param <T> The type of the elements in the list.
|
||||
* @param n The number of elements.
|
||||
* @param seed The first element.
|
||||
* @param f The immutator function on the elements.
|
||||
* @return The created list.
|
||||
*/
|
||||
public static <T> EagerList<T> generate(int n, T seed, Immutator<T, T> f) {
|
||||
EagerList<T> eagerList = new EagerList<>(new ArrayList<>());
|
||||
T curr = seed;
|
||||
for (int i = 0; i < n; i++ ) {
|
||||
eagerList.list.add(curr);
|
||||
curr = f.invoke(curr);
|
||||
}
|
||||
return eagerList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the element at index i of the list.
|
||||
*
|
||||
* @param i The index of the element to retrieved (0 for the 1st element).
|
||||
* @return The element at index i.
|
||||
*/
|
||||
public T get(int i) {
|
||||
return this.list.get(i);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the index of a given element.
|
||||
*
|
||||
* @param v The value of the element to look for.
|
||||
* @return The index of the element in the list. -1 is element is not in the list.
|
||||
*/
|
||||
public int indexOf(T v) {
|
||||
return this.list.indexOf(v);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the string representation of the list.
|
||||
*
|
||||
* @return The string representation of the list.
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.list.toString();
|
||||
}
|
||||
}
|
18
Lab7/Lab7.h
Normal file
18
Lab7/Lab7.h
Normal file
@ -0,0 +1,18 @@
|
||||
#!/bin/bash
|
||||
|
||||
mkdir cs2030s
|
||||
cd cs2030s
|
||||
mkdir fp
|
||||
cd ..
|
||||
|
||||
mv Action.java cs2030s/fp/Action.java
|
||||
mv Actionable.java cs2030s/fp/Actionable.java
|
||||
mv Actually.java cs2030s/fp/Actually.java
|
||||
mv Combiner.java cs2030s/fp/Combiner.java
|
||||
mv Constant.java cs2030s/fp/Constant.java
|
||||
mv Immutator.java cs2030s/fp/Immutator.java
|
||||
mv Immutatorable.java cs2030s/fp/Immutatorable.java
|
||||
mv Memo.java cs2030s/fp/Memo.java
|
||||
|
||||
javac cs2030s/fp/*.java
|
||||
javac *.java
|
235
Lab7/Lab7.java
Normal file
235
Lab7/Lab7.java
Normal file
@ -0,0 +1,235 @@
|
||||
import cs2030s.fp.*;
|
||||
import java.util.Scanner;
|
||||
|
||||
class Lab7 {
|
||||
public static void main(String[] args) {
|
||||
// Create a scanner to read from standard input.
|
||||
Scanner sc = new Scanner(System.in);
|
||||
|
||||
// Read a single integer from the test file
|
||||
// and then run the appropriate test case
|
||||
switch (sc.nextInt()) {
|
||||
case 1:
|
||||
test1();
|
||||
break;
|
||||
case 2:
|
||||
test2();
|
||||
break;
|
||||
case 3:
|
||||
test3();
|
||||
break;
|
||||
case 4:
|
||||
test4();
|
||||
break;
|
||||
case 5:
|
||||
test5();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public static void test1() {
|
||||
int[] eval = new int[]{0};
|
||||
Immutator<Integer, Integer> incr = x -> {
|
||||
eval[0] += 1;
|
||||
return x + 1;
|
||||
};
|
||||
|
||||
MemoList<Integer> l = MemoList.generate(4, 0, incr);
|
||||
|
||||
System.out.println(l.toString());
|
||||
System.out.println(eval[0]);
|
||||
System.out.println(l.indexOf(2));
|
||||
System.out.println(eval[0]);
|
||||
System.out.println(l.indexOf(1));
|
||||
System.out.println(eval[0]);
|
||||
System.out.println(l.get(1));
|
||||
System.out.println(eval[0]);
|
||||
System.out.println(l.get(3));
|
||||
System.out.println(eval[0]);
|
||||
}
|
||||
|
||||
public static void test2() {
|
||||
int[] eval = new int[]{0};
|
||||
Combiner<Integer, Integer, Integer> fib = (x, y) -> {
|
||||
eval[0] += 1;
|
||||
return x + y;
|
||||
};
|
||||
|
||||
MemoList<Integer> l = MemoList.generate(8, 0, 1, fib);
|
||||
|
||||
System.out.println(l.toString());
|
||||
System.out.println(eval[0]);
|
||||
System.out.println(l.indexOf(5));
|
||||
System.out.println(eval[0]);
|
||||
System.out.println(l.indexOf(3));
|
||||
System.out.println(eval[0]);
|
||||
System.out.println(l.get(4));
|
||||
System.out.println(eval[0]);
|
||||
System.out.println(l.get(6));
|
||||
System.out.println(eval[0]);
|
||||
}
|
||||
|
||||
public static void test3() {
|
||||
int[] _incr = new int[]{0};
|
||||
Immutator<Integer, Integer> incr = x -> {
|
||||
_incr[0] += 1;
|
||||
return x + 1;
|
||||
};
|
||||
int[] _dbl = new int[]{0};
|
||||
Immutator<Integer, Integer> dbl = x -> {
|
||||
_dbl[0] += 1;
|
||||
return x + x;
|
||||
};
|
||||
|
||||
MemoList<Integer> nat = MemoList.generate(10, 0, incr);
|
||||
|
||||
System.out.println(nat.toString());
|
||||
System.out.println(_incr[0]);
|
||||
System.out.println(_dbl[0]);
|
||||
|
||||
MemoList<Integer> even = nat.map(dbl);
|
||||
|
||||
System.out.println(even.toString());
|
||||
System.out.println(nat.indexOf(2));
|
||||
System.out.println(_incr[0]);
|
||||
System.out.println(_dbl[0]);
|
||||
System.out.println(even.indexOf(6));
|
||||
System.out.println(_incr[0]);
|
||||
System.out.println(_dbl[0]);
|
||||
|
||||
MemoList<Integer> odd = even.map(incr);
|
||||
|
||||
System.out.println(odd.toString());
|
||||
System.out.println(_incr[0]);
|
||||
System.out.println(_dbl[0]);
|
||||
System.out.println(odd.get(8));
|
||||
System.out.println(_incr[0]);
|
||||
System.out.println(_dbl[0]);
|
||||
}
|
||||
|
||||
public static void test4() {
|
||||
int[] _dupl = new int[]{0};
|
||||
int[] _copy = new int[]{0};
|
||||
Immutator<MemoList<Integer>, Integer> dupl = x -> {
|
||||
_dupl[0] += 1;
|
||||
return MemoList.generate(x, x, n -> {
|
||||
_copy[0] += 1;
|
||||
return x;
|
||||
});
|
||||
};
|
||||
|
||||
MemoList<Integer> nat = MemoList.generate(5, 1, x -> x + 1);
|
||||
|
||||
System.out.println(nat.toString());
|
||||
System.out.println(_dupl[0]);
|
||||
System.out.println(_copy[0]);
|
||||
|
||||
MemoList<Integer> superNat = nat.flatMap(dupl);
|
||||
System.out.println(superNat.toString());
|
||||
System.out.println(_dupl[0]);
|
||||
System.out.println(_copy[0]);
|
||||
|
||||
int[] _dbl = new int[]{0};
|
||||
Immutator<Integer, Integer> dbl = x -> {
|
||||
_dbl[0] += 1;
|
||||
return x * 2;
|
||||
};
|
||||
|
||||
MemoList<Integer> superEven = superNat.map(dbl);
|
||||
|
||||
System.out.println(superEven.toString());
|
||||
System.out.println(_dupl[0]);
|
||||
System.out.println(_copy[0]);
|
||||
System.out.println(_dbl[0]);
|
||||
System.out.println(superEven.get(12));
|
||||
System.out.println(_dupl[0]);
|
||||
System.out.println(_copy[0]);
|
||||
System.out.println(_dbl[0]);
|
||||
System.out.println(superEven.toString());
|
||||
System.out.println(superNat.toString());
|
||||
System.out.println(nat.toString());
|
||||
|
||||
MemoList<Integer> nat2 = MemoList.generate(5, 1, x -> x + 1);
|
||||
MemoList<MemoList<Integer>> nestNat2 = nat2.map(dupl);
|
||||
|
||||
System.out.println(nestNat2.toString());
|
||||
System.out.println(_dupl[0]);
|
||||
System.out.println(_copy[0]);
|
||||
System.out.println(_dbl[0]);
|
||||
System.out.println(nestNat2.get(2));
|
||||
System.out.println(_dupl[0]);
|
||||
System.out.println(_copy[0]);
|
||||
System.out.println(_dbl[0]);
|
||||
|
||||
for (int i=0; i<5; i++) {
|
||||
nestNat2.get(i);
|
||||
}
|
||||
System.out.println(nestNat2.toString());
|
||||
System.out.println(_dupl[0]);
|
||||
System.out.println(_copy[0]);
|
||||
System.out.println(_dbl[0]);
|
||||
|
||||
for (int i=0; i<5; i++) {
|
||||
for (int j=0; j<=i; j++) {
|
||||
nestNat2.get(i).get(j);
|
||||
}
|
||||
}
|
||||
System.out.println(nestNat2.toString());
|
||||
System.out.println(_dupl[0]);
|
||||
System.out.println(_copy[0]);
|
||||
System.out.println(_dbl[0]);
|
||||
}
|
||||
|
||||
public static void test5() {
|
||||
class A {
|
||||
private int x;
|
||||
public A(int x) {
|
||||
this.x = x;
|
||||
}
|
||||
public int getX() {
|
||||
return this.x;
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return "A:" + this.x;
|
||||
}
|
||||
}
|
||||
class B extends A {
|
||||
public B(int x) {
|
||||
super(x);
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return "B:" + super.toString();
|
||||
}
|
||||
}
|
||||
class C extends B {
|
||||
public C(int x) {
|
||||
super(x);
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return "C:" + super.toString();
|
||||
}
|
||||
}
|
||||
|
||||
Immutator<C, A> incr = x -> new C(x.getX() + 1);
|
||||
Combiner<C, A, A> fib = (x, y) -> new C(x.getX() + y.getX());
|
||||
Immutator<MemoList<B>, A> dbl = x -> MemoList.generate(x.getX(), new C(x.getX()), y -> new C(y.getX() + 1));
|
||||
MemoList<B> bList1 = MemoList.generate(8, new C(0), incr);
|
||||
|
||||
System.out.println(bList1.toString());
|
||||
|
||||
MemoList<B> bList2 = MemoList.generate(8, new C(0), new C(1), fib);
|
||||
|
||||
System.out.println(bList2.toString());
|
||||
|
||||
MemoList<B> bList3 = bList1.map(incr);
|
||||
|
||||
System.out.println(bList3.toString());
|
||||
|
||||
MemoList<B> bList4 = bList1.flatMap(dbl);
|
||||
|
||||
System.out.println(bList4.toString());
|
||||
}
|
||||
}
|
BIN
Lab7/Lab7.pdf
Normal file
BIN
Lab7/Lab7.pdf
Normal file
Binary file not shown.
76
Lab7/MemoList.java
Normal file
76
Lab7/MemoList.java
Normal file
@ -0,0 +1,76 @@
|
||||
import cs2030s.fp.Immutator;
|
||||
import cs2030s.fp.Combiner;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A wrapper around a lazily evaluated and memoized
|
||||
* list that can be generated with a lambda expression.
|
||||
*
|
||||
* @author Adi Yoga S. Prabawa
|
||||
* @version CS2030S AY 22/23 Sem 1
|
||||
*/
|
||||
class MemoList<T> {
|
||||
/** The wrapped java.util.List object */
|
||||
private List<T> list;
|
||||
|
||||
/**
|
||||
* A private constructor to initialize the list to the given one.
|
||||
*
|
||||
* @param list The given java.util.List to wrap around.
|
||||
*/
|
||||
private MemoList(List<T> list) {
|
||||
this.list = list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the content of the list. Given x and a lambda f,
|
||||
* generate the list of n elements as [x, f(x), f(f(x)), f(f(f(x))),
|
||||
* ... ]
|
||||
*
|
||||
* @param <T> The type of the elements in the list.
|
||||
* @param n The number of elements.
|
||||
* @param seed The first element.
|
||||
* @param f The immutator function on the elements.
|
||||
* @return The created list.
|
||||
*/
|
||||
public static <T> MemoList<T> generate(int n, T seed, Immutator<T, T> f) {
|
||||
MemoList<T> memoList = new MemoList<>(new ArrayList<>());
|
||||
T curr = seed;
|
||||
for (int i = 0; i < n; i++ ) {
|
||||
MemoList.list.add(curr);
|
||||
curr = f.invoke(curr);
|
||||
}
|
||||
return memoList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the element at index i of the list.
|
||||
*
|
||||
* @param i The index of the element to retrieved (0 for the 1st element).
|
||||
* @return The element at index i.
|
||||
*/
|
||||
public T get(int i) {
|
||||
return this.list.get(i);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the index of a given element.
|
||||
*
|
||||
* @param v The value of the element to look for.
|
||||
* @return The index of the element in the list. -1 is element is not in the list.
|
||||
*/
|
||||
public int indexOf(T v) {
|
||||
return this.list.indexOf(v);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the string representation of the list.
|
||||
*
|
||||
* @return The string representation of the list.
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.list.toString();
|
||||
}
|
||||
}
|
50
Lab7/Test1.java
Normal file
50
Lab7/Test1.java
Normal file
@ -0,0 +1,50 @@
|
||||
import cs2030s.fp.Immutator;
|
||||
import cs2030s.fp.Memo;
|
||||
|
||||
public class Test1 {
|
||||
public static void main(String[] args) {
|
||||
CS2030STest we = new CS2030STest();
|
||||
|
||||
int[] eval = new int[]{0};
|
||||
Immutator<Integer, Integer> incr = x -> {
|
||||
eval[0] += 1;
|
||||
return x + 1;
|
||||
};
|
||||
|
||||
MemoList<Integer> l = MemoList.generate(4, 0, incr);
|
||||
|
||||
we.expect(
|
||||
"An initial MemoList only has a single evaluated element",
|
||||
l.toString(),
|
||||
"[0, ?, ?, ?]"
|
||||
);
|
||||
|
||||
l.indexOf(2);
|
||||
we.expect(
|
||||
"Looking for 2 causes 2 evaluations",
|
||||
eval[0],
|
||||
2
|
||||
);
|
||||
|
||||
l.indexOf(1);
|
||||
we.expect(
|
||||
"Looking for 1 does not need any more evaluation",
|
||||
eval[0],
|
||||
2
|
||||
);
|
||||
|
||||
l.get(1);
|
||||
we.expect(
|
||||
"Retrieving index 1 does not need any more evaluation",
|
||||
eval[0],
|
||||
2
|
||||
);
|
||||
|
||||
l.get(3);
|
||||
we.expect(
|
||||
"Retrieving index 3 causes one more evaluation",
|
||||
eval[0],
|
||||
3
|
||||
);
|
||||
}
|
||||
}
|
50
Lab7/Test2.java
Normal file
50
Lab7/Test2.java
Normal file
@ -0,0 +1,50 @@
|
||||
import cs2030s.fp.Combiner;
|
||||
import cs2030s.fp.Memo;
|
||||
|
||||
public class Test2 {
|
||||
public static void main(String[] args) {
|
||||
CS2030STest we = new CS2030STest();
|
||||
|
||||
int[] eval = new int[]{0};
|
||||
Combiner<Integer, Integer, Integer> fib = (x, y) -> {
|
||||
eval[0] += 1;
|
||||
return x + y;
|
||||
};
|
||||
|
||||
MemoList<Integer> l = MemoList.generate(8, 0, 1, fib);
|
||||
|
||||
we.expect(
|
||||
"An initial MemoList only has the first two values evaluated",
|
||||
l.toString(),
|
||||
"[0, 1, ?, ?, ?, ?, ?, ?]"
|
||||
);
|
||||
|
||||
l.indexOf(5);
|
||||
we.expect(
|
||||
"Looking for 5 causes 4 evaluations",
|
||||
eval[0],
|
||||
4
|
||||
);
|
||||
|
||||
l.indexOf(3);
|
||||
we.expect(
|
||||
"Looking for 3 does not need any more evaluation",
|
||||
eval[0],
|
||||
4
|
||||
);
|
||||
|
||||
l.get(4);
|
||||
we.expect(
|
||||
"Retrieving index 4 does not need any more evaluation",
|
||||
eval[0],
|
||||
4
|
||||
);
|
||||
|
||||
l.get(6);
|
||||
we.expect(
|
||||
"Retrieving 6 causes one more evaluation",
|
||||
eval[0],
|
||||
5
|
||||
);
|
||||
}
|
||||
}
|
70
Lab7/Test3.java
Normal file
70
Lab7/Test3.java
Normal file
@ -0,0 +1,70 @@
|
||||
import cs2030s.fp.Immutator;
|
||||
import cs2030s.fp.Memo;
|
||||
|
||||
public class Test3 {
|
||||
public static void main(String[] args) {
|
||||
CS2030STest we = new CS2030STest();
|
||||
|
||||
int[] _incr = new int[]{0};
|
||||
Immutator<Integer, Integer> incr = x -> {
|
||||
_incr[0] += 1;
|
||||
return x + 1;
|
||||
};
|
||||
int[] _dbl = new int[]{0};
|
||||
Immutator<Integer, Integer> dbl = x -> {
|
||||
_dbl[0] += 1;
|
||||
return x + x;
|
||||
};
|
||||
|
||||
MemoList<Integer> nat = MemoList.generate(10, 0, incr);
|
||||
we.expect(
|
||||
"An initial natural number only has a single evaluated element",
|
||||
nat.toString(),
|
||||
"[0, ?, ?, ?, ?, ?, ?, ?, ?, ?]"
|
||||
);
|
||||
|
||||
MemoList<Integer> even = nat.map(dbl);
|
||||
we.expect(
|
||||
"An initial even number has no evaluated element",
|
||||
even.toString(),
|
||||
"[?, ?, ?, ?, ?, ?, ?, ?, ?, ?]"
|
||||
);
|
||||
|
||||
nat.indexOf(2);
|
||||
we.expect(
|
||||
"Looking for 2 on natural number causes 2 evaluations on increments ...",
|
||||
_incr[0],
|
||||
2
|
||||
);
|
||||
we.expect(
|
||||
"... and causes 0 evaluations on double",
|
||||
_dbl[0],
|
||||
0
|
||||
);
|
||||
|
||||
even.indexOf(6);
|
||||
we.expect(
|
||||
"Looking for 6 on even number causes 1 more evaluation on increment ...",
|
||||
_incr[0],
|
||||
3
|
||||
);
|
||||
we.expect(
|
||||
"... and causes 4 evaluation on double",
|
||||
_dbl[0],
|
||||
4
|
||||
);
|
||||
|
||||
MemoList<Integer> odd = even.map(incr);
|
||||
odd.get(8);
|
||||
we.expect(
|
||||
"Retrieving index 8 on odd number causes 5 more evaluation on increment ...",
|
||||
_incr[0],
|
||||
9
|
||||
);
|
||||
we.expect(
|
||||
"... and causes 1 more evaluation on double",
|
||||
_dbl[0],
|
||||
5
|
||||
);
|
||||
}
|
||||
}
|
146
Lab7/Test4.java
Normal file
146
Lab7/Test4.java
Normal file
@ -0,0 +1,146 @@
|
||||
import cs2030s.fp.Immutator;
|
||||
import cs2030s.fp.Memo;
|
||||
|
||||
public class Test4 {
|
||||
public static void main(String[] args) {
|
||||
CS2030STest we = new CS2030STest();
|
||||
|
||||
int[] _dupl = new int[]{0};
|
||||
int[] _copy = new int[]{0};
|
||||
Immutator<MemoList<Integer>, Integer> dupl = x -> {
|
||||
_dupl[0] += 1;
|
||||
return MemoList.generate(x, x, n -> {
|
||||
_copy[0] += 1;
|
||||
return x;
|
||||
});
|
||||
};
|
||||
|
||||
MemoList<Integer> nat = MemoList.generate(5, 1, x -> x + 1);
|
||||
we.expect(
|
||||
"An initial natural number only has a single evaluated element",
|
||||
nat.toString(),
|
||||
"[1, ?, ?, ?, ?]"
|
||||
);
|
||||
|
||||
MemoList<Integer> superNat = nat.flatMap(dupl);
|
||||
we.expect(
|
||||
"An initial super natural number has 5 evaluated element",
|
||||
superNat.toString(),
|
||||
"[1, 2, ?, 3, ?, ?, 4, ?, ?, ?, 5, ?, ?, ?, ?]"
|
||||
);
|
||||
we.expect(
|
||||
"... and we check the number of evaluation on dupl",
|
||||
_dupl[0],
|
||||
5
|
||||
);
|
||||
|
||||
we.expect(
|
||||
"... and there are 0 evaluation on copy",
|
||||
_copy[0],
|
||||
0
|
||||
);
|
||||
int[] _dbl = new int[]{0};
|
||||
Immutator<Integer, Integer> dbl = x -> {
|
||||
_dbl[0] += 1;
|
||||
return x * 2;
|
||||
};
|
||||
MemoList<Integer> superEven = superNat.map(dbl);
|
||||
we.expect(
|
||||
"An initial super even number has no evaluated element",
|
||||
superEven.toString(),
|
||||
"[?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?]"
|
||||
);
|
||||
we.expect(
|
||||
"... and we check the number of evaluation on dbl",
|
||||
_dbl[0],
|
||||
0
|
||||
);
|
||||
we.expect(
|
||||
"... and there are 0 additional evaluation on dupl",
|
||||
_dupl[0],
|
||||
5
|
||||
);
|
||||
we.expect(
|
||||
"... and there are still 0 evaluation on copy",
|
||||
_copy[0],
|
||||
0
|
||||
);
|
||||
|
||||
superEven.get(12);
|
||||
we.expect(
|
||||
"Retrieving index 12 on super even number causes 1 evaluation on dbl ...",
|
||||
_dbl[0],
|
||||
1
|
||||
);
|
||||
we.expect(
|
||||
"... and causes 0 additional evaluations on dupl",
|
||||
_dupl[0],
|
||||
5
|
||||
);
|
||||
we.expect(
|
||||
"... and causes 2 evaluations on copy",
|
||||
_copy[0],
|
||||
2
|
||||
);
|
||||
|
||||
we.expect(
|
||||
"Final super even number to contain 1 evaluated element",
|
||||
superEven.toString(),
|
||||
"[?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 10, ?, ?]"
|
||||
);
|
||||
we.expect(
|
||||
"... and final super natural number to contain 7 evaluated element",
|
||||
superNat.toString(),
|
||||
"[1, 2, ?, 3, ?, ?, 4, ?, ?, ?, 5, 5, 5, ?, ?]"
|
||||
);
|
||||
we.expect(
|
||||
"... and final natural number to contain 5 evaluated element",
|
||||
nat.toString(),
|
||||
"[1, 2, 3, 4, 5]"
|
||||
);
|
||||
|
||||
MemoList<Integer> nat2 = MemoList.generate(5, 1, x -> x + 1);
|
||||
MemoList<MemoList<Integer>> nestNat2 = nat2.map(dupl);
|
||||
we.expect(
|
||||
"An initial nested natural number has no evaluated element",
|
||||
nestNat2.toString(),
|
||||
"[?, ?, ?, ?, ?]"
|
||||
);
|
||||
we.expect(
|
||||
"... and we check the number of evaluation on dupl",
|
||||
_dupl[0],
|
||||
5
|
||||
);
|
||||
|
||||
nestNat2.get(2);
|
||||
we.expect(
|
||||
"Retrieving index 2 on nested natural number causes 1 evaluation on dupl ...",
|
||||
nestNat2.toString(),
|
||||
"[?, ?, [3, ?, ?], ?, ?]"
|
||||
);
|
||||
we.expect(
|
||||
"... and we check the number of evaluation on dupl",
|
||||
_dupl[0],
|
||||
6
|
||||
);
|
||||
|
||||
for (int i=0; i<5; i++) {
|
||||
nestNat2.get(i);
|
||||
}
|
||||
we.expect(
|
||||
"nestNat2 to be a partially evaluated nested list",
|
||||
nestNat2.toString(),
|
||||
"[[1], [2, ?], [3, ?, ?], [4, ?, ?, ?], [5, ?, ?, ?, ?]]"
|
||||
);
|
||||
for (int i=0; i<5; i++) {
|
||||
for (int j=0; j<=i; j++) {
|
||||
nestNat2.get(i).get(j);
|
||||
}
|
||||
}
|
||||
we.expect(
|
||||
"nestNat2 to be a fully evaluated nested list",
|
||||
nestNat2.toString(),
|
||||
"[[1], [2, 2], [3, 3, 3], [4, 4, 4, 4], [5, 5, 5, 5, 5]]"
|
||||
);
|
||||
}
|
||||
}
|
72
Lab7/Test5.java
Normal file
72
Lab7/Test5.java
Normal file
@ -0,0 +1,72 @@
|
||||
import cs2030s.fp.Immutator;
|
||||
import cs2030s.fp.Combiner;
|
||||
import cs2030s.fp.Memo;
|
||||
|
||||
public class Test5 {
|
||||
public static void main(String[] args) {
|
||||
CS2030STest we = new CS2030STest();
|
||||
|
||||
class A {
|
||||
private int x;
|
||||
public A(int x) {
|
||||
this.x = x;
|
||||
}
|
||||
public int getX() {
|
||||
return this.x;
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return "A:" + this.x;
|
||||
}
|
||||
}
|
||||
class B extends A {
|
||||
public B(int x) {
|
||||
super(x);
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return "B:" + super.toString();
|
||||
}
|
||||
}
|
||||
class C extends B {
|
||||
public C(int x) {
|
||||
super(x);
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return "C:" + super.toString();
|
||||
}
|
||||
}
|
||||
|
||||
Immutator<C, A> incr = x -> new C(x.getX() + 1);
|
||||
Combiner<C, A, A> fib = (x, y) -> new C(x.getX() + y.getX());
|
||||
Immutator<MemoList<B>, A> dbl = x -> MemoList.generate(x.getX(), new C(x.getX()), y -> new C(y.getX() + 1));
|
||||
MemoList<B> bList1 = MemoList.generate(8, new C(0), incr);
|
||||
we.expect(
|
||||
"PECS is followed on generate (Immutator)",
|
||||
bList1.toString(),
|
||||
"[C:B:A:0, ?, ?, ?, ?, ?, ?, ?]"
|
||||
);
|
||||
|
||||
MemoList<B> bList2 = MemoList.generate(8, new C(0), new C(1), fib);
|
||||
we.expect(
|
||||
"PECS is followed on generate (Combiner)",
|
||||
bList2.toString(),
|
||||
"[C:B:A:0, C:B:A:1, ?, ?, ?, ?, ?, ?]"
|
||||
);
|
||||
|
||||
MemoList<B> bList3 = bList1.map(incr);
|
||||
we.expect(
|
||||
"PECS is followed on map",
|
||||
bList3.toString(),
|
||||
"[?, ?, ?, ?, ?, ?, ?, ?]"
|
||||
);
|
||||
|
||||
MemoList<B> bList4 = bList1.flatMap(dbl);
|
||||
we.expect(
|
||||
"PECS is followed on flatMap",
|
||||
bList4.toString(),
|
||||
"[C:B:A:1, C:B:A:2, ?, C:B:A:3, ?, ?, C:B:A:4, ?, ?, ?, C:B:A:5, ?, ?, ?, ?, C:B:A:6, ?, ?, ?, ?, ?, C:B:A:7, ?, ?, ?, ?, ?, ?]"
|
||||
);
|
||||
}
|
||||
}
|
18
Lab7/cs2030s/fp/Action.java
Normal file
18
Lab7/cs2030s/fp/Action.java
Normal file
@ -0,0 +1,18 @@
|
||||
package cs2030s.fp;
|
||||
|
||||
/**
|
||||
* Represent a function that acts on a value.
|
||||
* CS2030S Lab 5
|
||||
* AY22/23 Semester 1
|
||||
*
|
||||
* @param <T> The type of the input value.
|
||||
*/
|
||||
@FunctionalInterface
|
||||
interface Action<T> {
|
||||
/**
|
||||
* The functional method to act on the value t.
|
||||
*
|
||||
* @param t The input value.
|
||||
*/
|
||||
void call(T t);
|
||||
}
|
17
Lab7/cs2030s/fp/Actionable.java
Normal file
17
Lab7/cs2030s/fp/Actionable.java
Normal file
@ -0,0 +1,17 @@
|
||||
package cs2030s.fp;
|
||||
|
||||
/**
|
||||
* Represent a container that can act on its content.
|
||||
* CS2030S Lab 5
|
||||
* AY22/23 Semester 1
|
||||
*
|
||||
* @param <T> The type of the content.
|
||||
*/
|
||||
interface Actionable<T> {
|
||||
/**
|
||||
* The method to act on its content.
|
||||
*
|
||||
* @param f The action.
|
||||
*/
|
||||
void act(Action<? super T> f);
|
||||
}
|
89
Lab7/cs2030s/fp/Actually.java
Normal file
89
Lab7/cs2030s/fp/Actually.java
Normal file
@ -0,0 +1,89 @@
|
||||
package cs2030s.fp;
|
||||
|
||||
/**
|
||||
* A container class the encapsulate
|
||||
* a value that may or may not be an error.
|
||||
*
|
||||
* @author Adi Yoga S. Prabawa
|
||||
* @version CS2030S AY 22/23 Sem 1
|
||||
*/
|
||||
public class Actually<T> implements Immutatorable<T> {
|
||||
private T val;
|
||||
private Exception err;
|
||||
|
||||
private Actually(T val, Exception err) {
|
||||
this.val = val;
|
||||
this.err = err;
|
||||
}
|
||||
|
||||
public static <T> Actually<T> err() {
|
||||
// A common error for ease of use
|
||||
return new Actually<T>((T) null, new Exception("err"));
|
||||
}
|
||||
public static <T> Actually<T> err(Exception err) {
|
||||
return new Actually<T>((T) null, err);
|
||||
}
|
||||
public static <T> Actually<T> ok(T val) {
|
||||
return new Actually<T>(val, null);
|
||||
}
|
||||
|
||||
public T except(Constant<? extends T> com) {
|
||||
return this.err == null ? this.val : com.init();
|
||||
}
|
||||
public <U extends T> T unless(U val) {
|
||||
return this.err == null ? this.val : val;
|
||||
}
|
||||
public void finish(Action<? super T> act) {
|
||||
if (this.err == null) {
|
||||
act.call(this.val);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public <R> Actually<R> transform(Immutator<? extends R, ? super T> f) {
|
||||
return this.err == null ? Actually.<R>ok(f.invoke(this.val)) : Actually.<R>err(this.err);
|
||||
}
|
||||
public <R> Actually<? extends R> next(Immutator<? extends Actually<? extends R>, ? super T> f) {
|
||||
if (this.err != null) {
|
||||
return Actually.err(this.err);
|
||||
} else {
|
||||
return f.invoke(this.val);
|
||||
}
|
||||
}
|
||||
public Actually<T> check(Immutator<Boolean, ? super T> pred) {
|
||||
if (this.err != null) {
|
||||
return this;
|
||||
}
|
||||
Boolean chk = pred.invoke(this.val);
|
||||
if (chk) {
|
||||
return this;
|
||||
}
|
||||
return Actually.err();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (this.err != null) {
|
||||
return "<>";
|
||||
}
|
||||
return "<" + this.val + ">";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
if (!(obj instanceof Actually<?>)) {
|
||||
return false;
|
||||
}
|
||||
Actually<?> that = (Actually<?>) obj;
|
||||
if (this.err != null) {
|
||||
// for simplicity, all err is the same
|
||||
return that.err != null;
|
||||
}
|
||||
if (this.val == null) {
|
||||
return that.val == null;
|
||||
}
|
||||
return this.val.equals(that.val);
|
||||
}
|
||||
}
|
23
Lab7/cs2030s/fp/Combiner.java
Normal file
23
Lab7/cs2030s/fp/Combiner.java
Normal file
@ -0,0 +1,23 @@
|
||||
package cs2030s.fp;
|
||||
|
||||
/**
|
||||
* Represent a function that combines two values into one. The two inputs
|
||||
* and the result can be of different types.
|
||||
* CS2030S Lab 5
|
||||
* AY20/21 Semester 2
|
||||
*
|
||||
* @param <R> The type of the return value
|
||||
* @param <S> The type of the first input value
|
||||
* @param <T> The type of the second input value
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface Combiner<R, S, T> {
|
||||
/**
|
||||
* The functional method to combines two values into one.
|
||||
*
|
||||
* @param s The first input value
|
||||
* @param t The second input value
|
||||
* @return The value after combining s and t.
|
||||
*/
|
||||
R combine(S s, T t);
|
||||
}
|
18
Lab7/cs2030s/fp/Constant.java
Normal file
18
Lab7/cs2030s/fp/Constant.java
Normal file
@ -0,0 +1,18 @@
|
||||
package cs2030s.fp;
|
||||
|
||||
/**
|
||||
* Represent a function to initialise a constant value.
|
||||
* CS2030S Lab 5
|
||||
* AY22/23 Semester 1
|
||||
*
|
||||
* @param <T> The type of the constant value.
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface Constant<T> {
|
||||
/**
|
||||
* The functional method to initialise the constant.
|
||||
*
|
||||
* @return The constant value.
|
||||
*/
|
||||
T init();
|
||||
}
|
20
Lab7/cs2030s/fp/Immutator.java
Normal file
20
Lab7/cs2030s/fp/Immutator.java
Normal file
@ -0,0 +1,20 @@
|
||||
package cs2030s.fp;
|
||||
|
||||
/**
|
||||
* Represent a function that immutate one value into another, possible of different types.
|
||||
* CS2030S Lab 5
|
||||
* AY22/23 Semester 1
|
||||
*
|
||||
* @param <R> The type of the result value.
|
||||
* @param <P> The type of the input value.
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface Immutator<R, P> {
|
||||
/**
|
||||
* The functional method to immutate the value p.
|
||||
*
|
||||
* @param p The input value.
|
||||
* @return The value after applying the given immutation on p.
|
||||
*/
|
||||
R invoke(P p);
|
||||
}
|
18
Lab7/cs2030s/fp/Immutatorable.java
Normal file
18
Lab7/cs2030s/fp/Immutatorable.java
Normal file
@ -0,0 +1,18 @@
|
||||
package cs2030s.fp;
|
||||
|
||||
/**
|
||||
* Represent a container that can transforms its content to produce another container containing the immutated element, possible of different types.
|
||||
* CS2030S Lab 5
|
||||
* AY22/23 Semester 1
|
||||
*
|
||||
* @param <T> The type of the content.
|
||||
*/
|
||||
public interface Immutatorable<T> {
|
||||
/**
|
||||
* The method to produce another container with immutated element.
|
||||
*
|
||||
* @param f The immutator.
|
||||
* @return A new container containing the immutated element.
|
||||
*/
|
||||
<R> Immutatorable<R> transform(Immutator<? extends R, ? super T> f);
|
||||
}
|
73
Lab7/cs2030s/fp/Memo.java
Normal file
73
Lab7/cs2030s/fp/Memo.java
Normal file
@ -0,0 +1,73 @@
|
||||
package cs2030s.fp;
|
||||
|
||||
/**
|
||||
* A container class the encapsulate a
|
||||
* lazily-evaluated-and-memoized value.
|
||||
*
|
||||
* @author Adi Yoga S. Prabawa
|
||||
* @version CS2030S AY 22/23 Sem 1
|
||||
*/
|
||||
public class Memo<T> implements Immutatorable<T> {
|
||||
|
||||
private Constant<? extends T> com;
|
||||
private Actually<T> val;
|
||||
|
||||
private Memo(Actually<T> val, Constant<T> com) {
|
||||
this.com = com;
|
||||
this.val = val;
|
||||
}
|
||||
|
||||
public static <T> Memo<T> from(T val) {
|
||||
return new Memo<T>(Actually.ok(val), null);
|
||||
}
|
||||
public static <T> Memo<T> from(Constant<T> com) {
|
||||
return new Memo<T>(Actually.err(), com);
|
||||
}
|
||||
|
||||
public T get() {
|
||||
this.eval();
|
||||
return this.val.unless(null);
|
||||
}
|
||||
private void eval() {
|
||||
if (this.com != null) {
|
||||
this.val = Actually.<T>ok(this.com.init());
|
||||
this.com = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R> Memo<R> transform(Immutator<? extends R, ? super T> f) {
|
||||
return Memo.<R>from(() -> f.invoke(this.get()));
|
||||
}
|
||||
public <R> Memo<R> next(Immutator<? extends Memo<? extends R>, ? super T> f) {
|
||||
return Memo.<R>from(() -> f.invoke(this.get()).get());
|
||||
}
|
||||
public <S, R> Memo<R> combine(Memo<S> snd, Combiner<? extends R, ? super T, ? super S> f) {
|
||||
return Memo.<R>from(() -> f.combine(this.get(), snd.get()));
|
||||
}
|
||||
public Memo<Boolean> check(Immutator<Boolean, ? super T> pred) {
|
||||
return Memo.<Boolean>from(() -> pred.invoke(this.get()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (this.com != null) {
|
||||
return "?";
|
||||
}
|
||||
return this.get().toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
if (!(obj instanceof Memo<?>)) {
|
||||
return false;
|
||||
}
|
||||
Memo<?> that = (Memo<?>) obj;
|
||||
that.eval();
|
||||
this.eval();
|
||||
return this.val.equals(that.val);
|
||||
}
|
||||
}
|
1
Lab7/input/Test1.in
Normal file
1
Lab7/input/Test1.in
Normal file
@ -0,0 +1 @@
|
||||
1
|
1
Lab7/input/Test2.in
Normal file
1
Lab7/input/Test2.in
Normal file
@ -0,0 +1 @@
|
||||
2
|
1
Lab7/input/Test3.in
Normal file
1
Lab7/input/Test3.in
Normal file
@ -0,0 +1 @@
|
||||
3
|
1
Lab7/input/Test4.in
Normal file
1
Lab7/input/Test4.in
Normal file
@ -0,0 +1 @@
|
||||
4
|
1
Lab7/input/Test5.in
Normal file
1
Lab7/input/Test5.in
Normal file
@ -0,0 +1 @@
|
||||
5
|
10
Lab7/output/Test1.out
Normal file
10
Lab7/output/Test1.out
Normal file
@ -0,0 +1,10 @@
|
||||
[0, ?, ?, ?]
|
||||
0
|
||||
2
|
||||
2
|
||||
1
|
||||
2
|
||||
1
|
||||
2
|
||||
3
|
||||
3
|
10
Lab7/output/Test2.out
Normal file
10
Lab7/output/Test2.out
Normal file
@ -0,0 +1,10 @@
|
||||
[0, 1, ?, ?, ?, ?, ?, ?]
|
||||
0
|
||||
5
|
||||
4
|
||||
4
|
||||
4
|
||||
3
|
||||
4
|
||||
8
|
||||
5
|
16
Lab7/output/Test3.out
Normal file
16
Lab7/output/Test3.out
Normal file
@ -0,0 +1,16 @@
|
||||
[0, ?, ?, ?, ?, ?, ?, ?, ?, ?]
|
||||
0
|
||||
0
|
||||
[?, ?, ?, ?, ?, ?, ?, ?, ?, ?]
|
||||
2
|
||||
2
|
||||
0
|
||||
3
|
||||
3
|
||||
4
|
||||
[?, ?, ?, ?, ?, ?, ?, ?, ?, ?]
|
||||
3
|
||||
4
|
||||
17
|
||||
9
|
||||
5
|
33
Lab7/output/Test4.out
Normal file
33
Lab7/output/Test4.out
Normal file
@ -0,0 +1,33 @@
|
||||
[1, ?, ?, ?, ?]
|
||||
0
|
||||
0
|
||||
[1, 2, ?, 3, ?, ?, 4, ?, ?, ?, 5, ?, ?, ?, ?]
|
||||
5
|
||||
0
|
||||
[?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?]
|
||||
5
|
||||
0
|
||||
0
|
||||
10
|
||||
5
|
||||
2
|
||||
1
|
||||
[?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 10, ?, ?]
|
||||
[1, 2, ?, 3, ?, ?, 4, ?, ?, ?, 5, 5, 5, ?, ?]
|
||||
[1, 2, 3, 4, 5]
|
||||
[?, ?, ?, ?, ?]
|
||||
5
|
||||
2
|
||||
1
|
||||
[3, ?, ?]
|
||||
6
|
||||
2
|
||||
1
|
||||
[[1], [2, ?], [3, ?, ?], [4, ?, ?, ?], [5, ?, ?, ?, ?]]
|
||||
10
|
||||
2
|
||||
1
|
||||
[[1], [2, 2], [3, 3, 3], [4, 4, 4, 4], [5, 5, 5, 5, 5]]
|
||||
10
|
||||
12
|
||||
1
|
4
Lab7/output/Test5.out
Normal file
4
Lab7/output/Test5.out
Normal file
@ -0,0 +1,4 @@
|
||||
[C:B:A:0, ?, ?, ?, ?, ?, ?, ?]
|
||||
[C:B:A:0, C:B:A:1, ?, ?, ?, ?, ?, ?]
|
||||
[?, ?, ?, ?, ?, ?, ?, ?]
|
||||
[C:B:A:1, C:B:A:2, ?, C:B:A:3, ?, ?, C:B:A:4, ?, ?, ?, C:B:A:5, ?, ?, ?, ?, C:B:A:6, ?, ?, ?, ?, ?, C:B:A:7, ?, ?, ?, ?, ?, ?]
|
Loading…
Reference in New Issue
Block a user