feat: add lab7

This commit is contained in:
Yadunand Prem 2022-10-20 13:51:59 +08:00
parent 4ee04937da
commit 86e5d543b2
29 changed files with 1223 additions and 0 deletions

76
Lab7/CS2030STest.java Normal file
View 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
View 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
View 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
View 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

Binary file not shown.

76
Lab7/MemoList.java Normal file
View 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
View 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
View 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
View 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
View 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
View 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, ?, ?, ?, ?, ?, ?]"
);
}
}

View 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);
}

View 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);
}

View 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);
}
}

View 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);
}

View 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();
}

View 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);
}

View 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
View 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
View File

@ -0,0 +1 @@
1

1
Lab7/input/Test2.in Normal file
View File

@ -0,0 +1 @@
2

1
Lab7/input/Test3.in Normal file
View File

@ -0,0 +1 @@
3

1
Lab7/input/Test4.in Normal file
View File

@ -0,0 +1 @@
4

1
Lab7/input/Test5.in Normal file
View File

@ -0,0 +1 @@
5

10
Lab7/output/Test1.out Normal file
View File

@ -0,0 +1,10 @@
[0, ?, ?, ?]
0
2
2
1
2
1
2
3
3

10
Lab7/output/Test2.out Normal file
View File

@ -0,0 +1,10 @@
[0, 1, ?, ?, ?, ?, ?, ?]
0
5
4
4
4
3
4
8
5

16
Lab7/output/Test3.out Normal file
View 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
View 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
View 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, ?, ?, ?, ?, ?, ?]