├── .gitattributes ├── .gitignore ├── HW6_CNN_example ├── mnist_example.py └── readme.md ├── Java ├── Java.tar.gz ├── jmm.jar ├── jmm │ ├── NullState.java │ ├── State.java │ ├── SwapTest.java │ ├── SynchronizedState.java │ └── UnsafeMemory.java └── readme.md ├── OCaml ├── hw1 │ ├── OCaml_Basics.ml │ ├── OCaml_Type_Inference.ml │ ├── currying │ │ ├── currying.ml │ │ ├── currying.s │ │ ├── no_currying.ml │ │ ├── no_currying.s │ │ └── readme.md │ ├── python_hint.py │ └── readme.md └── hw2 │ ├── 2006 │ ├── 2006_old_spec.pdf │ ├── hint_code.ml │ ├── readme.md │ └── sample_test.ml │ ├── Why_Acceptor.ml │ ├── grammar_converter_sample.ml │ ├── hw2_matcher2parser.py │ ├── hw2tree_hint.py │ ├── option.ml │ ├── pseudo_code.txt │ └── readme.md ├── Prolog ├── check_row_unique.pl ├── examples.pl ├── hello.pl ├── list2D_hint.pl ├── plain_domain.pl ├── readme.md ├── show_cut.pl ├── sudoku_cell.pl └── unique_list.pl ├── Python ├── aiohttp_example.py ├── asyncio_advanced.py ├── asyncio_basic.py ├── asyncio_context.py ├── asyncio_naive.py ├── asyncio_syntax.py ├── asyncio_task.py ├── dict_and_class.py ├── echo_client.py ├── echo_server.py ├── flooding_hint.py ├── json_hint.py ├── message_hint.py └── readme.md ├── Scheme ├── Xinyu_stronger_test_cases.rkt ├── hello.ss ├── readme.md └── starting_hint.ss ├── Xinyu_Interpreter ├── CPS_OCaml.ml ├── Generator_based_coroutine.py ├── OCaml_pl.pl ├── bfs.ml ├── dynamic_array_in_c99.c ├── dynamic_array_in_c99.s ├── prolog.rkt └── vaarg.c └── readme.md /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | t Byte-compiled / optimized / DLL files 2 | deps.txt 3 | archive 4 | saver 5 | *~ 6 | styles 7 | pngs 8 | preds 9 | 10 | *.sw* 11 | data 12 | __pycache__/ 13 | *.py[cod] 14 | *$py.class 15 | 16 | # C extensions 17 | *.so 18 | 19 | # Distribution / packaging 20 | .Python 21 | env/ 22 | build/ 23 | develop-eggs/ 24 | dist/ 25 | downloads/ 26 | eggs/ 27 | .eggs/ 28 | lib/ 29 | lib64/ 30 | parts/ 31 | sdist/ 32 | var/ 33 | *.egg-info/ 34 | .installed.cfg 35 | *.egg 36 | 37 | # PyInstaller 38 | # Usually these files are written by a python script from a template 39 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 40 | *.manifest 41 | *.spec 42 | 43 | # Installer logs 44 | pip-log.txt 45 | pip-delete-this-directory.txt 46 | 47 | # Unit test / coverage reports 48 | htmlcov/ 49 | .tox/ 50 | .coverage 51 | .coverage.* 52 | .cache 53 | nosetests.xml 54 | coverage.xml 55 | *,cover 56 | .hypothesis/ 57 | 58 | # Translations 59 | *.mo 60 | *.pot 61 | 62 | # Django stuff: 63 | *.log 64 | local_settings.py 65 | 66 | # Flask stuff: 67 | instance/ 68 | .webassets-cache 69 | 70 | # Scrapy stuff: 71 | .scrapy 72 | 73 | # Sphinx documentation 74 | docs/_build/ 75 | 76 | # PyBuilder 77 | target/ 78 | 79 | # IPython Notebook 80 | .ipynb_checkpoints 81 | 82 | # pyenv 83 | .python-version 84 | 85 | # celery beat schedule file 86 | celerybeat-schedule 87 | 88 | # dotenv 89 | .env 90 | 91 | # virtualenv 92 | venv/ 93 | ENV/ 94 | pypyvenv/ 95 | 96 | # Spyder project settings 97 | .spyderproject 98 | 99 | # Rope project settings 100 | .ropeproject 101 | 102 | # PyCharm 103 | .idea 104 | 105 | # checkpoint 106 | checkpoint 107 | 108 | ############# 109 | 110 | # VS Code 111 | .vscode 112 | 113 | # Mac 114 | *.DS_Store 115 | 116 | # Python 117 | *.pyc 118 | 119 | # pytest 120 | .pytest_cache 121 | 122 | # Racket 123 | *compiled/ 124 | *.o 125 | *.cmi 126 | *.cmx 127 | *.opt 128 | *.class 129 | -------------------------------------------------------------------------------- /HW6_CNN_example/mnist_example.py: -------------------------------------------------------------------------------- 1 | # adapted from https://github.com/pytorch/examples/blob/master/mnist/main.py 2 | import argparse 3 | import torch 4 | import torch.nn as nn 5 | import torch.nn.functional as F 6 | import torch.optim as optim 7 | from torchvision import datasets, transforms 8 | from torch.optim.lr_scheduler import StepLR 9 | import matplotlib.pyplot as plt 10 | 11 | 12 | class Net(nn.Module): 13 | def __init__(self): 14 | super(Net, self).__init__() 15 | self.conv1 = nn.Conv2d(1, 32, 3, 1) 16 | self.conv2 = nn.Conv2d(32, 64, 3, 1) 17 | self.dropout1 = nn.Dropout2d(0.25) 18 | self.dropout2 = nn.Dropout2d(0.5) 19 | self.fc1 = nn.Linear(9216, 128) 20 | self.fc2 = nn.Linear(128, 10) 21 | 22 | def forward(self, x): 23 | x = self.conv1(x) 24 | x = F.relu(x) 25 | x = self.conv2(x) 26 | x = F.max_pool2d(x, 2) 27 | x = self.dropout1(x) 28 | x = torch.flatten(x, 1) 29 | x = self.fc1(x) 30 | x = F.relu(x) 31 | x = self.dropout2(x) 32 | x = self.fc2(x) 33 | output = F.log_softmax(x, dim=1) 34 | return output 35 | 36 | def train(model, train_loader, optimizer, epoch, log_interval=10, debug=False): 37 | model.train() 38 | for batch_idx, (data, target) in enumerate(train_loader): 39 | optimizer.zero_grad() 40 | output = model(data) 41 | loss = F.nll_loss(output, target) 42 | loss.backward() 43 | optimizer.step() 44 | if batch_idx % log_interval == 0: 45 | print('\rTrain Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format( 46 | epoch, batch_idx * len(data), len(train_loader.dataset), 47 | 100. * batch_idx / len(train_loader), loss.item())) 48 | 49 | 50 | def test(model, test_loader, debug=False): 51 | model.eval() 52 | test_loss = 0 53 | correct = 0 54 | with torch.no_grad(): 55 | for data, target in test_loader: 56 | output = model(data) 57 | test_loss += F.nll_loss(output, target, reduction='sum').item() # sum up batch loss 58 | pred = output.argmax(dim=1, keepdim=True) # get the index of the max log-probability 59 | if debug: 60 | show_data(data, target) 61 | print("ground truth: {}".format(target.numpy().reshape(-1))) 62 | print("prediction: {}".format(pred.numpy().reshape(-1))) 63 | exit(0) 64 | correct += pred.eq(target.view_as(pred)).sum().item() 65 | 66 | test_loss /= len(test_loader.dataset) 67 | 68 | print('\nTest set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\n'.format( 69 | test_loss, correct, len(test_loader.dataset), 70 | 100. * correct / len(test_loader.dataset))) 71 | 72 | 73 | def show_data(data, target, show_row=2, show_col=3): 74 | fig = plt.figure() 75 | for i in range(show_row*show_col): 76 | plt.subplot(show_row, show_col,i+1) 77 | plt.tight_layout() 78 | plt.imshow(data[i][0], cmap='gray', interpolation='none') 79 | plt.title("Ground Truth: {}".format(target[i])) 80 | plt.xticks([]) 81 | plt.yticks([]) 82 | plt.show() 83 | 84 | def get_data_loader(train=False): 85 | data_loader = torch.utils.data.DataLoader( 86 | datasets.MNIST('./data', train=train, download=train, 87 | transform=transforms.Compose([ 88 | transforms.ToTensor(), 89 | # don't ask me the reason, these parameters are most oftenly used ... 90 | transforms.Normalize((0.1307,), (0.3081,)) 91 | ])), 92 | batch_size=64, shuffle=True) 93 | return data_loader 94 | 95 | def main(): 96 | # Training settings 97 | epochs = 2 98 | DEBUG = True 99 | 100 | train_loader = get_data_loader(train=True) 101 | test_loader = get_data_loader() 102 | 103 | model = Net() 104 | optimizer = optim.Adadelta(model.parameters(), lr=1.0) 105 | 106 | scheduler = StepLR(optimizer, step_size=1, gamma=0.7) 107 | for epoch in range(1, epochs + 1): 108 | train(model, train_loader, optimizer, epoch, debug=DEBUG) 109 | model.eval() 110 | test(model, test_loader, debug=DEBUG) 111 | scheduler.step() 112 | 113 | 114 | if __name__ == '__main__': 115 | main() 116 | 117 | 118 | -------------------------------------------------------------------------------- /HW6_CNN_example/readme.md: -------------------------------------------------------------------------------- 1 | # About HW3 Image Processing 2 | 3 | This is a Python example of image classification. 4 | 5 | To run it you have to install pytorch and matplotlib. 6 | 7 | After all requirements are satisfies, run: 8 | ```shell 9 | python mnist_example.py 10 | ``` -------------------------------------------------------------------------------- /Java/Java.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CS131-TA-team/UCLA_CS131_CodeHelp/2a1f582cb592a1e8727955d7addaeb5df60ba08e/Java/Java.tar.gz -------------------------------------------------------------------------------- /Java/jmm.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CS131-TA-team/UCLA_CS131_CodeHelp/2a1f582cb592a1e8727955d7addaeb5df60ba08e/Java/jmm.jar -------------------------------------------------------------------------------- /Java/jmm/NullState.java: -------------------------------------------------------------------------------- 1 | // This is a dummy implementation, useful for 2 | // deducing the overhead of the testing framework. 3 | class NullState implements State { 4 | private long[] value; 5 | NullState(int length) { value = new long[length]; } 6 | public int size() { return value.length; } 7 | public long[] current() { return value; } 8 | public void swap(int i, int j) { } 9 | } 10 | -------------------------------------------------------------------------------- /Java/jmm/State.java: -------------------------------------------------------------------------------- 1 | interface State { 2 | int size(); 3 | long[] current(); 4 | void swap(int i, int j); 5 | } 6 | -------------------------------------------------------------------------------- /Java/jmm/SwapTest.java: -------------------------------------------------------------------------------- 1 | import java.util.concurrent.ThreadLocalRandom; 2 | import java.lang.management.ThreadMXBean; 3 | 4 | class SwapTest implements Runnable { 5 | private long nTransitions; 6 | private State state; 7 | private ThreadMXBean bean; 8 | private long cputime; 9 | 10 | SwapTest(long n, State s, ThreadMXBean b) { 11 | nTransitions = n; 12 | state = s; 13 | bean = b; 14 | } 15 | 16 | public void run() { 17 | var n = state.size(); 18 | if (n <= 1) 19 | return; 20 | var rng = ThreadLocalRandom.current(); 21 | var id = Thread.currentThread().getId(); 22 | 23 | var start = bean.getThreadCpuTime(id); 24 | for (var i = nTransitions; 0 < i; i--) 25 | state.swap(rng.nextInt(0, n), rng.nextInt(0, n)); 26 | var end = bean.getThreadCpuTime(id); 27 | 28 | cputime = end - start; 29 | } 30 | 31 | public long cpuTime() { 32 | return cputime; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Java/jmm/SynchronizedState.java: -------------------------------------------------------------------------------- 1 | class SynchronizedState implements State { 2 | private long[] value; 3 | 4 | SynchronizedState(int length) { value = new long[length]; } 5 | 6 | public int size() { return value.length; } 7 | 8 | public long[] current() { return value; } 9 | 10 | public synchronized void swap(int i, int j) { 11 | value[i]--; 12 | value[j]++; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Java/jmm/UnsafeMemory.java: -------------------------------------------------------------------------------- 1 | import java.lang.management.ManagementFactory; 2 | 3 | class UnsafeMemory { 4 | public static void main(String args[]) { 5 | if (args.length != 4) 6 | usage(null); 7 | try { 8 | var nThreads = (int) argInt (args[1], 1, Integer.MAX_VALUE); 9 | var nTransitions = argInt (args[2], 0, Long.MAX_VALUE); 10 | var nValues = (int) argInt (args[3], 0, Integer.MAX_VALUE); 11 | State s; 12 | if (args[0].equals("Null")) 13 | s = new NullState(nValues); 14 | else if (args[0].equals("Synchronized")) 15 | s = new SynchronizedState(nValues); 16 | // else if (args[0].equals("Unsynchronized")) 17 | // s = new UnsynchronizedState(nValues); 18 | // else if (args[0].equals("AcmeSafe")) 19 | // s = new AcmeSafeState(nValues); 20 | else 21 | throw new Exception(args[0]); 22 | dowork(nThreads, nTransitions, s); 23 | test(s.current()); 24 | System.exit (0); 25 | } catch (Exception e) { 26 | usage(e); 27 | } 28 | } 29 | 30 | private static void usage(Exception e) { 31 | if (e != null) 32 | System.err.println(e); 33 | System.err.println("Usage: model nthreads ntransitions nvalues\n"); 34 | System.exit (1); 35 | } 36 | 37 | private static long argInt(String s, long min, long max) { 38 | var n = Long.parseLong(s); 39 | if (min <= n && n <= max) 40 | return n; 41 | throw new NumberFormatException(s); 42 | } 43 | 44 | private static void dowork(int nThreads, long nTransitions, State s) 45 | throws InterruptedException { 46 | var test = new SwapTest[nThreads]; 47 | var t = new Thread[nThreads]; 48 | var bean = ManagementFactory.getThreadMXBean(); 49 | bean.setThreadCpuTimeEnabled(true); 50 | for (var i = 0; i < nThreads; i++) { 51 | var threadTransitions = 52 | (nTransitions / nThreads 53 | + (i < nTransitions % nThreads ? 1 : 0)); 54 | test[i] = new SwapTest (threadTransitions, s, bean); 55 | t[i] = new Thread (test[i]); 56 | } 57 | var realtimeStart = System.nanoTime(); 58 | for (var i = 0; i < nThreads; i++) 59 | t[i].start (); 60 | for (var i = 0; i < nThreads; i++) 61 | t[i].join (); 62 | var realtimeEnd = System.nanoTime(); 63 | long realtime = realtimeEnd - realtimeStart, cputime = 0; 64 | for (var i = 0; i < nThreads; i++) 65 | cputime += test[i].cpuTime(); 66 | double dTransitions = nTransitions; 67 | System.out.format("Total time %g s real, %g s CPU\n", 68 | realtime / 1e9, cputime / 1e9); 69 | System.out.format("Average swap time %g ns real, %g ns CPU\n", 70 | realtime / dTransitions * nThreads, 71 | cputime / dTransitions); 72 | } 73 | 74 | private static void test(long[] output) { 75 | long osum = 0; 76 | for (var i = 0; i < output.length; i++) 77 | osum += output[i]; 78 | if (osum != 0) 79 | error("output sum mismatch", osum, 0); 80 | } 81 | 82 | private static void error(String s, long i, long j) { 83 | System.err.format("%s (%d != %d)\n", s, i, j); 84 | System.exit(1); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /Java/readme.md: -------------------------------------------------------------------------------- 1 | # About HW3: Java 2 | 3 | We don't have hint code for Java. And we don't think you need any hint code to get it done. For further information on the file format please visit [tutorial](https://docs.oracle.com/javase/tutorial/deployment/jar/index.html). For more on threads and locks [official language spec](https://docs.oracle.com/javase/specs/jls/se13/html/index.html) [Chapter 17](https://docs.oracle.com/javase/specs/jls/se13/html/jls-17.html) 4 | 5 | Xinyu provided [examples](./Java.tar.gz) to help you have a better understanding on Java objects. 6 | 7 | Remember **not** to include your name / ID in report. 8 | 9 | 10 | ## About the .jar format 11 | 12 | ### To Unzip the .jar file 13 | ```bash 14 | jar xf jmm.jar 15 | ``` 16 | Then you should see the *jmm* folder. 17 | 18 | ### To zip your solutions 19 | ```bash 20 | jar cvf jmmplus.jar *.java 21 | ``` 22 | 23 | ## Explanations of Requirements 24 | 25 | All in homework spec. 26 | 27 | From **UnsafeMemory** class you call all the remaining classes. Please uncomment line 16 to 19 in *UnsafeMemory.java* to make the options you implemented available for debugging and testing. 28 | 29 | ## To compile 30 | ```bash 31 | javac *.java 32 | ``` 33 | 34 | ## To run / test 35 | 36 | For your debugging purpose (just an example, you should try different parameters): 37 | ```bash 38 | java UnsafeMemory Synchronized 8 100000000 5 39 | ``` 40 | means run our **UnsafeMemory** java class with parameters: ```Synchronized 8 100000000 5```. 41 | - **SynchronizedState** implementation 42 | - divide the work into **8** threads of roughly equal size 43 | - do **100000000** swap transitions total 44 | - use a state array of **5** entries 45 | 46 | To test: 47 | ```bash 48 | time timeout 3600 java UnsafeMemory Synchronized 8 100000000 5 49 | ``` 50 | - **time**: use real, user and system time (a [discussion](https://blog.gceasy.io/2016/12/08/real-time-greater-than-user-and-sys-time/) might be useful for you to understand the time measurements) 51 | - **timeout 3600**: run ```java UnsafeMemory Synchronized 8 100000000 5``` and wait for **3600** seconds, such that it won't loop forever 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /OCaml/hw1/OCaml_Basics.ml: -------------------------------------------------------------------------------- 1 | (*** Fall 2019 Discussion B-1 2 | Code Provided by Xinyu Ma 3 | ***) 4 | 5 | (* OCaml basics *) 6 | 7 | (* ---------- basic data types ---------- *) 8 | 9 | let an_integer : int = 5;; 10 | (* Bind 5 to a global var `an_integer`, type is `int` *) 11 | 12 | (* type can be omitted *) 13 | (* `;;` can be omitted in a script *) 14 | let an_integer = 5 15 | (* val an_integer : int = 7 *) 16 | 17 | (* -- Basic_types *) 18 | let int_var : int = 5 19 | let float_var : float = 1. 20 | let bool_var : bool = true 21 | let char_var : char = '\n' 22 | let string_var : string = "string" 23 | let unit_var : uint = () (* something like `void` in C *) 24 | 25 | (* ---------- let ---------- *) 26 | 27 | (* 1. Write functions: let = *) 28 | let add_int x y = x + y 29 | (* val add_int : int -> int -> int = 30 | Meaning: add_int is a , which takes an int, and another int, 31 | and returns an int at last *) 32 | (* So if we feed two ints to it, we get *) 33 | let five = add_int 2 3 34 | (* val five : int = 5 *) 35 | 36 | let add_float x y = x +. y 37 | let five = add_float 2. 3. 38 | (* val add_float : float -> float -> float = 39 | Things related to float usually have a `.` in it. 40 | Integer: 2 + - * / mod 41 | Float: 2. +. -. *. /. ** 42 | But comparison work for both: < <= > >= = <> *) 43 | 44 | (* 2. Let expression: let = in *) 45 | let five = 46 | let x = 2 in 47 | add_int x 3 48 | 49 | (* We can do nested let *) 50 | let five = 51 | let x = 2 in 52 | let y = 3 in 53 | let ret = add_int x y in 54 | ret 55 | 56 | (* Variant 1: simultaneously *) 57 | let five = 58 | let anti_div x y = 59 | let y = x 60 | and x = y in 61 | x / y in 62 | anti_div 2 10 63 | (* Useful in defining mutually recursive func *) 64 | 65 | (* Variant 2: recursively *) 66 | let ten = 67 | let rec sum_up_to x = 68 | if x <> 0 (* if then else *) 69 | then x + sum_up_to (x - 1) 70 | else 0 in 71 | sum_up_to 4 72 | 73 | (* let is not assignment *) 74 | let ten = 75 | let x = 2 in (* Here x = 2 *) 76 | let y = 77 | let x = 3 in (* This is not good. x = 3 only affects inner env *) 78 | x + 4 in (* 3 + 4 *) 79 | 1 + x + y (* 1 + 2 + 7 *) 80 | 81 | (* ---------- list ---------- *) 82 | 83 | let one_to_five : int list = [1; 2; 3; 4; 5] 84 | (* val one_to_five : int list = [1; 2; 3; 4; 5] *) 85 | (* This is illegal: [1; 2.5] *) 86 | 87 | (* list is actually a linked list *) 88 | let one_to_five = 1::2::3::4::5::[] 89 | (* val one_to_five : int list = [1; 2; 3; 4; 5] *) 90 | 91 | let tail = List.tl one_to_five 92 | (* val tail : int list = [2; 3; 4; 5] *) 93 | 94 | let three = List.hd (List.tl (List.tl one_to_five)) 95 | 96 | let concat = List.length ([1; 2]@[3; 4]) 97 | (* val concat : int = 4 *) 98 | (* [1; 2]::[3; 4] is NG *) 99 | 100 | let map_exmaple = 101 | let lst = [1; 2; 3] in 102 | let double x = 2 * x in 103 | List.map double lst 104 | (* val map_exmaple : int list = [2; 4; 6] *) 105 | 106 | let filter_exmaple = 107 | let lst = [1; 2; 3; 4; 5; 6; 7] in 108 | List.filter (fun x -> x mod 2 = 0) lst (* anonymous func *) 109 | (* val filter_exmaple : int list = [2; 4; 6] *) 110 | 111 | let reduce_exmaple = 112 | let lst = [1; 2; 3; 4] in 113 | List.fold_left (fun x y -> x + y) 0 lst 114 | (* val reduce_exmaple : int = 10 *) 115 | (* let f x y = x + y in 116 | List.fold_left f 0 [1; 2; 3; 4] 117 | => f (f (f (f 0 1) 2) 3) 4 118 | => (((0 + 1) + 2) + 3) + 4 119 | => 10 120 | *) 121 | 122 | (* Reference site *) 123 | let list_module_desc = print_string "https://caml.inria.fr/pub/docs/manual-ocaml/libref/List.html" 124 | 125 | (*exercise 1*) 126 | let odd_sum_up_to num = 127 | let rec up_to x = 128 | if x = 0 then [] else x::(up_to (x - 1)) in 129 | let lst = up_to num in (* [1; 2; 3; 4; ...] *) 130 | let filtered_lst = List.filter (fun x -> x mod 2 = 1) lst in (* [1; 3; 5; ...] *) 131 | List.fold_left (fun x y -> x + y) 0 filtered_lst 132 | 133 | let rec odd_sum_up_to num = 134 | match num with 135 | | -1 -> 0 136 | | x -> 137 | if x mod 2 = 1 138 | then x + odd_sum_up_to (num - 2) 139 | else odd_sum_up_to (num - 1) 140 | 141 | (* ---------- match ---------- *) 142 | 143 | let tuple_exam : int * float * string = (1, 2., "3") 144 | (* val tuple_exam : int * float * string = (1, 2., "3") *) 145 | 146 | let match_exam = match (1, 2., "3") with 147 | | (0, x, _) -> x + 1. (* if first ele is 0, bind x to the second ele, and get x + 1 *) 148 | | (1, y, _) -> y (* if first ele is 1, bind y to the second ele, and get y *) 149 | | _ -> 0. (* match should be exhaustive *) 150 | 151 | (* match is done in order ^^The meaning of last example *) 152 | let match_exam = match (1, 2., "3") with 153 | | (fst, snd, trd) -> 154 | if fst = 0 then let x = snd in x + 1. (* | (0, x, _) -> x + 1. *) 155 | else 156 | if fst = 1 then let y = snd in y (* | (1, y, _) -> y + 1. *) 157 | else 158 | 0. (* | _ -> 0. *) 159 | 160 | (*exercise 2*) 161 | (* calculate sum {x=1 to N} x, x^2 and x^3 *) 162 | let sum_lsc n = 163 | let rec sum_lsc_aux i aux = 164 | if i > n then aux else 165 | match aux with 166 | | (s, s2, s3) -> 167 | sum_lsc_aux (i + 1) (s + i, s2 + i * i, s3 + i * i * i) in 168 | sum_lsc_aux 1 (0, 0, 0) 169 | 170 | (* ---------- enumarate ---------- *) 171 | 172 | type day_of_week = Sun | Mon | Tue | Wed | Thu | Fri | Sat 173 | let sun = Sun 174 | (* val sun : day_of_week = Sun *) 175 | 176 | (* Enum can take parameters, which works like a constructor *) 177 | type number = Int of int | Float of float 178 | let int_4 = Int 4 179 | and float_4 = Float 4. 180 | (* val int_4 : number = Int 4 181 | val float_4 : number = Float 4. *) 182 | 183 | type something = Something of int * float | Nothing 184 | 185 | let mixed_lst = [Int 1; Float 2.5] 186 | let rec float_sum lst = 187 | match lst with 188 | | [] -> 0. 189 | | (Int i)::rst -> float i +. float_sum rst 190 | | (Float f)::rst -> f +. float_sum rst 191 | let three_dot_five = float_sum mixed_lst 192 | (* val three_dot_five : float = 3.5 *) 193 | 194 | (*exercise 3*) 195 | let sum_of_mixed lst = 196 | let number_add x y = match x, y with 197 | | Int ia, Int ib -> Int (ia + ib) 198 | | Float fa, Int ib -> Float (fa +. float ib) 199 | | Int ia, Float fb -> Float (float ia +. fb) 200 | | Float fa, Float fb -> Float (fa +. fb) 201 | in 202 | List.fold_left number_add (Int 0) lst 203 | let int_ten = sum_of_mixed [Int 1; Int 2; Int 3; Int 4] 204 | let float_ten = sum_of_mixed [Int 1; Float 2.5; Int 3; Float 3.5] 205 | (* val sum_of_mixed : number list -> number = 206 | val int_ten : number = Int 10 207 | val float_ten : number = Float 10. *) 208 | 209 | (* ---------- grammar ---------- *) 210 | 211 | (* Remember to copy this *) 212 | type ('nonterminal, 'terminal) symbol = 213 | | N of 'nonterminal 214 | | T of 'terminal 215 | 216 | (* a terminal is a word directly used in a `final` sentence" *) 217 | let terminal_exmaple = 218 | let term1 = "1" in 219 | let term2 = "+" in 220 | let term3 = "2" in 221 | print_string "1+2" 222 | 223 | type nomterminal = Expr | Number | Operator 224 | (* a nonterminal is something like a category 225 | We don't write ` ` directly *) 226 | 227 | let rule_examples = 228 | let what = "a rule is used to replace a N to a sequence of symbol" in 229 | let exam1 = (N Number, (* -> *) [T "1"]) 230 | and exam2 = (N Number, (* -> *) [T "2"]) 231 | and exam3 = (N Operator, (* -> *) [T "+"]) 232 | and exam4 = (N Expr, (* -> *) [N Number; N Operator; N Number]) in 233 | [exam1; exam2; exam3; exam4] 234 | 235 | let derivation = 236 | let what = "use a rule to replace a nonterminal" in 237 | [[N Expr]; (* => *) 238 | [N Number; N Operator; N Number]; (* => *) 239 | [T "1"; N Operator; N Number]; (* => *) 240 | [T "1"; N Operator; T "2"]; (* => *) 241 | [T "1"; T "+"; T "2"]] 242 | 243 | let grammar = 244 | let what = "a starting nonterminal and a set of rules" in 245 | let starting_terminal = Expr 246 | and rule_set = rule_examples in 247 | starting_terminal, rule_set 248 | 249 | let language = 250 | let what = "any sentences that can be derived from the starting terminal by rules" in 251 | [[T "1"; T "+"; T "1"]; 252 | [T "1"; T "+"; T "2"]; 253 | [T "2"; T "+"; T "1"]; 254 | [T "2"; T "+"; T "2"]] 255 | -------------------------------------------------------------------------------- /OCaml/hw1/OCaml_Type_Inference.ml: -------------------------------------------------------------------------------- 1 | (*** Provided by Xinyu Ma ***) 2 | 3 | (* Type System *) 4 | 5 | (* ---------- type inference & currying ---------- *) 6 | 7 | let an_integer = 5 8 | (* val an_integer : int = 5 *) 9 | (* Why this type? 5 is an int *) 10 | 11 | let plus x y = x + y 12 | (* val plus : int -> int -> int = *) 13 | (* its type is 'int -> int -> int', which means 'take an int, take another int, and return an int' *) 14 | (* Why this type? (+) only works for int: *) 15 | 16 | let _ = (+) 17 | (* - : int -> int -> int = *) 18 | (* Here 'x + y' is a syntax suger for '(+) x y' *) 19 | 20 | (* 21 | Q1. What has a type? 22 | Every expression = variables + literals + functions + let/if/match/function-call/etc statement 23 | Exception: constructors (e.g. Some, (::)) 24 | 25 | Q2. How to know its type? 26 | Like a bidirection match. 27 | *) 28 | 29 | (* 30 | COND1 plus : int -> int -> int 31 | COND2 plus x y 32 | => x : int , y : int, (plus x y) : int 33 | *) 34 | 35 | (* -> is right associative *) 36 | (* 'int -> int -> int' = 'int -> (int -> int)' *) 37 | (* Take an int, and return a function that (take an int, and return an int) *) 38 | let plus_5 = plus 5 39 | (* val plus_5 : int -> int = *) 40 | let elf = plus_5 6 41 | (* val elf : int = 11 *) 42 | (* 43 | plus : int -> (int -> int) 44 | plus 5 : int -> int 45 | plus 5 6 : int 46 | *) 47 | 48 | (* 49 | Rule1: IF func:'a->'b AND arg:'a THEN (func arg):'b 50 | where 'a, 'b and 'c are type varibles. 51 | Remember this is a match, 52 | i.e.when we know the type of arg and (func arg), we can also infer func. 53 | *) 54 | 55 | let rec insert_n_int n (x: int) lst = 56 | if n = 0 then lst else x::(insert_n_int (n - 1) x lst) 57 | (* val insert_n_int : int -> int -> int list -> int list = *) 58 | (* 59 | insert_n_int : 'a -> int -> 'b -> 'c 60 | 61 | "n = 0" is equivalent to "(=) n 0" 62 | 1) (=): 'd -> 'd -> bool 63 | 2) n: 'a 64 | 1) 2) RULE1 => 65 | 3) 'a = 'd AND ((=) n): 'a -> bool 66 | 4) 0: int 67 | 3) 4) RULE1 => 68 | 5) 'a = int AND ((=) n 0): bool 69 | This method looks stupid but it's sure to give you a correct answer. 70 | 71 | (::) is a constructor for 'e list 72 | 1) (::): 'e -> 'e list -> 'e list (similar to a function, but it's not a function) 73 | 2) x: int 74 | 3) (insert_n_int (n - 1) x lst): 'c 75 | 1) 2) 3) RULE1 => 76 | 4) 'e = int AND 'c = int list AND (x::(insert_n_int (n - 1) x lst)): int list 77 | 78 | 79 | What's the rule for "if e1 then e2 else e3"? 80 | 81 | RULE2: IF e1: bool AND e2: 'a AND e3: 'a THEN (if e1 then e2 else e3): 'a 82 | 1) (n = 0): bool 83 | 2) lst: 'b 84 | 3) (x::(insert_n_int (n - 1) x lst)): int list 85 | 1) 2) 3) RULE2 => 86 | 4) 'b = int list AND (if ...): int list 87 | Actually (if ...) has the same type with 'c = int list. 88 | 89 | It's not easy to write down all RULEs, but you know the basic idea. 90 | *) 91 | 92 | (* ---------- polymorphism ---------- *) 93 | 94 | (* Some functions work for different types. 95 | We use ' to indicate a type var, which can be any type. 96 | Like 'a, 'b, 'terminal. 97 | *) 98 | let rec insert_n n x lst = 99 | if n = 0 then lst else x::(insert_n (n - 1) x lst) 100 | (* val insert_n_int : int -> 'a -> 'a list -> 'a list = *) 101 | (* Can 'a? be int? YES float? YES *) 102 | 103 | let _ = insert_n 3 0. [] 104 | (* - : float list = [0.; 0.; 0.] *) 105 | let _ = insert_n 3 4 [0; 1; 2] 106 | (* - : int list = [4; 4; 4; 0; 1; 2] *) 107 | (* let _ = insert_n 3 0. [0; 1; 2] *) 108 | (* Error: This expression has type int but an expression was expected of type float *) 109 | 110 | (* 'a can be ANY type, as long as x has the same type with elements in lst *) 111 | (* 112 | The compiler only gives 'a when it does not have any hint for an expression. 113 | There does not exist types such as "int or float". 114 | You have to define an enumerate for something like that: 115 | type number = Int of int | Float of float 116 | *) 117 | 118 | (* We can also have enumeratives with polymorphism *) 119 | type 'a option = Some of 'a | None 120 | let _ = Some 1 121 | (* - : int option = Some 1 *) 122 | (* 'int option' is similar to 'int list' *) 123 | let _ = None 124 | (* - : 'a option = None *) 125 | (* Here None is still a polymorphic value *) 126 | 127 | (* 128 | Note: 'a option != option. 129 | 'a option is a type 130 | int option is a type 131 | But option itself is not a type. 132 | *) 133 | 134 | (* Remember what we copied in HW1? *) 135 | type ('nonterminal, 'terminal) symbol = 136 | | N of 'nonterminal 137 | | T of 'terminal 138 | let _ = N 3 139 | (* - : (int, 'a) symbol = N 3 *) 140 | let _ = T "a" 141 | (* - : ('a, string) symbol = T "a" *) 142 | let _ = [N 3; T "a"] 143 | (* - : (int, string) symbol list = [N 3; T "a"] *) 144 | 145 | type 'a list2 = Empty | Cons of 'a * 'a list2 146 | (* This shows how the built-in list is defined *) 147 | 148 | (* Insert n x into lst if x has something; do nothing if x is None. *) 149 | let rec insert_n_option n x lst = 150 | match x with 151 | | _ when n = 0 -> lst 152 | | None -> lst 153 | | Some y -> y::(insert_n_option (n - 1) x lst) 154 | (* val insert_n_option : int -> 'a option -> 'a list -> 'a list = *) 155 | 156 | (* 157 | START WITH insert_n_option : 'a -> 'b -> 'c -> 'd (We want to solve 'a, 'b, 'c, 'd) 158 | 159 | COND1 n = 0 160 | COND2 (=) : 'e -> 'e -> bool (Forall 'e) 161 | => n : int, 'a = int 162 | => insert_n_option : int -> 'b -> 'c -> 'd 163 | 164 | COND1 match x with None 165 | COND2 None : 'f option (Forall 'f) 166 | => x : 'f option, 'b = 'f option 167 | 168 | COND1 insert_n_option _ _ lst = match _ with None -> lst 169 | => 'c = 'd 170 | 171 | COND1 match x with Some y 172 | COND2 x : 'f option 173 | => y : 'f 174 | 175 | COND1 y::(insert_n_option _ _ _) 176 | COND2 List.(::) : 'g -> 'g list -> 'g list (Forall 'g) 177 | COND3 y : 'f 178 | => (insert_n_option _ _ _) : 'f list, 'c = 'f list 179 | 180 | CONCLUSION 'a = int, 'b = 'f option, 'c = 'f list, 'd = 'f list 181 | insert_n_option : int -> 'f option -> 'f list -> 'f list (Forall 'f) 182 | *) 183 | 184 | (* RULE3: IF e: 'a AND case1: 'a AND ret1: 'b THEN (match e with case1 -> ret1): 'b 185 | Notice that which case is used can only be resolved at runtime. 186 | But the types of all expressions can be resolved during compiling. 187 | *) 188 | 189 | let _ = insert_n_option 3 (Some 1) [2; 3] 190 | (* - : int list = [1; 1; 1; 2; 3] *) 191 | let _ = insert_n_option 3 None [2; 3] 192 | (* - : int list = [2; 3] *) 193 | 194 | 195 | let f f = f (f None) 196 | (* val f : ('a option -> 'a option) -> 'a option = *) 197 | 198 | (* 199 | Functor: For a polymorphic type 'a T, if we define a map function of type 200 | fmap : ('a -> 'b) -> 'a T -> 'b T 201 | We can call ('a T, fmap) a functor. 202 | *) 203 | let _ = List.map 204 | (* - : ('a -> 'b) -> 'a list -> 'b list = *) 205 | let _ = List.map (fun x -> x >= 3) [1; 2; 3; 4] 206 | (* - : bool list = [false; false; true; true] *) 207 | 208 | let opt_map f a = 209 | match a with 210 | | Some x -> Some (f x) 211 | | None -> None 212 | (* val opt_map : ('a -> 'b) -> 'a option -> 'b option = *) 213 | let _ = List.map (opt_map @@ (+) 1) [Some 1; None; Some 3; None] 214 | (* - : int option list = [Some 2; None; Some 4; None] *) 215 | 216 | (* ---------- imperfect type inference ---------- *) 217 | 218 | (* Type systems has its limitations. Not all correct program can pass the type checking *) 219 | 220 | let get_some x = Some x 221 | (* val get_some : 'a -> 'a option = *) 222 | let p = get_some false, get_some 1.5 223 | (* val p : bool option * float option = (Some false, Some 1.5) *) 224 | (* let p some = some false, some 1.5 *) 225 | (* Error: This expression has type float but an expression was expected of type bool *) 226 | 227 | (* Why the 2nd p doesn't work? *) 228 | (* 229 | COND1 false : bool 230 | COND2 some false 231 | => some : bool -> 'a 232 | 233 | COND1 1.5 : float 234 | COND2 some 1.5 235 | COND3 some : bool -> 'c 236 | => ERROR 237 | *) 238 | (* let p (some : ('a -> 'a option)) : bool option * float option = some false, some 1.5;; *) 239 | (* Conclusion: An argument cannot be a considered as a polymorphic function *) 240 | 241 | 242 | let insert_twice_1 = insert_n 2 243 | (* val insert_twice_1 : '_weak1 -> '_weak1 list -> '_weak1 list = *) 244 | (* We may expect it to be 'a -> 'a list -> 'a list, but what is '_weak1? *) 245 | 246 | let _ = insert_twice_1 1 [2; 3] 247 | (* - : int list = [1; 1; 2; 3] *) 248 | (* insert_twice_1 1. [2.; 3.];; *) 249 | (* This expression has type float but an expression was expected of type int *) 250 | let _ = insert_twice_1 251 | (* - : int -> int list -> int list = *) 252 | (* Weak is bound to int after last function call *) 253 | 254 | (* This is because mutability is allowed in OCaml. To avoid troubles, function calls cannot be polymorphic *) 255 | (* Let's just remind OCaml that insert_twice is a function, not only a partial application *) 256 | let insert_twice_2 x = insert_n 2 x 257 | (* val insert_twice_2 : 'a -> 'a list -> 'a list = *) 258 | (* Conclusion: A function can be polymorphic but a partial application cannot *) 259 | 260 | (* More examples *) 261 | let id x = x 262 | (* val id : 'a -> 'a = *) 263 | let s = id (fun _ -> "") 264 | (* val s : '_weak3 -> string = *) 265 | let s x = id (fun _ -> "") x 266 | (* val s : 'a -> string = *) 267 | 268 | let p x = id id x 269 | (* val p : 'a -> 'a = *) 270 | (* let p f x = f f x *) 271 | (* Error: This expression has type 'a -> 'b -> 'c 272 | but an expression was expected of type 'a 273 | The type variable 'a occurs inside 'a -> 'b -> 'c *) 274 | 275 | (* ---------- recursive types ---------- *) 276 | 277 | type 'a bst = Node of 'a * 'a bst option * 'a bst option 278 | 279 | let leaf x = Node (x, None, None) 280 | (* val leaf : 'a -> 'a bst = *) 281 | let tree = Node (4, Some (Node (2, Some (leaf 1), Some (leaf 3))), 282 | Some (Node (6, Some (leaf 5), Some (leaf 7)))) 283 | 284 | let infix_travel t = 285 | let rec infix_travel_aux = function 286 | | Some (Node (v, l, r)) -> (infix_travel_aux l) @ (v::(infix_travel_aux r)) 287 | | None -> [] in 288 | infix_travel_aux (Some t) 289 | (* val infix_travel : 'a bst -> 'a list = *) 290 | let _ = infix_travel tree 291 | (* - : int list = [1; 2; 3; 4; 5; 6; 7] *) 292 | 293 | (* ---------- calculator ---------- *) 294 | 295 | type math_term = Add | Sub | Mul | Div | Num of int 296 | 297 | (* 298 | Assume start symbol is Expr. Let's define the rules. 299 | 300 | Ver1: 301 | Expr ::= Expr + Expr | Expr - Expr | Expr * Expr | Expr + Expr | (Expr) 302 | 303 | There is ambiguity -- what about the order? 304 | 305 | Ver2: 306 | Expr ::= Expr + Term | Expr - Term | Term 307 | Term ::= Term * Factor | Term / Factor | Factor 308 | Factor ::= number | (Expr) 309 | 310 | Another issue is left recursion. So the top-down algorithm will run into an infinite loop. 311 | 312 | Ver3: 313 | Expr ::= Term ExprRest 314 | ExprRest ::= + Term ExprRest | - Term ExprRest | ø 315 | Term ::= Factor TermRest 316 | TermRest ::= + Factor TermRest | - Factor TermRest | ø 317 | Factor ::= number | (Expr) 318 | *) 319 | -------------------------------------------------------------------------------- /OCaml/hw1/currying/currying.ml: -------------------------------------------------------------------------------- 1 | let plus x y = x + y;; -------------------------------------------------------------------------------- /OCaml/hw1/currying/currying.s: -------------------------------------------------------------------------------- 1 | .file "" 2 | .data 3 | .globl _camlCurrying__data_begin 4 | _camlCurrying__data_begin: 5 | .text 6 | .globl _camlCurrying__code_begin 7 | _camlCurrying__code_begin: 8 | nop 9 | .data 10 | .align 3 11 | .quad 1792 12 | .globl _camlCurrying 13 | _camlCurrying: 14 | .quad 1 15 | .data 16 | .align 3 17 | .globl _camlCurrying__gc_roots 18 | _camlCurrying__gc_roots: 19 | .quad _camlCurrying 20 | .quad 0 21 | .text 22 | .align 4 23 | .globl _camlCurrying__plus_80 24 | _camlCurrying__plus_80: 25 | .cfi_startproc 26 | L100: 27 | leaq -1(%rax,%rbx), %rax 28 | ret 29 | .cfi_endproc 30 | .data 31 | .align 3 32 | .quad 4087 33 | _camlCurrying__1: 34 | .quad _caml_curry2 35 | .quad 5 36 | .quad _camlCurrying__plus_80 37 | .text 38 | .align 4 39 | .globl _camlCurrying__entry 40 | _camlCurrying__entry: 41 | .cfi_startproc 42 | L101: 43 | leaq _camlCurrying__1(%rip), %rax 44 | movq %rax, _camlCurrying(%rip) 45 | movq $1, %rax 46 | ret 47 | .cfi_endproc 48 | .data 49 | .align 3 50 | .text 51 | nop 52 | .globl _camlCurrying__code_end 53 | _camlCurrying__code_end: 54 | .data 55 | /* relocation table start */ 56 | .align 3 57 | /* relocation table end */ 58 | .data 59 | .quad 0 60 | .globl _camlCurrying__data_end 61 | _camlCurrying__data_end: 62 | .quad 0 63 | .align 3 64 | .globl _camlCurrying__frametable 65 | _camlCurrying__frametable: 66 | .quad 0 67 | -------------------------------------------------------------------------------- /OCaml/hw1/currying/no_currying.ml: -------------------------------------------------------------------------------- 1 | let plus (x, y) = x + y;; -------------------------------------------------------------------------------- /OCaml/hw1/currying/no_currying.s: -------------------------------------------------------------------------------- 1 | .file "" 2 | .data 3 | .globl _camlNo_currying__data_begin 4 | _camlNo_currying__data_begin: 5 | .text 6 | .globl _camlNo_currying__code_begin 7 | _camlNo_currying__code_begin: 8 | nop 9 | .data 10 | .align 3 11 | .quad 1792 12 | .globl _camlNo_currying 13 | _camlNo_currying: 14 | .quad 1 15 | .data 16 | .align 3 17 | .globl _camlNo_currying__gc_roots 18 | _camlNo_currying__gc_roots: 19 | .quad _camlNo_currying 20 | .quad 0 21 | .text 22 | .align 4 23 | .globl _camlNo_currying__plus_80 24 | _camlNo_currying__plus_80: 25 | .cfi_startproc 26 | L100: 27 | leaq -1(%rax,%rbx), %rax 28 | ret 29 | .cfi_endproc 30 | .data 31 | .align 3 32 | .quad 4087 33 | _camlNo_currying__1: 34 | .quad _caml_tuplify2 35 | .quad -3 36 | .quad _camlNo_currying__plus_80 37 | .text 38 | .align 4 39 | .globl _camlNo_currying__entry 40 | _camlNo_currying__entry: 41 | .cfi_startproc 42 | L101: 43 | leaq _camlNo_currying__1(%rip), %rax 44 | movq %rax, _camlNo_currying(%rip) 45 | movq $1, %rax 46 | ret 47 | .cfi_endproc 48 | .data 49 | .align 3 50 | .text 51 | nop 52 | .globl _camlNo_currying__code_end 53 | _camlNo_currying__code_end: 54 | .data 55 | /* relocation table start */ 56 | .align 3 57 | /* relocation table end */ 58 | .data 59 | .quad 0 60 | .globl _camlNo_currying__data_end 61 | _camlNo_currying__data_end: 62 | .quad 0 63 | .align 3 64 | .globl _camlNo_currying__frametable 65 | _camlNo_currying__frametable: 66 | .quad 0 67 | -------------------------------------------------------------------------------- /OCaml/hw1/currying/readme.md: -------------------------------------------------------------------------------- 1 | # An Early Start on Currying 2 | 3 | This is a simple OCaml currying example showing how it works & how to check OCaml assembly. 4 | 5 | ## Generate Assembly Code 6 | 7 | First you get your source code files ready, say, ```currying.ml``` and ```no_currying.ml```. 8 | 9 | Then you run: 10 | 11 | ```shell 12 | ocamlopt -S -inline 20 -nodynlink currying.ml -o currying.opt 13 | ocamlopt -S -inline 20 -nodynlink no_currying.ml -o no_currying.opt 14 | ``` 15 | 16 | And check the ```currying.s``` and ```no_currying.s``` files. -------------------------------------------------------------------------------- /OCaml/hw1/python_hint.py: -------------------------------------------------------------------------------- 1 | ######################################################################## 2 | # For whoever new to Python: 3 | # you may use this as pseudo code 4 | # it is not mandatory to use hint code 5 | # Usage: 6 | # python python_hint.py 7 | # To all students: 8 | # try implementing everything **without** the help from hint-code first 9 | # 10 | # Fall 2019 by Patricia Xiao 11 | ######################################################################## 12 | 13 | from math import * 14 | 15 | def subset(a, b): 16 | ''' 17 | check if a is a subset of b 18 | parameters: 19 | a: list (representing a set) 20 | b: list 21 | return: 22 | boolean 23 | sample usage: subset([1,2], [1,2,3,4,5]) 24 | # output: True 25 | ''' 26 | if len(a) == 0: 27 | return True 28 | else: 29 | if a[0] not in b: 30 | return False 31 | else: 32 | return subset(a[1:], b) 33 | 34 | def equal_sets(a, b): 35 | ''' 36 | check if the sets represented by two lists are equivalent 37 | parameters: 38 | a: list 39 | b: list 40 | return: 41 | boolean 42 | sample usage: equal_sets([1,2,3,4,5], [1,1,1,1,1,2,3,4,5]) 43 | # output: True 44 | ''' 45 | return subset(a, b) and subset(b, a) 46 | 47 | def set_diff(a, b): 48 | ''' 49 | parameters: 50 | a: list 51 | b: list 52 | return: 53 | a - b (as set) 54 | sample usage: set_diff([1,2,3,4,5], [1,2]) 55 | # output: [3, 4, 5] 56 | ''' 57 | if len(a) == 0: 58 | return [] 59 | else: 60 | if a[0] in b: 61 | return set_diff(a[1:], b) 62 | else: 63 | return [a[0]] + set_diff(a[1:], b) 64 | 65 | def set_union(a, b): 66 | ''' 67 | parameters: 68 | a: list 69 | b: list 70 | return: 71 | boolean 72 | sample usage: set_union([1,2], [3, 4]) 73 | # output: [1, 2, 3, 4] 74 | ''' 75 | return a + set_diff(b, a) 76 | 77 | def computed_fixed_point(eq, f, x): 78 | ''' 79 | parameters: 80 | eq: a function (predicate) determining whether or not two inputs are equal 81 | f: the target function to compute the fixed point for 82 | x: the starting point of computing fixed point 83 | return: the computed fixed point for f with respect to x, 84 | assuming that eq is the equality predicate for f's domain 85 | sample usage: 86 | computed_fixed_point((lambda x, y: x == y), (lambda x: x / 2 + 0.5), 1) 87 | # outputs: 1 88 | ''' 89 | if eq(f(x), x): 90 | return x 91 | else: 92 | return computed_fixed_point(eq, f, f(x)) 93 | 94 | class symbol: 95 | def __init__(self, _type, _val): 96 | assert(_type in ['T', 'N']) 97 | self.type = _type 98 | self.value = _val 99 | def __call__(self): 100 | return self.value 101 | def __repr__(self): 102 | return "symbol {}: {}".format(self.type, self.value) 103 | def __eq__(self, other): 104 | return self.value == other.value and self.type == other.type 105 | 106 | sample_rules = [ 107 | (symbol('N', 'Expr'), [symbol('T', "("), symbol('N', 'Expr'), symbol('T',")")]), 108 | (symbol('N', 'Expr'), [symbol('N', 'Num')]), 109 | (symbol('N', 'Expr'), [symbol('N', 'Expr'), symbol('N', 'Binop'), symbol('N', 'Expr')]), 110 | (symbol('N', 'Expr'), [symbol('N', 'Lvalue')]), 111 | (symbol('N', 'Expr'), [symbol('N', 'Incrop'), symbol('N', 'Lvalue')]), 112 | (symbol('N', 'Expr'), [symbol('N', 'Lvalue'), symbol('N', 'Incrop')]), 113 | (symbol('N', 'Lvalue'), [symbol('T', "$"), symbol('N', 'Expr')]), 114 | (symbol('N', 'Incrop'), [symbol('T', "++")]), 115 | (symbol('N', 'Incrop'), [symbol('T', "--")]), 116 | (symbol('N', 'Binop'), [symbol('T',"+")]), 117 | (symbol('N', 'Binop'), [symbol('T',"-")]), 118 | (symbol('N', 'Num'), [symbol('T', "0")]), 119 | (symbol('N', 'Num'), [symbol('T', "1")]), 120 | (symbol('N', 'Num'), [symbol('T', "2")]), 121 | (symbol('N', 'Num'), [symbol('T', "3")]), 122 | (symbol('N', 'Num'), [symbol('T', "4")]), 123 | (symbol('N', 'Num'), [symbol('T', "5")]), 124 | (symbol('N', 'Num'), [symbol('T', "6")]), 125 | (symbol('N', 'Num'), [symbol('T', "7")]), 126 | (symbol('N', 'Num'), [symbol('T', "8")]), 127 | (symbol('N', 'Num'), [symbol('T', "9")])] 128 | 129 | sample_grammar = (symbol('N', 'Expr'), sample_rules[2:]) 130 | 131 | 132 | def equal_second_elem_sets(a, b): 133 | return equal_sets(a[1], b[1]) 134 | 135 | def get_reachable_symbols(params): 136 | rules, reachable_symbols = params 137 | if len(rules) == 0: 138 | return (rules, reachable_symbols) 139 | else: 140 | tmp_rule = rules[0] 141 | rest_rules = rules[1:] 142 | tmp_symbol = tmp_rule[0] 143 | right_hand_side = tmp_rule[1] 144 | if tmp_symbol in reachable_symbols: 145 | nonterminal = list(filter(lambda s: s.type == 'N', right_hand_side)) 146 | return get_reachable_symbols((rest_rules, set_union(reachable_symbols, nonterminal))) 147 | else: 148 | return get_reachable_symbols((rest_rules, reachable_symbols)) 149 | 150 | 151 | def filter_reachable(g): 152 | ''' 153 | keep only the reachable rules in grammar g 154 | parameters: 155 | g: a pair, first element is a symbol, second element is a list of rules 156 | return: 157 | grammar after filtered the symbols 158 | sample usage: filter_reachable(sample_grammar) 159 | ''' 160 | start_symbol = g[0] 161 | rules = g[1] 162 | # step 1: find the reachable symbols 163 | _, reachable_symbols = computed_fixed_point(equal_second_elem_sets, get_reachable_symbols, (rules, [start_symbol])) 164 | # step 2: filter the rules 165 | filtered_rules = list(filter(lambda r: r[0] in reachable_symbols, rules)) 166 | return (start_symbol, filtered_rules) 167 | 168 | 169 | if __name__ == '__main__': 170 | print(filter_reachable(sample_grammar)) 171 | -------------------------------------------------------------------------------- /OCaml/hw1/readme.md: -------------------------------------------------------------------------------- 1 | # Hint Code for OCaml HW1 2 | 3 | ## About this hint (and all the future hint code in CS131) 4 | * It is **NOT MANDATORY** to use hint code, we encourage independent thinking. 5 | * **WARNING**: if you "strictly follow" the hint code, you'll **never** reach the solution, and you'll have **a lot of problem with OCaml variable types**. It is **only** good for telling you the logic. **It is a tragedy if you do translation.** 6 | * Don't take us wrong, hint code is not something you use to translate into your solution. 7 | * Try to design your own solution first, and get some inspirations from hint code whenever get stucked. 8 | * Solving HW1 independently will be super helpful when you move on to HW2. 9 | * You need to get yourself familiarized with **functional programming** style sooner (HW1) or later (HW2). 10 | * HW2 is much harder than & closely related to HW1, and is widely-known as the hardest homework in CS131. Working on HW1 independently will increase your chance of survival in HW2, and the rest of this course. 11 | * Many students decided to drop after the deadline of HW2. 12 | 13 | ## OCaml Starter Resource 14 | * [The Official Website](https://ocaml.org/) 15 | * [Installation Guide](https://ocaml.org/docs/install.html) 16 | * Installing locally on your own machine will help you work on it easier. 17 | * [The OCaml Manual](https://caml.inria.fr/pub/docs/manual-ocaml/libref/index.html) 18 | * Special requirements in **HW1**: only library functions in [Pervasives](https://caml.inria.fr/pub/docs/manual-ocaml/libref/Pervasives.html) and in [List](https://caml.inria.fr/pub/docs/manual-ocaml/libref/List.html) are allowed. 19 | * An [online interpreter](https://try.ocamlpro.com/) to play with. 20 | * But this is an outdated version of OCaml, we use more recent versions. 21 | * Xinyu provided code for [OCaml Basics](./OCaml_Vasics.ml) and [Type Inference](./OCaml_Type_Inference.ml). You may run it line by line to get yourself started with OCaml. 22 | * Some [hints](./python_hint.py) are provided in Python. If you don't know Python you can use it as pseudo-code. 23 | 24 | ## Currying 25 | * It is not required to understand currying in HW1, but if you are curious, please check for official explanation of [currying](https://ocaml.org/learn/tutorials/functional_programming.html#Partial-function-applications-and-currying), and also see if [this](./currying/) helps. 26 | * Currying will be covered in your midterm & final. -------------------------------------------------------------------------------- /OCaml/hw2/2006/2006_old_spec.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CS131-TA-team/UCLA_CS131_CodeHelp/2a1f582cb592a1e8727955d7addaeb5df60ba08e/OCaml/hw2/2006/2006_old_spec.pdf -------------------------------------------------------------------------------- /OCaml/hw2/2006/hint_code.ml: -------------------------------------------------------------------------------- 1 | (* DNA fragment analyzer. *) 2 | 3 | type nucleotide = A | C | G | T 4 | type fragment = nucleotide list 5 | type acceptor = fragment -> fragment option 6 | type matcher = fragment -> acceptor -> fragment option 7 | 8 | type pattern = 9 | | Frag of fragment 10 | | List of pattern list 11 | | Or of pattern list 12 | | Junk of int 13 | | Closure of pattern 14 | (*| Eager of pattern*) (* not included in the hint code 2006 *) 15 | 16 | let match_empty frag accept = accept frag 17 | 18 | let match_nothing frag accept = None 19 | 20 | let rec match_junk k frag accept = 21 | match accept frag with 22 | | None -> 23 | (if k = 0 24 | then None 25 | else match frag with 26 | | [] -> None 27 | | _::tail -> match_junk (k - 1) tail accept) 28 | | ok -> ok 29 | 30 | let rec match_star matcher frag accept = 31 | match accept frag with 32 | | None -> 33 | matcher frag 34 | (fun frag1 -> 35 | if frag == frag1 36 | then None 37 | else match_star matcher frag1 accept) 38 | | ok -> ok 39 | 40 | let match_nucleotide nt frag accept = 41 | match frag with 42 | | [] -> None 43 | | n::tail -> if n == nt then accept tail else None 44 | 45 | let append_matchers matcher1 matcher2 frag accept = 46 | matcher1 frag (fun frag1 -> matcher2 frag1 accept) 47 | 48 | let make_appended_matchers make_a_matcher ls = 49 | let rec mams = function 50 | | [] -> match_empty 51 | | head::tail -> append_matchers (make_a_matcher head) (mams tail) 52 | in mams ls 53 | 54 | let rec make_or_matcher make_a_matcher = function 55 | | [] -> match_nothing 56 | | head::tail -> 57 | let head_matcher = make_a_matcher head 58 | and tail_matcher = make_or_matcher make_a_matcher tail 59 | in fun frag accept -> 60 | let ormatch = head_matcher frag accept 61 | in match ormatch with 62 | | None -> tail_matcher frag accept 63 | | _ -> ormatch 64 | 65 | let rec make_matcher = function 66 | | Frag frag -> make_appended_matchers match_nucleotide frag 67 | | List pats -> make_appended_matchers make_matcher pats 68 | | Or pats -> make_or_matcher make_matcher pats 69 | | Junk k -> match_junk k 70 | | Closure pat -> match_star (make_matcher pat) -------------------------------------------------------------------------------- /OCaml/hw2/2006/readme.md: -------------------------------------------------------------------------------- 1 | # 2006 Hint 2 | 3 | ## To Run 4 | 5 | - open ocaml toplevel by ```ocaml``` command 6 | - inside the topelevel type ```#use "hint_code.ml";;``` 7 | - then followed by ```#use "sample_test.ml";;``` -------------------------------------------------------------------------------- /OCaml/hw2/2006/sample_test.ml: -------------------------------------------------------------------------------- 1 | (* Fragments. *) 2 | 3 | let frag0 = [] 4 | 5 | let frag1 = [A;T;G;C;T;A] 6 | 7 | (* OCaml does not care about the newlines in the definition of frag2. 8 | From OCaml's point of view, they are merely extra white space that 9 | is ignored. The newlines are present only to help humans understand 10 | how the patterns defined below are matched against frag2. *) 11 | let frag2 = [C;C;C;G;A;T;A;A;A;A;A;A;G;T;G;T;C;G;T; 12 | A; 13 | A;G;T;A;T;A;T;G;G;A;T;A; 14 | T;A; 15 | A;G;T;A;T;A;T;G;G;A;T;A; 16 | C;G;A;T;C;C;C;T;C;G;A;T;C;T;A] 17 | 18 | let frag3 = [A;G;A;G;A;G] 19 | 20 | (* Patterns. *) 21 | 22 | let pat1 = Frag [A;T;G;C] 23 | let pat2 = Or [Frag [A;G;T;A;T;A;T;G;G;A;T;A]; 24 | Frag [G;T;A;G;G;C;C;G;T]; 25 | Frag [C;C;C;G;A;T;A;A;A;A; 26 | A;A;G;T;G;T;C;G;T]; 27 | List [Frag [C;G;A;T;C;C;C]; 28 | Junk 1; 29 | Frag [C;G;A;T;C;T;A]]] 30 | let pat3 = List [pat2; Junk 2] 31 | let pat4 = Closure pat3 32 | let pat5 = Closure (Frag [A]) 33 | let pat6 = Closure (Frag [A;G]) 34 | (*let pat7 = Eager (List [pat5; pat6])*) 35 | let pat8 = List [pat5; pat6] 36 | 37 | (* Matchers. *) 38 | let matcher1 = make_matcher pat1 39 | let matcher2 = make_matcher pat2 40 | let matcher3 = make_matcher pat3 41 | let matcher4 = make_matcher pat4 42 | let matcher5 = make_matcher pat5 43 | let matcher6 = make_matcher pat6 44 | (*let matcher7 = make_matcher pat7*) 45 | let matcher8 = make_matcher pat8 46 | 47 | (* Acceptors. *) 48 | 49 | (* Always fail, i.e., never accept a match. *) 50 | let accept_none x = None 51 | 52 | (* Always succeed. This acceptor returns the suffix 53 | containing all the symbols that were not matched. 54 | It causes the matcher to return the unmatched suffix. *) 55 | let accept_all x = Some x 56 | 57 | (* Accept only the empty fragment. *) 58 | let accept_empty = function 59 | | [] -> Some [] 60 | | _ -> None 61 | 62 | 63 | (* Test cases. These should all be true. *) 64 | 65 | let test1 = matcher1 frag0 accept_all = None 66 | let test2 = matcher1 frag1 accept_none = None 67 | 68 | (* A match must always match an entire prefix of a fragment. 69 | So, even though matcher1 finds a match in frag1, 70 | it does not find the match in A::frag1. *) 71 | let test3 = matcher1 frag1 accept_all = Some [T;A] 72 | let test4 = matcher1 (A::frag1) accept_all = None 73 | 74 | let test4 = matcher2 frag1 accept_all = None 75 | let test5 = 76 | (matcher2 frag2 accept_all 77 | = Some [A; 78 | A;G;T;A;T;A;T;G;G;A;T;A; 79 | T;A; 80 | A;G;T;A;T;A;T;G;G;A;T;A; 81 | C;G;A;T;C;C;C;T;C;G;A;T;C;T;A]) 82 | 83 | (* These matcher calls match the same prefix, 84 | so they return unmatched suffixes that are ==. *) 85 | let test6 = 86 | match (matcher2 frag2 accept_all, 87 | matcher3 frag2 accept_all) 88 | with 89 | | (Some fraga, Some fragb) -> fraga == fragb 90 | | _ -> false 91 | 92 | (* matcher4 is lazy: it matches the empty fragment first, 93 | but you can force it to backtrack by insisting on progress. *) 94 | let test7 = 95 | match matcher4 frag2 accept_all with 96 | | Some frag -> frag == frag2 97 | | _ -> false 98 | let test8 = 99 | match (matcher2 frag2 accept_all, 100 | matcher4 frag2 101 | (fun frag -> 102 | if frag == frag2 then None else Some frag)) 103 | with 104 | | (Some fraga, Some fragb) -> fraga == fragb 105 | | _ -> false 106 | let test9 = matcher4 frag2 accept_empty = Some [] 107 | 108 | let test10 = matcher5 frag3 accept_all = Some frag3 109 | let test11 = matcher6 frag3 accept_all = Some frag3 110 | (*let test12 = matcher7 frag3 accept_all = Some [G; A; G; A; G]*) 111 | let test13 = matcher8 frag3 accept_all = Some frag3 112 | -------------------------------------------------------------------------------- /OCaml/hw2/Why_Acceptor.ml: -------------------------------------------------------------------------------- 1 | (*** Provided by Xinyu ***) 2 | 3 | (* Homework 2 *) 4 | 5 | (* ---------- convert_grammar ---------- *) 6 | 7 | type ('nonterminal, 'terminal) symbol = 8 | | N of 'nonterminal 9 | | T of 'terminal 10 | 11 | type awksub_nonterminals = 12 | | Expr | Term | Lvalue | Incrop | Binop | Num 13 | 14 | (* This is the grammar from HW1 (but take a Term out) *) 15 | let old_awkish_grammar = Expr, 16 | [Expr, [N Term; N Binop; N Expr]; 17 | Expr, [N Term]; 18 | Term, [N Num]; 19 | Term, [N Lvalue]; 20 | Term, [N Incrop; N Lvalue]; 21 | Term, [N Lvalue; N Incrop]; 22 | Term, [T"("; N Expr; T")"]; 23 | Lvalue, [T"$"; N Expr]; 24 | Incrop, [T"++"]; 25 | Incrop, [T"--"]; 26 | Binop, [T"+"]; 27 | Binop, [T"-"]; 28 | Num, [T"0"]; 29 | Num, [T"1"]; 30 | Num, [T"2"]; 31 | Num, [T"3"]; 32 | Num, [T"4"]; 33 | Num, [T"5"]; 34 | Num, [T"6"]; 35 | Num, [T"7"]; 36 | Num, [T"8"]; 37 | Num, [T"9"]] 38 | 39 | (* This is the same grammar used in HW2 *) 40 | let awkish_grammar = 41 | (Expr, 42 | function (* The rules list is a function: 'nonterm -> ('nonterm, 'term) symbol list list 43 | ^ ^ ^ 44 | | | | 45 | | A rule is a sequence of symbols | 46 | | Alternative list is all possible rules' rhs 47 | All rules with the same lhs are merged *) 48 | | Expr -> 49 | [[N Term; N Binop; N Expr]; (* Expr, [N Term; N Binop; N Expr] *) 50 | [N Term]] (* Expr, [N Term] *) 51 | | Term -> 52 | [[N Num]; 53 | [N Lvalue]; 54 | [N Incrop; N Lvalue]; 55 | [N Lvalue; N Incrop]; 56 | [T"("; N Expr; T")"]] 57 | | Lvalue -> 58 | [[T"$"; N Expr]] 59 | | Incrop -> 60 | [[T"++"]; 61 | [T"--"]] 62 | | Binop -> 63 | [[T"+"]; 64 | [T"-"]] 65 | | Num -> 66 | [[T"0"]; [T"1"]; [T"2"]; [T"3"]; [T"4"]; 67 | [T"5"]; [T"6"]; [T"7"]; [T"8"]; [T"9"]]) 68 | 69 | (* ---------- parse_tree_leaves ---------- *) 70 | 71 | type ('nonterminal, 'terminal) parse_tree = 72 | | Node of 'nonterminal * ('nonterminal, 'terminal) parse_tree list 73 | | Leaf of 'terminal 74 | 75 | (* This is an example of expression tree, but it's not a parsing tree *) 76 | let expr_tree = Node ("+", [Leaf 3; Node ("*", [Leaf 4; Leaf 5])]) 77 | (* val expr_tree : (string, int) parse_tree = ... *) 78 | 79 | (* An sentence of awk grammar *) 80 | let sentence = ["9"; "+"; "$"; "1"] 81 | 82 | (* The parsing tree of it *) 83 | let tree = Node (Expr, 84 | [Node (Term, [Node (Num, [Leaf "9"])]); 85 | Node (Binop, [Leaf "+"]); 86 | Node (Expr, [Node (Term, [Node (Lvalue, 87 | [Leaf "$"; 88 | Node (Expr, 89 | [Node (Term, [Node (Num, [Leaf "1"])])])])])])]) 90 | (* parse_tree_leaves tree = sentence *) 91 | 92 | (* ---------- make_matcher ---------- *) 93 | 94 | type 'terminal fragment = 'terminal list 95 | let sentence : string fragment = ["9"; "+"; "$"; "1"] 96 | 97 | 98 | type ('terminal, 'result) acceptor = 'terminal fragment -> 'result option 99 | let accept_all : ('terminal, 'terminal fragment) acceptor = fun str -> Some str 100 | let accept_empty_suffix : ('terminal, 'terminal fragment) acceptor = 101 | function 102 | | _::_ -> None 103 | | x -> Some x 104 | 105 | let _ = accept_all [] 106 | (* - : 'a fragment option = Some [] *) 107 | let _ = accept_all sentence 108 | (* - : string fragment option = Some ["9"; "+"; "$"; "1"] *) 109 | let _ = accept_empty_suffix [] 110 | (* - : 'a fragment option = Some [] *) 111 | let _ = accept_empty_suffix sentence 112 | (* - : string fragment option = None *) 113 | 114 | 115 | type ('terminal, 'result) matcher = 116 | ('terminal, 'result) acceptor -> 'terminal fragment -> 'result option 117 | (* ^ ^ ^ 118 | | | | 119 | A matcher takes an acceptor accept and a fragment frag | 120 | It matches a prefix of frag such that accept accepts the suffix | 121 | If there exists such a prefix, return whatever accept returns ----| 122 | If there does not exist one, return None -------------------------| 123 | 124 | A matcher should try rules in order 125 | *) 126 | 127 | (* 128 | let awk_matcher : (string, string fragment) matcher = make_matcher awkish_grammar 129 | 130 | let test2 = awk_matcher accept_all ["9"; "+"; "$"; "1"; "+"] 131 | val test2 : string fragment option = Some ["+"] 132 | Expr 133 | ^ 134 | |-------|-------| 135 | | | | 136 | Term Binop Expr 137 | ^ ^ Term 138 | | | Lvalue 139 | | | ^ 140 | | | |----|----| 141 | Num | | | 142 | ^ | | Expr 143 | | | | Term 144 | | | | Num 145 | 9 + $ 1 + 146 | [ PREFIX ] [SUFFIX] 147 | accept_all ["+"] = Some ["+"] *) 148 | 149 | (* Why it's Some ["+"] but not Some ["+"; "$"; "1"; "+"]? *) 150 | let _ = (snd awkish_grammar) Expr 151 | (* - : (awksub_nonterminals, string) symbol fragment fragment = [[N Term; N Binop; N Expr]; [N Term]] *) 152 | (* [N Term; N Binop; N Expr] is in front of [N Term] *) 153 | 154 | (* 155 | let test0 = awk_matcher accept_all ["ouch"] 156 | val test0 : string fragment option = None 157 | 158 | Why it's not Some ["ouch"]? 159 | Expr 160 | | 161 | ??? 162 | | 163 | "ouch" 164 | [ PREFIX ] [SUFFIX] 165 | [] is not a sentence in awkish_grammar. 166 | *) 167 | 168 | (* ---------- make_parser ---------- *) 169 | 170 | type ('nonterminal, 'terminal) parser = 171 | 'terminal fragment -> ('nonterminal, 'terminal) parse_tree 172 | (* ^ ^ 173 | | | 174 | ----------------| |-------- 175 | A parser is a function from fragments to parse trees 176 | *) 177 | 178 | (* make_parser awkish_grammar sentence = Some tree *) 179 | (* make_parser awkish_grammar ["9"; "+"; "$"; "1"; "+"] = None *) 180 | 181 | (* 182 | Remember: Say what you cannot do in the report 183 | *) 184 | let recur_grammar = Expr, function 185 | | Expr -> [[N Expr; T "+"; N Expr]; 186 | [N Expr; T "*"; N Expr]; 187 | [N Num]] 188 | | Num -> [[T"0"]; [T"1"]; [T"2"]; [T"3"]; [T"4"]; 189 | [T"5"]; [T"6"]; [T"7"]; [T"8"]; [T"9"]] 190 | | _ -> [] 191 | (* This will not occur in our testcases. There's no score for it. 192 | But to be honest, can your algorithm handle this? *) 193 | 194 | (* ---------- The need for CPS ---------- *) 195 | 196 | (* 197 | This is not a formal introduction of CPS, which will be at the end of this quarter. 198 | I only want to introduce why it's useful in matching. 199 | *) 200 | 201 | type nonterm_set = S | A | B | C | D | E | F 202 | 203 | let grammar_a = S, function 204 | | S -> [[T "^"; N A]; 205 | [N B]] 206 | | A -> [[T "a"; T "a"]] 207 | | B -> [[T "^"; T "b"]] 208 | | _ -> [] (* Other nonterms are not used *) 209 | 210 | (* 211 | How do we construct a matcher for this grammar? 212 | A simple idea is to write a function for everything: Terminal, A, B and S. 213 | Each of the matcher consumes what it needs and returns Some suffix if it's successful; otherwise None. 214 | *) 215 | 216 | (* match_term works well. It just checks whether the first symbol is the terminal we want... *) 217 | let match_term t = function 218 | | h::s when h = t -> Some s 219 | | _ -> None 220 | 221 | (* 222 | Here we define a function that helps us to handle with option: 223 | 1. When the input is (Some x), return (f x) 224 | 2. When the input is None, return None 225 | So we can chain functions that returns an option 226 | *) 227 | let (>>=) v f = match v with 228 | | None -> None 229 | | Some x -> f x 230 | 231 | (* matchers for A and B are trival *) 232 | let match_a s = 233 | let after_a = match_term "a" s in 234 | let after_aa = after_a >>= match_term "a" in 235 | after_aa 236 | 237 | let match_b s = 238 | let after_hat = match_term "^" s in 239 | let after_hatb = after_hat >>= match_term "b" in 240 | after_hatb 241 | 242 | (* For the matcher for s, we first try $A; if it fails, then B *) 243 | let match_s s = 244 | let try_hata = match_term "^" s >>= match_a in 245 | match try_hata with 246 | | Some _ -> try_hata 247 | | None -> match_b s 248 | 249 | let _ = match_s ["^"; "a"; "a"; "$"] 250 | (* - : string list option = Some ["$"] *) 251 | 252 | let _ = match_s ["^"; "b"; "a"] 253 | (* - : string list option = Some ["a"] *) 254 | 255 | (* Till now it looks good. But how about this grammar? *) 256 | 257 | let grammar_b = S, function 258 | | S -> [[N C; T "$"]] 259 | | C -> [[N B]; [N A]] 260 | | A -> [[T "a"; T "a"]] 261 | | B -> [[T "a"]] 262 | | _ -> [] 263 | (* match_term and match_a keeps the same so we do not need to rewrite *) 264 | 265 | (* match_b and match_c seems easy *) 266 | let match_b = match_term "a" 267 | let match_c s = 268 | let try_b = match_b s in 269 | match try_b with 270 | | Some _ -> try_b 271 | | None -> match_a s 272 | 273 | (* But match_s does not work well ... *) 274 | let match_s s = match_c s >>= match_term "$" 275 | 276 | let _ = match_s ["a"; "$"] 277 | (* - : string list option = Some [] *) 278 | 279 | let _ = match_s ["a"; "a"; "$"] 280 | (* - : string list option = None *) 281 | (* Why it's not Some [] ? 282 | 283 | 0. call match_s ["a"; "a"; "$"] 284 | 1. match_s calls match_c ["a"; "a"; "$"] 285 | 2. match_c tries match_b ["a"; "a"; "$"] 286 | 3. match_b returns Some ["a"; "$"] 287 | 4. so match_c also returns Some ["a"; "$"] 288 | 5. match_s calls match_term "$" ["a"; "$"] 289 | 6. match_term returns None 290 | 7. BUT there is no way to redo match_c. 291 | It already returns ... 292 | 293 | *) 294 | 295 | (* Solution: do not let it return *) 296 | 297 | (* ---------- CPS (Continuation Passing Style) ---------- *) 298 | 299 | (* Add a new argument k: what's next *) 300 | (* Instead of return immediately, call that argument *) 301 | 302 | let plus_cps x y k = k (x + y) 303 | (* val plus_cps : int -> int -> (int -> 'a) -> 'a = *) 304 | 305 | let _ = plus_cps 2 3 (fun x -> x + 1) 306 | (* - : int = 6 *) 307 | 308 | let match_term2 t k = function 309 | | h::s when h = t -> k s 310 | | _ -> None 311 | 312 | let match_a2 k s = 313 | match_term2 "a" (match_term2 "a" k) s 314 | (* ^ ^ ^ 315 | | | | 316 | 1st a 2nd a next step 317 | *) 318 | 319 | (* Or use currying to write it shorter *) 320 | let match_a2 k = match_term2 "a" @@ match_term2 "a" k 321 | 322 | let match_b2 k = match_term2 "a" k 323 | 324 | let match_c2 k s = 325 | let try_b = match_b2 k s in (* Here try_b becomes the "final" result! *) 326 | match try_b with 327 | | Some _ -> try_b 328 | | None -> match_a2 k s 329 | 330 | let match_s2 k = match_c2 @@ match_term2 "$" k 331 | 332 | (* Finally we use an identity function to pass the result out *) 333 | let match_s = match_s2 (fun x -> Some x) 334 | 335 | let _ = match_s ["a"; "$"] 336 | (* - : string list option = Some [] *) 337 | 338 | let _ = match_s ["a"; "a"; "$"] 339 | (* - : string list option = Some [] *) 340 | (* This time works! *) 341 | 342 | (* ---------- Connection between HW2 ---------- *) 343 | (* You may already notice that the "k" above is exactly the acceptor function... *) 344 | (* Now you can read the Hint code. Remember accept == What to do next *) 345 | -------------------------------------------------------------------------------- /OCaml/hw2/grammar_converter_sample.ml: -------------------------------------------------------------------------------- 1 | (* 2 | * type: symbol definition (in HW1 / HW2) 3 | *) 4 | 5 | type ('nonterminal, 'terminal) symbol = 6 | | N of 'nonterminal 7 | | T of 'terminal;; 8 | 9 | (* 10 | * this is the HW1-style grammar example 11 | *) 12 | 13 | type awksub_nonterminals = 14 | | Expr | Lvalue | Incrop | Binop | Num;; 15 | 16 | let awksub_rules = 17 | [Expr, [T"("; N Expr; T")"]; 18 | Expr, [N Num]; 19 | Expr, [N Expr; N Binop; N Expr]; 20 | Expr, [N Lvalue]; 21 | Expr, [N Incrop; N Lvalue]; 22 | Expr, [N Lvalue; N Incrop]; 23 | Lvalue, [T"$"; N Expr]; 24 | Incrop, [T"++"]; 25 | Incrop, [T"--"]; 26 | Binop, [T"+"]; 27 | Binop, [T"-"]; 28 | Num, [T"0"]; 29 | Num, [T"1"]; 30 | Num, [T"2"]; 31 | Num, [T"3"]; 32 | Num, [T"4"]; 33 | Num, [T"5"]; 34 | Num, [T"6"]; 35 | Num, [T"7"]; 36 | Num, [T"8"]; 37 | Num, [T"9"]];; 38 | 39 | let awksub_grammar = Expr, awksub_rules;; 40 | 41 | (* 42 | * test cases 43 | * assume that you have convert_grammar implemented already 44 | *) 45 | 46 | let awksub_grammar_hw2 = convert_grammar awksub_grammar;; 47 | 48 | let test_start_symbol = 49 | fst awksub_grammar = fst awksub_grammar_hw2;; 50 | let test_Expr = 51 | (snd awksub_grammar_hw2) Expr = [ 52 | [T"("; N Expr; T")"]; 53 | [N Num]; 54 | [N Expr; N Binop; N Expr]; 55 | [N Lvalue]; 56 | [N Incrop; N Lvalue]; 57 | [N Lvalue; N Incrop] 58 | ];; 59 | let test_Lvalue = 60 | (snd awksub_grammar_hw2) Lvalue = [[T"$"; N Expr]];; 61 | 62 | let test_Incrop = 63 | (snd awksub_grammar_hw2) Incrop = [[T"++"];[T"--"]];; 64 | 65 | let test_Binop = 66 | (snd awksub_grammar_hw2) Binop = [[T"+"];[T"-"]];; 67 | 68 | let test_Num = 69 | (snd awksub_grammar_hw2) Num = [[T"0"];[T"1"];[T"2"];[T"3"];[T"4"];[T"5"];[T"6"];[T"7"];[T"8"];[T"9"]];; 70 | 71 | 72 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /OCaml/hw2/hw2_matcher2parser.py: -------------------------------------------------------------------------------- 1 | ''' 2 | This is a hint from matcher to parser 3 | 4 | for a python class (e.g. Node) 5 | __init__ is called when initializing it 6 | __repr__ is called as representation 7 | __str__ is used to generate a string representation, take effect when calling str(node) to initialize it 8 | __eq__ is the reload of = 9 | __call__ is called when we call an instance, e.g. node() 10 | ''' 11 | 12 | class Node: 13 | def __init__(self, value, children): 14 | self.value = value 15 | self.children = children 16 | def is_node(self): 17 | return True 18 | def is_leaf(self): 19 | return False 20 | def __repr__(self): 21 | return "Node ({}, [{}])".format(self.value, ",".join(map(str, self.children))) 22 | def __str__(self): 23 | return "Node ({}, [{}])".format(self.value, ",".join(map(str, self.children))) 24 | 25 | class Leaf: 26 | def __init__(self, value): 27 | self.value = value 28 | def __repr__(self): 29 | return "Leaf {}".format(self.value) 30 | def __str__(self): 31 | return "Leaf {}".format(self.value) 32 | def is_node(self): 33 | return False 34 | def is_leaf(self): 35 | return True 36 | 37 | class symbol: 38 | def __init__(self, _type, _val): 39 | assert(_type in ['T', 'N']) 40 | self.type = _type 41 | self.value = _val 42 | def __call__(self): 43 | return self.value 44 | def __repr__(self): 45 | return str(self.value) 46 | def __eq__(self, other): 47 | return self.value == other.value and self.type == other.type 48 | def is_terminal(self): 49 | return self.type == 'T' 50 | def is_nonterminal(self): 51 | return self.type == 'N' 52 | 53 | example_tree = Node('root', [ 54 | Leaf ('1.1'), 55 | Node('1.2', [Leaf ('2.1'), Node ('2.2', [Leaf ('3.1')]), Leaf ('2.3')]), 56 | Leaf('1.3'), 57 | Node('1.4', [Leaf ('2.4')]) 58 | ] 59 | ) 60 | naive_rules = { 61 | 'Expr': [ 62 | [symbol('T', "("), symbol('N', 'Expr'), symbol('N', 'Binop'), symbol('N', 'Expr'), symbol('T', ")")], 63 | [symbol('N', 'Num')] 64 | ], 65 | 'Binop': [[symbol('T', "+")], [symbol('T', "-")], [symbol('T', "*")], [symbol('T', "/")]], 66 | 'Num': [[symbol('T', "0")], [symbol('T', "1")], [symbol('T', "2")], [symbol('T', "3")], [symbol('T', "4")], 67 | [symbol('T', "5")], [symbol('T', "6")], [symbol('T', "7")], [symbol('T', "8")], [symbol('T', "9")]] 68 | } 69 | 70 | start_symbol = 'Expr' 71 | 72 | naive_grammar = ( 73 | start_symbol, 74 | naive_rules 75 | ) 76 | 77 | # (2 + (6 - 3)) 78 | rules_record = [ 79 | ('Expr', [symbol('T', "("), symbol('N', 'Expr'), symbol('N', 'Binop'), symbol('N', 'Expr'), symbol('T', ")")]), 80 | ('Expr', [symbol('N', 'Num')]), 81 | ('Num', [symbol('T', "2")]), 82 | ('Binop', [symbol('T', "+")]), 83 | ('Expr', [symbol('T', "("), symbol('N', 'Expr'), symbol('N', 'Binop'), symbol('N', 'Expr'), symbol('T', ")")]), 84 | ('Expr', [symbol('N', 'Num')]), 85 | ('Num', [symbol('T', "6")]), 86 | ('Binop', [symbol('T', "-")]), 87 | ('Expr', [symbol('N', 'Num')]), 88 | ('Num', [symbol('T', "3")]) 89 | ] 90 | rhs_record = [ 91 | [symbol('T', "("), symbol('N', 'Expr'), symbol('N', 'Binop'), symbol('N', 'Expr'), symbol('T', ")")], 92 | [symbol('N', 'Num')], 93 | [symbol('T', "2")], 94 | [symbol('T', "+")], 95 | [symbol('T', "("), symbol('N', 'Expr'), symbol('N', 'Binop'), symbol('N', 'Expr'), symbol('T', ")")], 96 | [symbol('N', 'Num')], 97 | [symbol('T', "6")], 98 | [symbol('T', "-")], 99 | [symbol('N', 'Num')], 100 | [symbol('T', "3")] 101 | ] 102 | 103 | def rhs2children(rhs): 104 | children = [] 105 | for sym in rhs: 106 | if sym.is_terminal(): 107 | children.append( Leaf(sym()) ) 108 | else: 109 | children.append( Node(sym(), []) ) 110 | return children 111 | 112 | def constructing_tree(rhs_traced, temp_root): 113 | if temp_root.is_node() and len(rhs_traced) > 0: 114 | # if this is a node, need to expand its child and remove one rule from the traced list 115 | tmp_rhs = rhs_traced[0] 116 | rhs_traced = rhs_traced[1:] 117 | temp_root.children = rhs2children(tmp_rhs) 118 | for i in range(len(temp_root.children)): 119 | (rhs_traced, temp_root.children[i]) = constructing_tree(rhs_traced, temp_root.children[i]) 120 | return (rhs_traced, temp_root) 121 | 122 | 123 | def print_a_tree(tree, level_indent=0): 124 | ''' 125 | this function is for elegant printing only 126 | never needed for OCaml 127 | ''' 128 | print_indent = level_indent * " " 129 | tmp_value = tree.value 130 | print("{}{}".format(print_indent, tmp_value)) 131 | if tree.is_node(): 132 | children_level = level_indent + 1 133 | for child in tree.children: 134 | print_a_tree(child, children_level) 135 | def print_rule_list(rule_list): 136 | ''' 137 | again, only for beautiful printing 138 | ''' 139 | for rule in rule_list: 140 | print("{} -> {}".format(rule[0], rule[1])) 141 | def print_rhs_list(rhs_list): 142 | ''' 143 | again, only for printing in python 144 | ''' 145 | for rhs in rhs_list: 146 | print(rhs) 147 | 148 | if __name__ == '__main__': 149 | print("If we know that the order of rules used for expanding the start_symbol all the way until the fragment?\n" 150 | "For example, the rules we've used to expand the symbol list starting with the staring-symbol is:\n") 151 | print_rule_list(rules_record) 152 | print("\nAnd obviously, the corresponding right-hand-side list is:\n") 153 | print_rhs_list(rhs_record) 154 | print("\nWe are able to reconstruct the tree easily:\n") 155 | (_, tree) = constructing_tree(rhs_record, Node(start_symbol, [])) 156 | print_a_tree(tree) 157 | print("\nBut remember that this is not the OCaml way of solving problems (e.g. loop is not allowed).") 158 | print("Plus, this is not the only way out. This helper function is not necessarily used. DONOT be restricted.\n") 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | -------------------------------------------------------------------------------- /OCaml/hw2/hw2tree_hint.py: -------------------------------------------------------------------------------- 1 | ''' 2 | for a python class (e.g. Node) 3 | __init__ is called when initializing it 4 | __repr__ is called as representation 5 | __str__ is used to generate a string representation, take effect when calling str(node) to initialize it 6 | __eq__ is the reload of = 7 | __call__ is called when we call an instance, e.g. node() 8 | ''' 9 | 10 | class Node: 11 | def __init__(self, value, children): 12 | self.value = value 13 | self.children = children 14 | def is_node(self): 15 | return True 16 | def is_leaf(self): 17 | return False 18 | def __repr__(self): 19 | return "Node ({}, [{}])".format(self.value, ",".join(map(str, self.children))) 20 | def __str__(self): 21 | return "Node ({}, [{}])".format(self.value, ",".join(map(str, self.children))) 22 | 23 | class Leaf: 24 | def __init__(self, value): 25 | self.value = value 26 | def __repr__(self): 27 | return "Leaf {}".format(self.value) 28 | def __str__(self): 29 | return "Leaf {}".format(self.value) 30 | def is_node(self): 31 | return False 32 | def is_leaf(self): 33 | return True 34 | 35 | class symbol: 36 | def __init__(self, _type, _val): 37 | assert(_type in ['T', 'N']) 38 | self.type = _type 39 | self.value = _val 40 | def __call__(self): 41 | return self.value 42 | def __repr__(self): 43 | return "symbol {}: {}".format(self.type, self.value) 44 | def __eq__(self, other): 45 | return self.value == other.value and self.type == other.type 46 | def is_terminal(self): 47 | return self.type == 'T' 48 | def is_nonterminal(self): 49 | return self.type == 'N' 50 | 51 | example_tree = Node('root', [ 52 | Leaf ('1.1'), 53 | Node('1.2', [Leaf ('2.1'), Node ('2.2', [Leaf ('3.1')]), Leaf ('2.3')]), 54 | Leaf('1.3'), 55 | Node('1.4', [Leaf ('2.4')]) 56 | ] 57 | ) 58 | naive_rules = { 59 | 'SimpleExpr': [ 60 | [symbol('N', 'LeftExpr'), symbol('N', 'Binop'), symbol('N', 'RightExpr')], 61 | [symbol('N', 'Num')] 62 | ], 63 | 'Binop': [[symbol('T', "+")], [symbol('T', "-")], [symbol('T', "*")], [symbol('T', "/")]], 64 | 'LeftExpr': [ 65 | [symbol('N', 'Num')], 66 | [symbol('T', "("), symbol('N', 'Num'), symbol('N', 'Binop'), symbol('N', 'Num'), symbol('T', ")")] 67 | ], 68 | 'RightExpr': [ 69 | [symbol('N', 'Num')], 70 | [symbol('T', "("), symbol('N', 'Num'), symbol('N', 'Binop'), symbol('N', 'Num'), symbol('T', ")")] 71 | ], 72 | 'Num': [[symbol('T', "0")], [symbol('T', "1")], [symbol('T', "2")], [symbol('T', "3")], [symbol('T', "4")], 73 | [symbol('T', "5")], [symbol('T', "6")], [symbol('T', "7")], [symbol('T', "8")], [symbol('T', "9")]] 74 | } 75 | 76 | naive_grammar = ( 77 | 'SimpleExpr', 78 | naive_rules 79 | ) 80 | 81 | def PreorderTraversal(tree): 82 | ''' 83 | visit Root first, then Children from left to right 84 | ''' 85 | if tree.is_leaf(): 86 | return [tree.value] 87 | else: 88 | result = [tree.value] 89 | for child in tree.children: 90 | result += PreorderTraversal(child) 91 | return result 92 | 93 | def PostorderTraversal(tree): 94 | ''' 95 | visit Children from left to right, then Root 96 | ''' 97 | if tree.is_leaf(): 98 | return [tree.value] 99 | else: 100 | result = [] 101 | for child in tree.children: 102 | result += PostorderTraversal(child) 103 | result.append(tree.value) 104 | return result 105 | 106 | def example_function(x, y=None): 107 | if y is None: 108 | return lambda y: example_function(x, y) 109 | else: 110 | return x + y 111 | 112 | def print_list(terminate_symbols): 113 | print("".join(terminate_symbols)) 114 | 115 | def brutal_force_expand(rules, symbol_list, terminate_prefix): 116 | if len(symbol_list) == 0: 117 | # reached the end of the symbol list 118 | print_list(terminate_prefix) 119 | else: 120 | first_symbol = symbol_list[0] 121 | rest_symbols = symbol_list[1:] 122 | if first_symbol.is_terminal(): 123 | brutal_force_expand(rules, rest_symbols, terminate_prefix+[first_symbol()]) 124 | else: 125 | right_hand_side_list = rules[first_symbol()] 126 | for rhs in right_hand_side_list: 127 | brutal_force_expand(rules, rhs + rest_symbols, terminate_prefix) 128 | 129 | if __name__ == '__main__': 130 | print("depth-first traversals:") 131 | print("note that I used the terms pre-order and post-order INACCURATELY - \n \ 132 | these terms should be used ONLY for BINARY trees (all nodes at most 2 children) \n \ 133 | please DONOT mess-up the concepts.") 134 | print("pre-order style (root-first):",PreorderTraversal(example_tree)) 135 | print("post-order style (child-first)",PostorderTraversal(example_tree)) 136 | print("explaination of the idea of currying:") 137 | print("example_function(2,3)={}".format(example_function(2,3))) 138 | print("example_function(2)(3)={}".format(example_function(2)(3))) 139 | print("silly example of generating all possible expressions\ 140 | Becareful: you CAN'T use this logic in your code - WHY? (infinite loop / functional expression)") 141 | start_symbol = naive_grammar[0] 142 | rules = naive_grammar[1] 143 | brutal_force_expand(rules, [symbol('N', start_symbol)], []) 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | -------------------------------------------------------------------------------- /OCaml/hw2/option.ml: -------------------------------------------------------------------------------- 1 | let is_some x = (x != None);; 2 | 3 | let is_none x = (x = None);; 4 | 5 | let get x = (let (Some x_value) = x in x_value);; 6 | 7 | let may f x = 8 | if (is_some x) then (f x) 9 | else ();; 10 | 11 | let map f x = 12 | if (is_some x) then (f x) 13 | else None;; 14 | 15 | let default x opt = 16 | match opt with 17 | | None -> x 18 | | Some v -> v;; 19 | 20 | let map_default f x opt = 21 | match opt with 22 | | None -> x 23 | | Some v -> f v;; -------------------------------------------------------------------------------- /OCaml/hw2/pseudo_code.txt: -------------------------------------------------------------------------------- 1 | (* 2 | hint code from Fall 2019 3 | given by Prof. Eggert in class, re-organized by Xinyu Ma 4 | Notice: this is a piece of pseudo-code as a hint for hw2 5 | *) 6 | 7 | let id x = x 8 | 9 | (* A -> [[]] *) 10 | let matcherA = fun accept frag -> 11 | accept frag 12 | 13 | let matcherA = id 14 | 15 | (* B -> [[T"t"]] *) 16 | let matcherB = fun accept frag -> 17 | match frag with 18 | | t::s when t = "t" -> accept s 19 | | _ -> None 20 | 21 | (* C -> [[N D]; [N E]] *) 22 | let matcherC = fun accept frag -> 23 | let r = matcherD accept frag in 24 | match r with 25 | | Some x -> Some x 26 | | None -> matcherE accept frag 27 | 28 | (* F -> [[N G; N H]] *) 29 | let matcherF = fun accept frag -> 30 | let acceptG = fun suffixG -> matcherH accept suffixG in 31 | matcherG acceptG frag 32 | 33 | let matcherF = fun accept -> matcherG (matcherH accept) 34 | 35 | (* A -> [lst=[N B; N C; N D; ...]] *) 36 | let rec mmfcpl = function 37 | | [] -> id 38 | | p::ps -> 39 | let mp = make_matcher p in 40 | let mps = mmfcpl ps in 41 | fun accept -> mp (mps accept) 42 | 43 | (* C -> lst=[[N D]; [N E]; [N F]; ...] *) 44 | let rec mmds = function 45 | | [] -> fun _ _ -> None 46 | | p::ps -> 47 | let mp = make_matcher p in 48 | let mps = mmds ps in 49 | fun accept frag -> 50 | match mp accept frag with 51 | | None -> mps accept frag 52 | | x -> x -------------------------------------------------------------------------------- /OCaml/hw2/readme.md: -------------------------------------------------------------------------------- 1 | # Hint Code for OCaml HW2 2 | 3 | ## About 4 | * Still, not mandatory to be used. 5 | 6 | ## About the Files 7 | * [pseudo_code.txt](./pseudo_code.txt) 8 | * It comes from Prof. Eggert's Fall 2019 lecture, refined by Xinyu Ma 9 | * Note that it is only a piece of **pseudo** code, please don't ask us why it has compilation error. 10 | * [hw2tree_hint.py](./hw2tree_hint.py) 11 | * This piece of code introduces the structure of tree, and tree traversals. If you are already familiar with the tree structure, skip it. 12 | * [hw2_matcher2parser.py](./hw2_matcher2parser.py) 13 | * Many felt it easy implementing a matcher, but get confused how to move on to parser; this is how (in logic only; you still need to write your own implementation). 14 | * [option.ml](./option.ml) 15 | * You are not allowed to use the library functions in [Option](http://ocaml-lib.sourceforge.net/doc/Option.html). But listed here are some easy replacements of those library functions. 16 | * [grammer_converter_sample.ml](./grammar_converter_sample.ml) 17 | * This is some sample test cases for grammar converter (converting from hw1-style grammar to hw2-style grammar), if you feel confused on how to test the correctness of that part please try this. 18 | * [Why_Acceptor.ml](./Why_Acceptor.ml) is the hint code Xinyu provides to you. It'll help you have a better understanding on HW2 settings. 19 | * [2006 hint code](./2006/) is the runnable copy of the 2006 hint code we provide you. 20 | 21 | ## A few more tips 22 | * Check the [debugger](https://caml.inria.fr/pub/docs/manual-ocaml/debugger.html) if you love debuggers such as GDB etc. Not mandatory to use it. 23 | * If all your concern is about logic, not about OCaml, then you may consider editing the python hint to test your logic out. 24 | * If you somehow didn't make it to finish ```make_matcher``` and ```make_parser``` in time, please at least put the default implementation as a placeholder: 25 | ```ocaml 26 | let make_matcher gram accept frag = None;; 27 | let make_parser gram frag = None;; 28 | ``` 29 | so that you can avoid potential errors such as ```Unbound value make_matcher```. -------------------------------------------------------------------------------- /Prolog/check_row_unique.pl: -------------------------------------------------------------------------------- 1 | % example test cases: 2 | % row_all_unique([1,2,1]). 3 | % row_all_unique([1,2,3]). 4 | row_all_unique(Row) :- 5 | sort(Row, Sorted), 6 | length(Row, N_elements), 7 | length(Sorted, N_unique_elements), 8 | N_elements == N_unique_elements. -------------------------------------------------------------------------------- /Prolog/examples.pl: -------------------------------------------------------------------------------- 1 | % Man is but a reed, the weakest in nature, but he is a thinking reed 2 | 3 | man_is_a_thinking_reed. 4 | 5 | is_but_a(man, reed). 6 | weakest(reed, nature). 7 | thinking(man). 8 | 9 | thinking_reed(X) :- 10 | thinking(X), 11 | weak(X). 12 | 13 | weak(X) :- 14 | weakest(Y, nature), 15 | similar(X, Y). 16 | 17 | similar(X, X). 18 | similar(X, Y) :- 19 | is_but_a(X, Y). 20 | 21 | 22 | % Studies serve for delight, for ornament, and for ability. Their chief use for delight is in privateness and retiring; for ornament, is in discourse; and for ability, is in the judgement and execution of business. 23 | 24 | serve_for(study, delight). 25 | serve_for(study, ornament). 26 | serve_for(study, ability). 27 | 28 | useful_in(delight, privateness). 29 | useful_in(delight, retiring). 30 | useful_in(ornament, discourse). 31 | useful_in(ability, judgement). 32 | useful_in(ability, execution_of_business). 33 | 34 | chief_use_for(Object, Property, Usage) :- 35 | serve_for(Object, Property), 36 | useful_in(Property, Usage). 37 | 38 | % Raindrops on roses 39 | % And whiskers on kittens 40 | % Bright copper kettles and warm woolen mittens 41 | % Brown paper packages tied up with strings 42 | % These are a few of my favorite things 43 | 44 | favorite_things(raindrops, roses). 45 | favorite_things(whiskers, kittens). 46 | favorite_things(copper, kettles). 47 | favorite_things(woolen, mittens). 48 | favorite_things(packages, strings). 49 | 50 | % usage from query: 51 | % favorite(things(raindrops, roses)) 52 | favorite(X) :- 53 | things(A, B) = X, 54 | favorite_pair(A, B). 55 | 56 | favorite_pair(A, B) :- 57 | favorite_things(A, B); % this is or 58 | favorite_things(B, A). 59 | 60 | p([H1, H2 | T], H1, H2, T). 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /Prolog/hello.pl: -------------------------------------------------------------------------------- 1 | % these are Facts 2 | % always start with a lowercase letter, otherwise thrown an error 3 | raining. 4 | john_is_cold. 5 | john_forgot_his_raincoat. 6 | % calling example: 7 | % raining. 8 | 9 | % these are Relations 10 | % closed-world assumption: all unknown rules are NO 11 | student(fred). 12 | eats(fred, oranges). 13 | eats(fred, bananas). 14 | eats(tony, apples). 15 | % sample usage: 16 | % eats(fred, oranges). 17 | % eats(fred, apples). 18 | 19 | % Variables & Unification 20 | % Unification tries to find a way to fill the missing Values(variables), binds variables to atoms 21 | % NO Return Values in Prolog! 22 | % Variable is any string that starts with a capital letter 23 | % sample cases 24 | % eats(fred, What). 25 | % eats(Who, apples). 26 | 27 | % Rules allow us to make conditional statement 28 | % Syntax: conclusion :- premises. 29 | % Conclusion is true iif the premises are true 30 | % example: Consider the statement - All men are mortal 31 | mortal(X) :- 32 | human(X). 33 | human(socrates). 34 | % sample usage: 35 | % mortal(socrates). 36 | % mortal(Who). 37 | 38 | % Rules can contain multiple statements 39 | % Comma (,) is the AND operator, semi-colon (;) is the OR operator 40 | red_car(X) :- 41 | red(X), 42 | car(X). 43 | red(ford_focus). 44 | car(ford_focus). 45 | red_or_blue_car(X) :- 46 | (red(X);blue(X)), 47 | car(X). 48 | red(ford_escort). 49 | car(ford_escort). 50 | % sample usage 51 | % red_or_blue_car(ford_escort). 52 | % red_car(What). 53 | 54 | % Three equality operators: = , is , =:= 55 | % = tries unification directly 56 | % is evaluates the right side then unifies 57 | % =:= evaluates both sides 58 | % e.g. 59 | 60 | % ?- 7 = 5 + 2. 61 | % no 62 | % ?- X = 5 + 2. 63 | % X = 5+2 64 | % yes 65 | % ?- A + B = 5 + 2. 66 | % A = 5 67 | % B = 2 68 | 69 | % ?- X is 5 + 2. 70 | % X = 7 71 | % yes 72 | % ?- 7 is 5 + 2. 73 | % yes 74 | % ?- 5 + 2 is 7. 75 | % no 76 | % ?- X is 5 + Y. 77 | % uncaught exception: 78 | % error(instantiation_error,(is)/2) 79 | 80 | % ?- 5 + 2 =:= 4 + 3. 81 | % yes 82 | % ?- X =:= 4 + 3. 83 | % uncaught exception: 84 | % error(instantiation_error,(=:=)/2) 85 | % ?- X = 5, Y = 5, X =:= Y. 86 | % X = 5 87 | % Y = 5 88 | % yes 89 | 90 | % Arithmetic comparisons 91 | % <, =<, >=, =:= (equals), =\= (not equals) 92 | 93 | % Recursion 94 | flight(lax,atl). 95 | flight(atl,jfk). 96 | flight(jfk,lhr). 97 | can_travel(X,Y) :- flight(X,Y). % try match this rule first - so always ending condition first 98 | can_travel(X,Y) :- flight(X,Z), can_travel(Z,Y). 99 | % example: 100 | % can_travel(lax,lhr). 101 | % can_travel(lhr,lax). 102 | 103 | % another recursion example 104 | father(john,paul). 105 | father(paul,henry). 106 | mother(paul,mary). 107 | mother(mary,susan). 108 | ancestor(X,Y) :- father(X,Y); mother(X,Y). 109 | ancestor(X,Y) :- (father(X,Z), ancestor(Z,Y)); 110 | (mother(X,Z), ancestor(Z,Y)). 111 | % ancestor(john,Who). 112 | 113 | % List 114 | p([H | T], H, T). 115 | % p([a, b, c], a, [b, c]). 116 | % p([a, b, c], X, Y). 117 | % p([a], X, Y). 118 | % p([], X, Y). 119 | append([], Y, Y). 120 | append([XH|XT], Y, [XH|RT]) :- append(XT, Y, RT). 121 | 122 | 123 | 124 | -------------------------------------------------------------------------------- /Prolog/list2D_hint.pl: -------------------------------------------------------------------------------- 1 | % this is an additional material to sudoku_cell.pl 2 | % if that is not enough to help you finish hw4 3 | 4 | % you can call directly: 5 | % reverse(X, [1,2,3]). 6 | % from toplevel 7 | % to use it on a 2-D array, and reverse each row? 8 | % maplist(reverse, X, [[1,2,3],[4,5,6]]). 9 | 10 | % sample call from toplevel: 11 | % reverse_2d([[1,2,3],[4,5,6]], RX). 12 | reverse_2d(X, RX) :- 13 | maplist(reverse, X, RX). 14 | 15 | % what if I want to record a non-increasing sublist of a list? 16 | % for example, think about this scenario: eagle gliding and landing on hill tops whenever that hill is not higher than the previous hill 17 | % first stop 18 | % /\ 19 | % / \ second stop /\ 20 | % / \ /\ / \ third 21 | % / \ / \ / \ stop /\ 22 | % / \ / \ / \ /\ / \ last stop 23 | % / 6 \/ 4 \/ 5 \/ 2\/ 3 \/\1 24 | % design: 25 | % non_increasing(List, Sublist) 26 | % non_increasing(List, Minval, TmpSublist, ResultSublist) 27 | % force the function to "return", by non_increasing([], _, Sublist, Sublist) 28 | % --- it means that: after finished processing the whole list, return our sublist 29 | % sample usage (from toplevel): 30 | % non_increasing([6,4,5,2,3,1], NI). 31 | % expected outcome: [6,4,2,1] 32 | % think about it: how you could check and record the counting in towel? 33 | non_increasing([Hd|Tl], NI) :- 34 | non_increasing(Tl, Hd, [Hd], NI). 35 | non_increasing([], _, Sublist, Sublist). % this is how we force "return" 36 | non_increasing([Hd|Tl], Minval, TmpSublist, NI) :- 37 | Hd =< Minval, 38 | append(TmpSublist, [Hd], NextSublist), 39 | non_increasing(Tl, Hd, NextSublist, NI). 40 | non_increasing([Hd|Tl], Minval, TmpSublist, NI) :- 41 | Hd > Minval, 42 | non_increasing(Tl, Minval, TmpSublist, NI). 43 | 44 | % sample usage of statistic from toplevel: 45 | % count_runtime(T). 46 | % and you'll see 0 --- that's too fast, in your homework you might encounter similar problem 47 | % think about how to avoid being divided by zero? (hint: opt1 - +epsilon, opt2 - switch the order) 48 | count_runtime(T) :- 49 | % clear the clock before start counting 50 | statistics(cpu_time, [_, _]), 51 | % or any other rule(s) / relation(s) /... here 52 | reverse_2d(X, [[1,2,3],[4,5,6]]), 53 | % T is the time since last call of the clock 54 | statistics(cpu_time, [_ , T]). 55 | 56 | % how to check if a 2d list is the same / different as its reverse? 57 | % sample usage: 58 | % reverse_stable([[1,2,3],[4,5,6]], RX). 59 | % reverse_stable([[1,2,1],[6,3,6]], RX). 60 | % reverse_unstable([[1,2,3],[4,5,6]], RX). 61 | % reverse_unstable([[1,2,1],[6,3,6]], RX). 62 | reverse_stable(X, RX) :- 63 | reverse_2d(X, RX), 64 | X = RX. 65 | reverse_unstable(X, RX) :- 66 | reverse_2d(X, RX), 67 | X \= RX. -------------------------------------------------------------------------------- /Prolog/plain_domain.pl: -------------------------------------------------------------------------------- 1 | % hint of accelerating plain_tower 2 | 3 | % a list contain N elements 4 | % http://www.gprolog.org/manual/html_node/gprolog033.html 5 | % http://www.gprolog.org/manual/gprolog.html#hevea_default674 6 | % Domain is all the enumerated answers of between(1, N, X) 7 | within_domain(N, Domain) :- 8 | findall(X, between(1, N, X), Domain). 9 | 10 | % fill in a 2D array with lists of fixed length (N) 11 | % http://www.gprolog.org/manual/gprolog.html#sec215 12 | fill_2d([], _). 13 | fill_2d([Head | Tail], N) :- 14 | within_domain(N, Domain), 15 | permutation(Domain, Head), 16 | fill_2d(Tail, N). 17 | 18 | % here is an example that it might help you with... 19 | % but you know this is not the final answer... 20 | % for example, try calling 21 | % create_grid(Grid, 3). 22 | create_grid(Grid, N) :- 23 | length(Grid, N), 24 | fill_2d(Grid, N). 25 | -------------------------------------------------------------------------------- /Prolog/readme.md: -------------------------------------------------------------------------------- 1 | # Hint Code for Prolog 2 | 3 | ## About 4 | * Still, not mandatory to be used. 5 | * Remember it is gnu-prolog, not swi-prolog 6 | 7 | ## Getting Started 8 | - Open terminal and type in gprolog to the toplevel, and exit by CTRL&D or CTRL&C + e 9 | - [visualization](http://www.cdglabs.org/prolog/#/) 10 | 11 | ### Example 12 | 1. Have your code ready in, e.g. *hello.pl* 13 | 2. Enter gprolog to the toplevel. 14 | 3. From prolog toplevel, consult your code by either of the following ways: 15 | * ```[hello].``` 16 | * ```consult(hello).``` 17 | 4. Then you can run all the queries. e.g. ```ancestor(john,Who).``` 18 | 5. To debug: trace. (and exit by notrace.) 19 | 20 | ## About the Files 21 | * [hello.pl](./hello.pl) 22 | * Hint to get you started on prolog, containing the basic syntax. 23 | * [examples.pl](./examples.pl) 24 | * Some more-complex examples. 25 | * [unique_list.pl](./unique_list.pl) 26 | * An example from Kimmo's old slides, a showcase telling you the difference between **declarative** programming languages and imperative languages. 27 | * [sudoku_cell.pl](./sudoku_cell.pl) 28 | * Hint code on basis of finite-domain solver. 29 | * [list2D_hint.pl](./list2D_hint.pl) 30 | * Some examples on how to deal with a 2D array in prolog. 31 | * [plain_domain.pl](./plain_domain.pl) 32 | * A piece of hint that might help you implement plain_tower with higher efficiency! 33 | * [check_row_unique.pl](./check_row_unique.pl) 34 | * Suggests one way of using the library function *sort* for easier checking within each line. (For columns consider [transpose](https://github.com/CS131-TA-team/UCLA_CS131_CodeHelp/blob/master/Prolog/sudoku_cell.pl#L28-L34)) 35 | * [show_cut.pl](./show_cut.pl) 36 | * Showing the impact of cut. -------------------------------------------------------------------------------- /Prolog/show_cut.pl: -------------------------------------------------------------------------------- 1 | % a silly example showing cut has influence 2 | 3 | a(X) :- b(X), !, c(X). % no answer 4 | a_nocut(X) :- b(X), c(X). 5 | b(1). 6 | b(2). 7 | b(3). 8 | 9 | c(2). 10 | 11 | 12 | % another silly example showing cut has incluences 13 | 14 | d(X, Y) :- e(X), f(Y), !, g(X, Y). % no answer 15 | d_nocut(X, Y) :- e(X), f(Y), g(X, Y). 16 | e(2). 17 | e(1). 18 | f(2). 19 | f(1). 20 | g(1,1). 21 | g(1,2). 22 | g(2,1). 23 | 24 | 25 | -------------------------------------------------------------------------------- /Prolog/sudoku_cell.pl: -------------------------------------------------------------------------------- 1 | sudoku_cell(N, X) :- 2 | % array size limits 3 | len_row(X, N), 4 | len_col(X, N), 5 | % finish domain limits 6 | within_domain(X, N), 7 | maplist(fd_all_different, X), 8 | transpose(X, T), 9 | maplist(fd_all_different, T), 10 | maplist(fd_labeling, X). 11 | 12 | len_row(X, N) :- 13 | length(X, N). 14 | 15 | len_col([], _). 16 | len_col([HD | TL], N) :- 17 | length(HD, N), 18 | len_col(TL, N). 19 | 20 | within_domain([], _). 21 | within_domain([HD | TL], N) :- 22 | % http://www.gprolog.org/manual/html_node/gprolog057.html fd_domain(Vars, Lower, Upper) 23 | fd_domain(HD, 1, N), 24 | within_domain(TL, N). 25 | 26 | % This is SWI-prolog's old implementation 27 | % https://stackoverflow.com/questions/4280986/how-to-transpose-a-matrix-in-prolog 28 | transpose([], []). 29 | transpose([F|Fs], Ts) :- 30 | transpose(F, [F|Fs], Ts). 31 | transpose([], _, []). 32 | transpose([_|Rs], Ms, [Ts|Tss]) :- 33 | lists_firsts_rests(Ms, Ts, Ms1), 34 | transpose(Rs, Ms1, Tss). 35 | lists_firsts_rests([], [], []). 36 | lists_firsts_rests([[F|Os]|Rest], [F|Fs], [Os|Oss]) :- 37 | lists_firsts_rests(Rest, Fs, Oss). 38 | 39 | -------------------------------------------------------------------------------- /Prolog/unique_list.pl: -------------------------------------------------------------------------------- 1 | % rule-based thinking 2 | unique_list1(List, N) :- 3 | length(List, N), 4 | elements_between(List, 1, N), 5 | all_unique(List). 6 | 7 | elements_between(List, Min, Max) :- 8 | maplist(between(Min,Max), List). 9 | 10 | all_unique([]). 11 | all_unique([H|T]) :- exists(H, T), !, fail. 12 | all_unique([H|T]) :- all_unique(T). 13 | 14 | exists(X, [X|_]). 15 | exists(X, [_|T]) :- 16 | exists(X, T). 17 | 18 | % fd solver 19 | unique_list_fd(List, N) :- 20 | length(List,N), 21 | fd_domain(List, 1, N), 22 | fd_all_different(List), 23 | fd_labeling(List). 24 | 25 | % somewhat function-based thinking 26 | % but this way wouldn't work - why? 27 | unique_list2(List, N) :- 28 | range(Unique, N), 29 | permutation(Unique, List). 30 | 31 | range([], 0). 32 | range(A, N) :- 33 | range(A_prev, N-1), 34 | append(A_prev, [N], A). 35 | 36 | % unique_list(List, 6). 37 | 38 | 39 | -------------------------------------------------------------------------------- /Python/aiohttp_example.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import aiohttp 3 | 4 | API_KEY = '' 5 | latitude = "+34.068930" 6 | longitude = "-118.445127" 7 | loc = "{0},{1}".format(latitude, longitude) 8 | rad = 10 9 | 10 | url = 'https://maps.googleapis.com/maps/api/place/nearbysearch/json?key={0}&location={1}&radius={2}'.format(API_KEY, loc, rad) 11 | 12 | 13 | async def simple_case(url): 14 | async with aiohttp.ClientSession( 15 | connector=aiohttp.TCPConnector( 16 | ssl=False, 17 | ), 18 | ) as session: 19 | async with session.get(url) as resp: 20 | response = await resp.json() 21 | print(response) 22 | 23 | 24 | asyncio.run(simple_case(url)) -------------------------------------------------------------------------------- /Python/asyncio_advanced.py: -------------------------------------------------------------------------------- 1 | # code from https://realpython.com/async-io-python/ 2 | # this piece of code is more than what is needed for your project 3 | #!/usr/bin/env python3 4 | # asyncq.py 5 | 6 | import asyncio 7 | import itertools as it 8 | import os 9 | import random 10 | import time 11 | 12 | async def makeitem(size: int = 5) -> str: 13 | return os.urandom(size).hex() 14 | 15 | async def randsleep(a: int = 1, b: int = 5, caller=None) -> None: 16 | i = random.randint(0, 10) 17 | if caller: 18 | print(f"{caller} sleeping for {i} seconds.") 19 | await asyncio.sleep(i) 20 | 21 | async def produce(name: int, q: asyncio.Queue) -> None: 22 | n = random.randint(0, 10) 23 | for _ in it.repeat(None, n): # Synchronous loop for each single producer 24 | await randsleep(caller=f"Producer {name}") 25 | i = await makeitem() 26 | t = time.perf_counter() 27 | await q.put((i, t)) 28 | print(f"Producer {name} added <{i}> to queue.") 29 | 30 | async def consume(name: int, q: asyncio.Queue) -> None: 31 | while True: 32 | await randsleep(caller=f"Consumer {name}") 33 | i, t = await q.get() 34 | now = time.perf_counter() 35 | print(f"Consumer {name} got element <{i}>" 36 | f" in {now-t:0.5f} seconds.") 37 | q.task_done() 38 | 39 | async def main(nprod: int, ncon: int): 40 | q = asyncio.Queue() 41 | producers = [asyncio.create_task(produce(n, q)) for n in range(nprod)] 42 | consumers = [asyncio.create_task(consume(n, q)) for n in range(ncon)] 43 | await asyncio.gather(*producers) 44 | await q.join() # Implicitly awaits consumers, too 45 | for c in consumers: 46 | c.cancel() 47 | 48 | if __name__ == "__main__": 49 | import argparse 50 | random.seed(444) 51 | parser = argparse.ArgumentParser() 52 | parser.add_argument("-p", "--nprod", type=int, default=5) 53 | parser.add_argument("-c", "--ncon", type=int, default=10) 54 | ns = parser.parse_args() 55 | start = time.perf_counter() 56 | asyncio.run(main(**ns.__dict__)) 57 | elapsed = time.perf_counter() - start 58 | print(f"Program completed in {elapsed:0.5f} seconds.") -------------------------------------------------------------------------------- /Python/asyncio_basic.py: -------------------------------------------------------------------------------- 1 | ''' 2 | adapted from Kimmo's previous year's slides 3 | thank you Kimmo for the example 4 | ''' 5 | 6 | import asyncio 7 | import time 8 | 9 | async def count(task_id): 10 | print("One {}".format(task_id)) 11 | await asyncio.sleep(task_id) # Any IO-intensive task here 12 | print("Two {}".format(task_id)) 13 | 14 | async def main(): 15 | # it shows that they are actually executed in parallel! Please see the time printed out 16 | await asyncio.gather(count(1), count(2), count(3)) 17 | 18 | if __name__ == "__main__": 19 | s = time.perf_counter() 20 | asyncio.run(main()) # Add to an event loop 21 | elapsed = time.perf_counter() - s 22 | print(f"{__file__} executed in {elapsed:0.2f} seconds.") -------------------------------------------------------------------------------- /Python/asyncio_context.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import contextvars 3 | 4 | # declare context var 5 | request_id = contextvars.ContextVar('Id of request.') 6 | 7 | 8 | async def some_inner_coroutine(): 9 | # get value 10 | print('Processed inner coroutine of request: {}'.format(request_id.get())) 11 | 12 | 13 | async def some_outer_coroutine(req_id): 14 | # set value 15 | request_id.set(req_id) 16 | 17 | await some_inner_coroutine() 18 | 19 | # get value 20 | print('Processed outer coroutine of request: {}'.format(request_id.get())) 21 | 22 | 23 | async def main(): 24 | tasks = [] 25 | for req_id in range(1, 5): 26 | tasks.append(asyncio.create_task(some_outer_coroutine(req_id))) 27 | 28 | await asyncio.gather(*tasks) 29 | 30 | 31 | if __name__ == '__main__': 32 | asyncio.run(main()) -------------------------------------------------------------------------------- /Python/asyncio_naive.py: -------------------------------------------------------------------------------- 1 | ''' 2 | another silly example 3 | ''' 4 | 5 | import asyncio 6 | import time 7 | 8 | def ending_condition(num, odd_or_even="odd"): 9 | if num > 1: return None 10 | if (num == 1 and odd_or_even == "odd") or (num == 1 and odd_or_even == "even"): return True 11 | return False 12 | 13 | async def is_odd(num): 14 | ends = ending_condition(num, "odd") 15 | if ends is not None: 16 | return ends 17 | else: 18 | return not await is_even(num - 1) 19 | 20 | async def is_even(num): 21 | ends = ending_condition(num, "even") 22 | if ends is not None: 23 | return ends 24 | else: 25 | return not await is_odd(num - 1) 26 | 27 | async def main(num): 28 | if not isinstance(num, int): 29 | print("I can only handle integers") 30 | elif num < 0: 31 | print("I can't handle negative number") 32 | else: 33 | odd_flag = await is_odd(num) 34 | print("{0} is {1}".format(num, "odd" if odd_flag else "even")) 35 | 36 | if __name__ == "__main__": 37 | s = time.perf_counter() 38 | asyncio.run(main(10)) # Add to an event loop 39 | elapsed = time.perf_counter() - s 40 | print(f"{__file__} executed in {elapsed:0.2f} seconds.") -------------------------------------------------------------------------------- /Python/asyncio_syntax.py: -------------------------------------------------------------------------------- 1 | ''' 2 | simplest example, only here to show the syntax 3 | ''' 4 | 5 | import asyncio 6 | 7 | async def f(): 8 | print("called f") 9 | return True 10 | 11 | async def g(): 12 | # Pause here and come back to g() when f() is ready 13 | r = await f() 14 | return r 15 | 16 | 17 | if __name__ == "__main__": 18 | asyncio.run(g()) # Add to an event loop -------------------------------------------------------------------------------- /Python/asyncio_task.py: -------------------------------------------------------------------------------- 1 | # official example 2 | # from https://docs.python.org/3/library/asyncio-task.html 3 | 4 | import asyncio 5 | import time 6 | 7 | async def say_after(delay, what): 8 | await asyncio.sleep(delay) 9 | print(what) 10 | 11 | async def main(): 12 | 13 | # defined, but wouldn't be called until we run them by saying: await 14 | task1 = asyncio.create_task( 15 | say_after(1, 'hello')) 16 | 17 | task2 = asyncio.create_task( 18 | say_after(2, 'world')) 19 | 20 | print(f"started at {time.strftime('%X')}") 21 | 22 | # Wait until both tasks are completed (should take 23 | # around 2 seconds.) 24 | await task1 25 | await task2 26 | 27 | print(f"finished at {time.strftime('%X')}") 28 | 29 | asyncio.run(main()) -------------------------------------------------------------------------------- /Python/dict_and_class.py: -------------------------------------------------------------------------------- 1 | """ 2 | python example on dictionary and class usages and important tricks 3 | """ 4 | 5 | # nevermind this is my tool to make beautiful print, you don't need it 6 | # but I also use this as an example to show you how simple class works 7 | # notice the difference between variables of a class and variables of an object 8 | # notice the special function's usage 9 | # in fact, (object) is optional in syntax since it is by default an object already 10 | # we can simply do: 11 | # class Colors: 12 | # and it works exactly the same way 13 | 14 | 15 | class Colors(object): 16 | # these are the values of the whole class 17 | # it means that you have access to them after you define the class 18 | # you don't have to call them through any instance (object) 19 | PURPLE = '\033[95m' 20 | CYAN = '\033[96m' 21 | DARKCYAN = '\033[36m' 22 | BLUE = '\033[94m' 23 | GREEN = '\033[92m' 24 | YELLOW = '\033[93m' 25 | RED = '\033[91m' 26 | BOLD = '\033[1m' 27 | UNDERLINE = '\033[4m' 28 | END = '\033[0m' 29 | 30 | # here are some of the special methods of a python class 31 | def __init__(self, name=None): 32 | """ 33 | the initialize function is called whenever we initialize an object of this class 34 | called when, e.g. 35 | color = Colors("my colors") 36 | note that name has default value (None), so name is optional 37 | if we receive name, name is a field of this object we are initializing, not the whole class 38 | """ 39 | self.name = name 40 | 41 | def __repr__(self): 42 | """ 43 | observed when calling from interpreter directly 44 | for example, with color = Colors("my colors") 45 | if we call from the command line: 46 | color 47 | then we'll see the following line printed 48 | """ 49 | return f"repr: color object \"{self.name}\"" 50 | 51 | def __str__(self): 52 | """ 53 | called when converting this object into a string: (assuming color=Colors("my colors")) 54 | print(color) 55 | str(color) 56 | """ 57 | return f"object \"{self.name}\" converted to string" 58 | 59 | def __call__(self, text=None): 60 | """ 61 | this is called when: 62 | color() 63 | color(text) 64 | """ 65 | print("it makes no sense to do this in this case, I am simply showing you the usage of __call__") 66 | return text 67 | 68 | # there are of course many other interesting built-in functions in python, but I don't think you need them 69 | # actually it is not mandatory to use class for your project 70 | @staticmethod 71 | def bold(text): 72 | return Colors.BOLD + text + Colors.END 73 | 74 | @staticmethod 75 | def red(text): 76 | return Colors.RED + text + Colors.END 77 | 78 | @staticmethod 79 | def yellow(text): 80 | return Colors.YELLOW + text + Colors.END 81 | 82 | @staticmethod 83 | def blue(text): 84 | return Colors.BLUE + text + Colors.END 85 | 86 | @staticmethod 87 | def green(text): 88 | return Colors.GREEN + text + Colors.END 89 | 90 | 91 | # generator 92 | def batch_generator(dataset, batch_size=64): 93 | """ 94 | dataset in this case is expected to be a list 95 | batch_size has default value 64 96 | sample usage: 97 | dataset = list(range(1000)) 98 | batches = batch_generator(dataset) 99 | print(next(batches)) 100 | print(next(batches)) 101 | """ 102 | max_length = len(dataset) 103 | cursor_index = 0 104 | while cursor_index < max_length: 105 | cursor_index += batch_size 106 | yield dataset[cursor_index-batch_size:cursor_index] 107 | 108 | 109 | # dictionary 110 | my_dict = { 111 | 1: "integer", 112 | "2": {2}, 113 | 3: 3, 114 | 4: (4,), 115 | (5, 6): "pair" 116 | } 117 | # my_dict.keys() 118 | # my_dict.values() 119 | # my_dict.items() 120 | 121 | 122 | def dict_from_keys_values(keys_list, values_list): 123 | """ 124 | this is a very important usage of zip 125 | will likely to accelerate your code dramatically compared with iteration 126 | """ 127 | return dict(zip(keys_list, values_list)) 128 | 129 | 130 | def create_vocabulary(word_list): 131 | vocabulary = dict.fromkeys(word_list, 0) 132 | for word in word_list: 133 | vocabulary[word] += 1 134 | vocabulary = sort_by_value(vocabulary) # sorted by values from small to large 135 | return vocabulary 136 | 137 | 138 | def sort_by_value(d, reverse=False): 139 | return dict(sorted(d.items(), key=lambda x: x[1], reverse=reverse)) 140 | 141 | 142 | if __name__ == '__main__': 143 | color = Colors("my colors") 144 | color() 145 | print("showing the keys of my_dict using {}".format(color.bold("enumerate"))) 146 | for i, k in enumerate(my_dict.keys()): 147 | print(f"\tthe {i}-th key is {k}") 148 | for v, pair in zip(my_dict.values(), my_dict.items()): 149 | print(f"\tthe value {v} comes from the key-value pair {pair}") 150 | print("this is an example showing how to create a dictionary from key list and value list " 151 | "(and a scenario showing some other features of dict BTW)") 152 | dataset_example = ["hello", "world", "hello", "every", "one", 153 | "this", "is", "a", "sample", "test", "case", 154 | "for", "every", "one", "of", "you", 155 | "to", "get", "a", "better", "understanding", 156 | "on", "how", "flexible", "a", "dictionary", "could", "be"] 157 | vocabulary = create_vocabulary(dataset_example) 158 | unique_words = list(vocabulary.keys()) 159 | reversed_dict = dict_from_keys_values(unique_words, range(len(unique_words))) 160 | print(reversed_dict) 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | -------------------------------------------------------------------------------- /Python/echo_client.py: -------------------------------------------------------------------------------- 1 | """ 2 | Note that this piece of code is (of course) only a hint 3 | you are not required to use it 4 | neither do you have to use any of the methods mentioned here 5 | The code comes from 6 | https://asyncio.readthedocs.io/en/latest/tcp_echo.html 7 | 8 | To run: 9 | 1. start the echo_server.py first in a terminal 10 | 2. start the echo_client.py in another terminal 11 | 3. follow print-back instructions on client side until you quit 12 | """ 13 | 14 | import asyncio 15 | 16 | 17 | class Client: 18 | def __init__(self, ip='127.0.0.1', port=8888, name='client', message_max_length=1e6): 19 | """ 20 | 127.0.0.1 is the localhost 21 | port could be any port 22 | """ 23 | self.ip = ip 24 | self.port = port 25 | self.name = name 26 | self.message_max_length = int(message_max_length) 27 | 28 | async def tcp_echo_client(self, message): 29 | """ 30 | on client side send the message for echo 31 | """ 32 | reader, writer = await asyncio.open_connection(self.ip, self.port) 33 | print(f'{self.name} send: {message!r}') 34 | writer.write(message.encode()) 35 | 36 | data = await reader.read(self.message_max_length) 37 | print(f'{self.name} received: {data.decode()!r}') 38 | 39 | print('close the socket') 40 | # The following lines closes the stream properly 41 | # If there is any warning, it's due to a bug o Python 3.8: https://bugs.python.org/issue38529 42 | # Please ignore it 43 | writer.close() 44 | 45 | def run_until_quit(self): 46 | # start the loop 47 | while True: 48 | # collect the message to send 49 | message = input("Please input the next message to send: ") 50 | if message in ['quit', 'exit', ':q', 'exit;', 'quit;', 'exit()', '(exit)']: 51 | break 52 | else: 53 | asyncio.run(self.tcp_echo_client(message)) 54 | 55 | 56 | if __name__ == '__main__': 57 | client = Client() # using the default settings 58 | client.run_until_quit() 59 | -------------------------------------------------------------------------------- /Python/echo_server.py: -------------------------------------------------------------------------------- 1 | """ 2 | Note that this piece of code is (of course) only a hint 3 | you are not required to use it 4 | neither do you have to use any of the methods mentioned here 5 | The code comes from 6 | https://asyncio.readthedocs.io/en/latest/tcp_echo.html 7 | 8 | To run: 9 | 1. start the echo_server.py first in a terminal 10 | 2. start the echo_client.py in another terminal 11 | 3. follow print-back instructions on client side until you quit 12 | """ 13 | 14 | import asyncio 15 | import argparse 16 | 17 | 18 | class Server: 19 | def __init__(self, name, ip='127.0.0.1', port=8888, message_max_length=1e6): 20 | self.name = name 21 | self.ip = ip 22 | self.port = port 23 | self.message_max_length = int(message_max_length) 24 | 25 | async def handle_echo(self, reader, writer): 26 | """ 27 | on server side 28 | """ 29 | data = await reader.read(self.message_max_length) 30 | message = data.decode() 31 | addr = writer.get_extra_info('peername') 32 | print("{} received {} from {}".format(self.name, message, addr)) 33 | 34 | sendback_message = message 35 | 36 | print("{} send: {}".format(self.name, sendback_message)) 37 | writer.write(sendback_message.encode()) 38 | await writer.drain() 39 | 40 | print("close the client socket") 41 | writer.close() 42 | 43 | async def run_forever(self): 44 | server = await asyncio.start_server(self.handle_echo, self.ip, self.port) 45 | 46 | # Serve requests until Ctrl+C is pressed 47 | print(f'serving on {server.sockets[0].getsockname()}') 48 | async with server: 49 | await server.serve_forever() 50 | # Close the server 51 | server.close() 52 | 53 | 54 | def main(): 55 | parser = argparse.ArgumentParser('CS131 project example argument parser') 56 | parser.add_argument('server_name', type=str, 57 | help='required server name input') 58 | args = parser.parse_args() 59 | 60 | print("Hello, welcome to server {}".format(args.server_name)) 61 | 62 | server = Server(args.server_name) 63 | try: 64 | asyncio.run(server.run_forever()) 65 | except KeyboardInterrupt: 66 | pass 67 | 68 | 69 | if __name__ == '__main__': 70 | main() 71 | -------------------------------------------------------------------------------- /Python/flooding_hint.py: -------------------------------------------------------------------------------- 1 | """ 2 | you may also use this as the starter hint on flooding algorithm 3 | this is not the real flooding, since we don't use asyncio here 4 | but the algorithm should be basically as simple as this 5 | hint: probably consider OTHER ways than using Kid.secrets for keeping track of who knows the secret 6 | """ 7 | from collections import defaultdict 8 | 9 | 10 | class Kid: 11 | secrets = defaultdict(set) 12 | 13 | def __init__(self, name): 14 | self.name = name 15 | self.known_secret = list() 16 | self.friends = list() 17 | 18 | def __call__(self): 19 | print(f"{self.name}'s secrets:") 20 | for i, secret in enumerate(self.known_secret): 21 | print(f"{i})\t{secret}") 22 | 23 | def befriend(self, other, mutual=True): 24 | self.friends.append(other) 25 | if mutual: 26 | other.friends.append(self) 27 | 28 | def known(self, message): 29 | return self.name in Kid.secrets[message] 30 | 31 | def share(self, message): 32 | if not self.known(message): 33 | self.known_secret.append(message) 34 | Kid.secrets[message].add(self.name) 35 | for friend in self.friends: 36 | friend.share(message) 37 | 38 | def hear(self, message): 39 | self.share(message) 40 | 41 | 42 | if __name__ == '__main__': 43 | alice = Kid('Alice') 44 | bob = Kid('Bob') 45 | cathy = Kid('Cathy') 46 | alice.befriend(bob) 47 | alice.befriend(cathy) 48 | bob.befriend(cathy) 49 | 50 | alice.share("The King has ears shaped like a donkey!") 51 | bob.share("There's a silver nutmeg and a golden pear on my little nut tree.") 52 | 53 | print(Kid.secrets) 54 | 55 | cathy() 56 | -------------------------------------------------------------------------------- /Python/json_hint.py: -------------------------------------------------------------------------------- 1 | ''' 2 | json package documentation: 3 | https://docs.python.org/3/library/json.html 4 | ''' 5 | 6 | import json 7 | 8 | def string2json(json_string): 9 | return json.loads(json_string) 10 | 11 | def json2string(json_data): 12 | ''' 13 | actually indent is optional, simply putting here to make it look better 14 | so as below in save_json 15 | ''' 16 | return json.dumps(json_data, indent=4) 17 | 18 | def save_json(json_file, data): 19 | ''' 20 | encoding and ensure_ascii are here to make this piece of code more robust in practice 21 | indent is here to make it look pretty and well-organized 22 | actually without indentation it takes less space 23 | ''' 24 | with open(json_file, mode='w', encoding="utf-8") as outfile: 25 | json.dump(data, outfile, ensure_ascii=False, indent=4) 26 | 27 | def load_json(json_file): 28 | with open(json_file, mode='r', encoding="utf-8") as infile: 29 | data = json.load(infile) 30 | return data 31 | 32 | toydata = {'people':[{'first_name': 'Zhiping', 'middle_name': None, 'last_name': 'Xiao', 'nickname': 'Patricia'}]} 33 | fname = "./toy_sample_json.json" 34 | 35 | toydata_string = json2string(toydata) 36 | 37 | print(toydata_string) 38 | 39 | save_json(fname, toydata) 40 | print(load_json(fname)) -------------------------------------------------------------------------------- /Python/message_hint.py: -------------------------------------------------------------------------------- 1 | """ 2 | hint specifically on message contents and how to deal with them 3 | again, this is not the final answer, not even necessarily part of the final answer 4 | not even close to the right answer, nothing is handled carefully 5 | """ 6 | 7 | import time 8 | import json 9 | 10 | 11 | class ClientMessage: 12 | def __init__(self, client_id="kiwi.cs.ucla.edu", coordinates="+34.068930-118.445127"): 13 | self.client_id = client_id 14 | self.coordinates = coordinates 15 | 16 | def text(self, command_name, **kwargs): 17 | command_table = { 18 | 'IAMAT': self.i_am_at(), 19 | 'WHATSAT': self.whats_at(**kwargs) 20 | } 21 | return command_table.get(command_name, "") 22 | 23 | def i_am_at(self): 24 | """ 25 | reporting where am I at 26 | """ 27 | return f"IAMAT {self.client_id} {self.coordinates} {time.time()}" 28 | 29 | def whats_at(self, another_client=None, radius=0, max_results=0): 30 | """ 31 | get at most max_results places within the radius centered around another client 32 | those locations are expected to be given by Google Map 33 | the unit of radius is kilometer 34 | """ 35 | if another_client is None: 36 | another_client = self.client_id 37 | return f"WHATSAT {another_client} {radius} {max_results}" 38 | 39 | 40 | class ServerMessage: 41 | history = dict() 42 | 43 | def __init__(self, server_name="whatever_server"): 44 | self.server_name = server_name 45 | self.known_command = ["WHATSAT", "IAMAT"] 46 | 47 | def __call__(self, message): 48 | return self.parse_message(message) if len(message) else "ERROR: empty message" 49 | 50 | def parse_message(self, message): 51 | command_table = { 52 | "IAMAT": self.handle_i_am_at, 53 | "WHATSAT": self.handle_whats_at 54 | } 55 | message_list = [msg for msg in message.strip().split() if len(msg)] 56 | if len(message_list) != 4: 57 | return "ERROR: invalid command length" 58 | cmd = command_table.get(message_list[0], lambda x, y, z: f"ERROR: command name {message_list[0]} unrecognized") 59 | return cmd(*message_list[1:]) 60 | 61 | def handle_i_am_at(self, client_id, coordinates, timestamp): 62 | time.sleep(2) # sleep 2 seconds 63 | msg = f"AT {self.server_name} +{time.time() - float(timestamp)} {client_id} {coordinates} {timestamp}" 64 | ServerMessage.history[client_id] = msg 65 | return msg 66 | 67 | def handle_whats_at(self, client_id, radius, max_results): 68 | nonsense_json = ['foo', {'bar': ['baz', None, 1.0, 2]}] 69 | google_api_feedback = json.dumps(nonsense_json, indent=4) 70 | return ServerMessage.history[client_id] + "\n" + google_api_feedback 71 | 72 | 73 | if __name__ == '__main__': 74 | client_message = ClientMessage(client_id="whatever_name") 75 | print(client_message.text("IAMAT")) 76 | print(client_message.text("WHATSAT", another_client="kiwi.cs.ucla.edu", radius=10, max_results=5)) 77 | server_message = ServerMessage() 78 | print(server_message(client_message.text("IAMAT"))) 79 | print(server_message(client_message.text("WHATSAT"))) 80 | 81 | -------------------------------------------------------------------------------- /Python/readme.md: -------------------------------------------------------------------------------- 1 | # Hint Code for Project 2 | 3 | ## Warnings 4 | - Some previous students said that they sisn't get along well with the grading script using ```transport.write()```, but some other students passed everything using ```transport.write()```. There might be some tricky things going on in this part. Please be aware that there could be potentially some problems. 5 | 6 | ## Python Basics 7 | 8 | - [dict_and_class.py](./dict_and_class.py): The use of Python data structures like dictionary and class. 9 | - [message_hint.py](./message_hint.py): An example showing how you could handle message elegantly with classes. Not necessarily implemented this way, message handlers could be integrated directly into your server-class; or you could do without any class. It is also doable if you don't use class at all. 10 | 11 | ## asyncio Basics 12 | - [asyncio_syntax.py](./asyncio_syntax.py): asyncio basic syntax example. 13 | - [asyncio_basic.py](./asyncio_basic.py): asyncio basic usage. 14 | - [asyncio_naive.py](./asyncio_naive.py): another silly example. 15 | - [asyncio_task.py](./asyncio_task.py): an example using tasks. 16 | - (\*) [asyncio_advanced.py](./asyncio_advanced.py): more advanced usage that is not really required for this project. 17 | - (\*) [asyncio_context.py](./asyncio_context.py): more advanced usage, about keeping coroutine-local context, not required. 18 | - [echo_server.py](./echo_server.py) and [echo_client.py](./echo_client.py) 19 | * usage: ```python echo_server.py Hello``` and then ```python echo_client.py``` 20 | * could be other names for the server, I am including the name option as a must so as to show you how to use the command line arguments (required for this project). 21 | * they are the real starter hints for this project. 22 | 23 | ## The Flooding Algorithm 24 | 25 | - [flooding_hint.py](./flooding_hint.py): the idea of the floading algorithm in general, but shouldn't be how it is implemented in the end, please consider asyncio. 26 | - More hints: you can consider using timestamp to tell if a message is already received & processed by the current server! 27 | - How to store the messages received? Completely up to you. e.g. a dictionary, a list, another object of your self-defined class, etc. 28 | 29 | ## aiohttp Basics 30 | -[aiohttp_example.py](./aiohttp_example.py): the example of an aiohttp simplest illustration. the setting of ssl is to ensure it works on your laptop as well. 31 | 32 | ## The json Format 33 | 34 | - [json_hint.py](./json_hint.py): if you are not familiar with json format (will need it for the map API part), please check it out here. 35 | - Wait I mean you don't need to really store a json file... that is slightly more than needed for this project. 36 | 37 | ## How to test your code 38 | 39 | - Check the [sample grading scripts](https://github.com/CS131-TA-team/CS131-Project-Sample-Grading-Script) 40 | - Obviously it is not the real grading scripts, but the components I use to check for the correctness are almost the same (scoring function is not the same --- the version you see here is obviously an intermediate version, and in the current version, you should expect all outputs be "True") 41 | - Do not ask for your friends' code from previous quarters, we are changing the test cases. 42 | - Be sure to implement **whatever the spec requests**. 43 | - An **important** suggestion: please avoid using json file / txt file as configuration file! If you want to put your API keys into a separated file, try using *config.py* to hold it! Also, if you put your log file into a folder, please write the logic of **creating** that folder as well! 44 | - Only if when you put your *server.py* under the sample submission folder, and **directly** set it to run, without any additional action required, your script is safe to submit. 45 | - Please design your own test cases using the sample grading script we offer you. The existing samples for now are too naive. 46 | -------------------------------------------------------------------------------- /Scheme/Xinyu_stronger_test_cases.rkt: -------------------------------------------------------------------------------- 1 | (expr-compare '(cons a lambda) '(cons a λ)) 2 | ; => '(cons a (if % lambda λ)) 3 | (expr-compare '(lambda (a) a) '(lambda (b) b)) 4 | ; => '(lambda (a!b) a!b) 5 | (expr-compare '(lambda (a) b) '(cons (c) b)) 6 | ; => '(if % (lambda (a) b) (cons (c) b)) 7 | (expr-compare '((λ (if) (+ if 1)) 3) '((lambda (fi) (+ fi 1)) 3)) 8 | ; => '((λ (if!fi) (+ if!fi 1)) 3) 9 | (expr-compare '(lambda (lambda) lambda) '(λ (λ) λ)) 10 | ; => '(λ (lambda!λ) lambda!λ) 11 | (expr-compare ''lambda '(quote λ)) 12 | ; => '(if % 'lambda 'λ) 13 | (expr-compare '(lambda (a b) a) '(λ (b) b)) 14 | ; => '(if % (lambda (a b) a) (λ (b) b)) 15 | (expr-compare '(λ (a b) (lambda (b) b)) '(lambda (b) (λ (b) b))) 16 | ; => '(if % (λ (a b) (lambda (b) b)) (lambda (b) (λ (b) b))) 17 | (expr-compare '(λ (let) (let ((x 1)) x)) '(lambda (let) (let ((y 1)) y))) 18 | ; => '(λ (let) (let (((if % x y) 1)) (if % x y))) 19 | (expr-compare '(λ (x) ((λ (x) x) x)) 20 | '(λ (y) ((λ (x) y) x))) 21 | ; ⇒ '(λ (x!y) ((λ (x) (if % x x!y)) (if % x!y x))) 22 | (expr-compare '(((λ (g) 23 | ((λ (x) (g (λ () (x x)))) ; This is the way we define a recursive function 24 | (λ (x) (g (λ () (x x)))))) ; when we don't have 'letrec' 25 | (λ (r) ; Here (r) will be the function itself 26 | (λ (n) (if (= n 0) 27 | 1 28 | (* n ((r) (- n 1))))))) ; Therefore this thing calculates factorial of n 29 | 10) 30 | '(((λ (x) 31 | ((λ (n) (x (λ () (n n)))) 32 | (λ (r) (x (λ () (r r)))))) 33 | (λ (g) 34 | (λ (x) (if (= x 0) 35 | 1 36 | (* x ((g) (- x 1))))))) 37 | 9)) 38 | ; ⇒ '(((λ (g!x) 39 | ; ((λ (x!n) (g!x (λ () (x!n x!n)))) 40 | ; (λ (x!r) (g!x (λ () (x!r x!r)))))) 41 | ; (λ (r!g) 42 | ; (λ (n!x) (if (= n!x 0) 43 | ; 1 44 | ; (* n!x ((r!g) (- n!x 1))))))) 45 | ; (if % 10 9)) 46 | -------------------------------------------------------------------------------- /Scheme/hello.ss: -------------------------------------------------------------------------------- 1 | #lang racket 2 | #| don't forget to include the first-line above! 3 | otherwise there might be troubles 4 | this file is directly runnable by either 5 | racket hello.ss 6 | or, open it in DrRacket and click run 7 | |# 8 | 9 | (define (square x) 10 | (* x x)) 11 | 12 | ; the sample exercise's answer (from slides) 13 | (define (do-twice f x) (f (f x))) 14 | 15 | ; (my-length '(1 2 3 4)) 16 | (define (my-length lst) 17 | (cond 18 | [(empty? lst) 0] 19 | [else (+ 1 (my-length (rest lst)))] 20 | )) 21 | 22 | ; (eval my-program) 23 | (define my-program '(display "Hello, World!\n")) 24 | 25 | 26 | ; namespace 27 | ; run the file as racket hello.ss 28 | ; or click run in DrRacket 29 | (define ns (make-base-namespace)) 30 | (eval my-program ns) 31 | 32 | ; dynamic eval example 33 | ; possible usage: call from the interpreter: 34 | ; (eval-formula '(+ x y)) 35 | ; (eval-formula '(+ (* x y) y)) 36 | (define (eval-formula formula) 37 | (eval `(let ([x 2] 38 | [y 3]) 39 | ,formula))) 40 | ; this version is with namespace 41 | ; could be evaluated from interpreter or inside this file as shown below 42 | (define (formula-to-eval formula) 43 | `(let ([x 2] [y 3]) ,formula)) 44 | (eval (formula-to-eval '(+ x y)) ns) 45 | (eval (formula-to-eval '(+ (* x y) y)) ns) 46 | 47 | ; a recursive example 48 | ; could be called as, e.g. (fib 10) 49 | (define (fib n) 50 | (cond 51 | [(= n 1) 1] 52 | [(= n 2) 1] 53 | [else (+ (fib (- n 1)) (fib (- n 2)))] 54 | ) 55 | ) 56 | -------------------------------------------------------------------------------- /Scheme/readme.md: -------------------------------------------------------------------------------- 1 | # Hint Code for Scheme 2 | 3 | The relation is that, LISP ==(simplified)==> Scheme ==(a popular variation)==> Racket 4 | 5 | ## Getting Started 6 | - [Official Website](https://racket-lang.org/) (including installation guide, etc.) 7 | - [Official Documentation](https://docs.racket-lang.org/), *including* the [racket guide](https://docs.racket-lang.org/guide/index.html) 8 | - Probably will need to add it to the path manually on your local machine, e.g. if you use mac, then: 9 | ```shell 10 | echo $PATH 11 | PATH=$PATH:/Applications/Racket\ v7.4/bin 12 | ``` 13 | 14 | ## About the Resources 15 | - [hello.ss](./hello.ss) 16 | * Simply a hello-world in Scheme 17 | - [starting_hint.ss](./starting_hint.ss) 18 | * If, by any chance, you can't figure out where to get started, please try to view this problem as solving many different cases one-by-one, and feel free to use this piece of code to get yourself started. 19 | * But this is not the only option, neither the best one. Can you come up with shorter solution / more elegant design of the helper functions? If yes, be confident and use your unique ones instead. 20 | - [Sample Grading Script of HW5 with NO actual test cases (provided by Xinyu)](https://github.com/CS131-TA-team/hw5-grading-script) 21 | * This script will help you avoid compile error, wrong-name error, etc. 22 | - [Stronger Test Cases (Designed by Xinyu)](./Xinyu_stronger_test_cases.txt) 23 | * These test cases will not guarantee you a full score, but will give you a higher chance of spotting bugs 24 | - [An additional Example on LISP Macros](https://github.com/CS131-TA-team/sigma_notation) 25 | -------------------------------------------------------------------------------- /Scheme/starting_hint.ss: -------------------------------------------------------------------------------- 1 | #lang racket 2 | (provide expr-compare) 3 | 4 | #| don't forget to include the lines above! 5 | otherwise there might be troubles 6 | this file is directly runnable by either 7 | racket FILENAME.ss 8 | or, open it in DrRacket and click run 9 | 10 | Also, it can be loaded from racket using 11 | 12 | (require "FILENAME.ss") 13 | 14 | for basic syntax introduction, please see slides and hello.ss 15 | |# 16 | 17 | ; hint on judging lambda 18 | (define (lambda? x) 19 | (member x '(lambda λ))) 20 | 21 | (define (expr-compare x y) 22 | (cond [(equal? x y) x] 23 | [(and (boolean? x) (boolean? y)) 24 | (if x '% '(not %))] 25 | ; if one of them is not list - which means that not function 26 | [(or (not (list? x)) 27 | (not (list? y))) 28 | (list 'if '% x y)] 29 | ; and below here it is your work to figure out how to judge every case 30 | ; but! please pay attention: this is NOT the only structure you could have for solving this homework 31 | ; we actually encourage you to come up with OTHER designs if you can! 32 | ; please only follow this starting hint when you REALLY don't know where to start! 33 | )) 34 | 35 | ; compare and see if the (expr-compare x y) result is the same with x when % = #t 36 | ; and the same with y when % = #f 37 | (define (test-expr-compare x y) 38 | (and (equal? (eval x) 39 | (eval `(let ((% #t)) ,(expr-compare x y)))) 40 | (equal? (eval y) 41 | (eval `(let ((% #f)) ,(expr-compare x y)))))) 42 | 43 | ; WARNING: IT MUST BE A SINGLE TEST CASE 44 | ; You need to cover all grammars including: 45 | ; constant literals, variables, procedure calls, quote, lambda, if 46 | (define test-expr-x 47 | `(cons 12 ((lambda (a) (+ a 1)) 2))) 48 | 49 | (define test-expr-y 50 | `(cons 11 ((lambda (a) (+ a 2)) 3))) 51 | 52 | 53 | ; the following line can be tested from interpreter 54 | ; (eval test-expr-x) 55 | ; (test-expr-compare test-expr-x test-expr-y)) 56 | ; test-expr-compare should return #t after you finish its implementation 57 | ; (expr-compare 'a '(cons a b)) 58 | ; (expr-compare '(cons a b) '(cons a b)) 59 | ; (lambda? 'λ) 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /Xinyu_Interpreter/CPS_OCaml.ml: -------------------------------------------------------------------------------- 1 | type ('a, 'r) cont_monad = ('a -> 'r) -> 'r 2 | 3 | let return value : ('a, 'r) cont_monad = 4 | fun k -> k value 5 | 6 | let (>>=) (step : ('a, 'r) cont_monad) (cont : 'a -> ('b, 'r) cont_monad) : ('b, 'r) cont_monad = 7 | fun k -> step (fun result -> cont result k) 8 | 9 | let call_cc (func : ('a -> ('b, 'r) cont_monad) -> ('a, 'r) cont_monad) : ('a, 'r) cont_monad = 10 | fun k -> func (fun v _ -> k v) k 11 | 12 | let mul_cps lst : (int, 'r) cont_monad = 13 | call_cc (fun k -> 14 | let rec mul_aux = function 15 | | [] -> return 1 16 | | 0::_ -> k 0 17 | | x::xs -> mul_aux xs >>= fun prod -> 18 | return (x * prod) in 19 | mul_aux lst) 20 | -------------------------------------------------------------------------------- /Xinyu_Interpreter/Generator_based_coroutine.py: -------------------------------------------------------------------------------- 1 | import time 2 | import random 3 | from collections import deque 4 | 5 | 6 | def sleep(interval): 7 | start_time = time.time() 8 | cur_time = start_time 9 | while cur_time < start_time + interval: 10 | # Here we use sleep to simulate io delay 11 | yield 12 | cur_time = time.time() 13 | 14 | 15 | def get_from(queue): 16 | while not queue: # while len(queue) == 0: 17 | # We can also use send to transmit the data read 18 | # So we can get the data here 19 | yield 20 | return queue.popleft() 21 | 22 | # ---------------------------------------------- 23 | 24 | def engine(proc_list): 25 | proc_cnt = len(proc_list) 26 | finished_cnt = 0 27 | while finished_cnt < proc_cnt: 28 | # Schedule all routines in order 29 | for i, proc in enumerate(proc_list): 30 | if not proc: 31 | continue 32 | try: 33 | # Schedule the processing routine 34 | next(proc) 35 | except StopIteration: 36 | # The processing is finished 37 | proc_list[i] = None 38 | finished_cnt += 1 39 | time.sleep(0.01) 40 | 41 | # ---------------------------------------------- 42 | 43 | def produce(queue, n): 44 | for x in range(1, n + 1): 45 | # produce an item 46 | print(f'producing {x}/{n}') 47 | # simulate i/o operation using sleep 48 | yield from sleep(random.random()) 49 | item = str(x) 50 | # put the item in the queue 51 | queue.append(item) 52 | 53 | # indicate the producer is done 54 | queue.append(None) 55 | 56 | 57 | def consume(queue): 58 | while True: 59 | # wait for an item from the producer 60 | item = yield from get_from(queue) 61 | if item is None: 62 | # the producer emits None to indicate that it is done 63 | break 64 | 65 | # process the item 66 | print(f'consuming item {item}...') 67 | # simulate i/o operation using sleep 68 | yield from sleep(random.random()) 69 | 70 | 71 | if __name__ == "__main__": 72 | queue = deque([]) 73 | engine([produce(queue, 10), consume(queue)]) 74 | print("Finished!") 75 | -------------------------------------------------------------------------------- /Xinyu_Interpreter/OCaml_pl.pl: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright Belongs to Xinyu Ma xinyuma@g.ucla.edu 4 | Thanks a lot to Xinyu for sharing this 5 | 6 | Translation rules: 7 | 8 | true => true 9 | false => false 10 | 1 => 1 11 | (=) 1 2 => =(1, 2) OR 1 = 2 OR fcall((=), [1, 2]) 12 | f a b c d => f(a, b, c, d) OR fcall(f, [a, b, c, d]) 13 | if 1=2 then 3 else 4 => if(1=2, 3, 4) 14 | fun x -> x + 1 => fun(x, x + 1) 15 | let x = 1 in x + 1 => fcall(fun(x, x + 1), [1]) 16 | 17 | let eq x y = x = y in if 1 > 2 then eq 1 2 else eq true false => Not supported yet. 18 | */ 19 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 20 | lookup(X, [[X, XType]|_], XType). 21 | lookup(X, [_|T], XType) :- lookup(X, T, XType). 22 | 23 | of_type(X, _, bool) :- X = true; X = false. % bool literal 24 | of_type(X, _, int) :- integer(X). % int literal 25 | of_type(X, TypeVars, XType) :- lookup(X, TypeVars, XType). % variable 26 | of_type(if(Cond, Then, Else), TypeVars, IfType) :- % if(Cond, Then, Else) 27 | of_type(Cond, TypeVars, bool), 28 | of_type(Then, TypeVars, IfType), 29 | of_type(Else, TypeVars, IfType). 30 | of_type(fun(Arg, Body), TypeVars, (ArgType -> RetType)) :- % fun(Arg, Body) 31 | of_type(Body, [[Arg, ArgType]|TypeVars], RetType). 32 | of_type(fcall(Func, ArgList), TypeVars, RetType) :- % fcall(Func, [Arg1, Arg2, ...]) 33 | of_type(Func, TypeVars, FuncType), 34 | func_type(ArgList, TypeVars, RetType, FuncType). 35 | of_type(Fcall, TypeVars, RetType) :- % func(Arg1, Arg2, ...). Just syntax sugar. 36 | Fcall =.. [Func, Arg|ArgRest], 37 | of_type(Func, TypeVars, FuncType), 38 | func_type([Arg|ArgRest], TypeVars, RetType, FuncType). 39 | 40 | func_type([], _, RetType, RetType). 41 | func_type([Arg|ArgRest], TypeVars, RetType, (ArgType -> RestType)) :- 42 | of_type(Arg, TypeVars, ArgType), 43 | func_type(ArgRest, TypeVars, RetType, RestType). 44 | 45 | get_type(Expr, Type) :- 46 | of_type(Expr, 47 | [[(+), (int -> int -> int)], 48 | [(=), (int -> int -> bool)], 49 | [(=), (bool -> bool -> bool)]], 50 | Type), 51 | !. 52 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 53 | /* 54 | Test cases 55 | 56 | ?- get_type(if(true, 1 = 2, true = false), T). 57 | T = bool 58 | yes 59 | 60 | ?- get_type(fun(x, fun(y, x + y)), T). 61 | T = (int->int->int) 62 | yes 63 | 64 | ?- get_type(fun(x, x(1)), T). 65 | T = ((int->A)->A) 66 | yes 67 | 68 | ?- get_type(fun(x, x(1) + x(2)), T). 69 | T = ((int->int)->int) 70 | yes 71 | 72 | ?- get_type(fcall(fun(x, x + 1), [1]), T). 73 | T = int 74 | yes 75 | 76 | ?- get_type(fun(x, x(1) + x(false)), T). 77 | no 78 | 79 | ?- get_type(fun(x, x), T). 80 | T = (A->A) 81 | yes 82 | 83 | ?- get_type(fun(f, f(1, 1)), T). 84 | T = ((int->int->A)->A) 85 | yes 86 | 87 | ?- of_type(computed_periodic_point(1, fun(fa, fun(fb, fa(1024)=fb(1024))), fun(f, fun(v, f(v+2))), fun(v, v+2)), 88 | [[(+), (int -> int -> int)], 89 | [(=), (int -> int -> bool)], 90 | [(=), (bool -> bool -> bool)], 91 | [computed_periodic_point, (int -> (A -> A -> bool) -> (A -> A) -> A -> A)]], 92 | Type), !. 93 | A = (int->int) 94 | Type = (int->int) 95 | yes 96 | */ -------------------------------------------------------------------------------- /Xinyu_Interpreter/bfs.ml: -------------------------------------------------------------------------------- 1 | (* 2 | Given that many people stated that it would be hard to implement a search 3 | algorithm like DFS or BFS in OCaml, let me give an example here. 4 | The conclusions are: 5 | 6 | - To implement BFS (or DFS) is as easy as in C, if we do not consider the 7 | performance loss. 8 | 9 | - OCaml has a built-in array which is mutable. If that is allowed to use, 10 | the algorithm is as fast as C version. 11 | 12 | - If nothing mutable is allowed, the performance of BFS will be 13 | O(BFS-in-C)*O(log n)*O(log n) 14 | 15 | - Not shown in the example code, but the performance loss of DFS is not this 16 | much because some tricks such as zipper can be used. 17 | *) 18 | 19 | (* Define the maze *) 20 | let maze = [ 21 | [0; 1; 0; 0; 0]; 22 | [0; 1; 0; 1; 0]; 23 | [0; 0; 0; 1; 0]; 24 | [0; 1; 1; 0; 0]; 25 | [0; 0; 0; 1; 0] 26 | ] 27 | let at_cell m (r, c) = 28 | List.nth (List.nth m r) c 29 | 30 | (* Define the queue *) 31 | (* List-based queue is in efficient, but we have a way to solve this *) 32 | 33 | let queue = [0, 0] 34 | let push q v = q @ [v] 35 | let pop = function 36 | | v::rest -> Some v, rest 37 | | [] -> None, [] 38 | 39 | (* BFS function computing the shortest path from (0, 0) to (n, n) *) 40 | (* Here we use list-based queue and List.assoc-based array first *) 41 | let bfs m = 42 | let nrow = List.length m in 43 | let ncol = List.length (List.nth m 0) in 44 | let rec helper steps que = 45 | (* steps stores the shortest step to every cell *) 46 | (* que is the BFD queue *) 47 | match pop que with 48 | | None, _ -> steps 49 | | Some (x, y), rest_q -> 50 | let cur = List.assoc (x, y) steps in 51 | let next_step (nx, ny) (st, q) = 52 | match List.assoc_opt (nx, ny) st with 53 | | None when nx >= 0 54 | && ny >= 0 55 | && nx < nrow 56 | && ny < ncol 57 | && at_cell m (nx, ny) <> 1 -> 58 | (st @ [(nx, ny), cur + 1]), push q (nx, ny) 59 | | _ -> st, q in 60 | let next_steps, next_q = (steps, rest_q) 61 | |> next_step (x + 1, y) 62 | |> next_step (x - 1, y) 63 | |> next_step (x, y + 1) 64 | |> next_step (x, y - 1) in 65 | helper next_steps next_q in 66 | let final_steps = helper [(0, 0), 0] queue in 67 | List.assoc (nrow - 1, ncol - 1) final_steps 68 | 69 | (* Define a faster queue, which solve the efficiency issue of push *) 70 | let fast_queue = [0, 0], [] 71 | let fast_push (f, b) v = f, v::b 72 | let rec fast_pop = function 73 | | [], [] -> None, ([], []) 74 | | v::rest, b -> Some v, (rest, b) 75 | | [], b -> fast_pop (List.rev b, []) 76 | (* The complexity is AMORTIZED O(1) for push and pop *) 77 | 78 | (* Define a faster array *) 79 | (* Unfortunately, we cannot get O(1) without mutability, 80 | but it is faster than List.assoc *) 81 | (* Real-world OCaml has mutability, so the built-in array is O(1) anyway *) 82 | type 't segment_tree = 83 | | Node of 't segment_tree * 't segment_tree 84 | | Leaf of 't 85 | 86 | let init_arr n init_val = 87 | let rec init l r = 88 | if l = r 89 | then Leaf init_val 90 | else 91 | let mid = (l + r) / 2 in 92 | let lchd = init l mid in 93 | let rchd = init (mid + 1) r in 94 | Node (lchd, rchd) in 95 | init 0 (n - 1), n 96 | let get_arr i (segt, n) = 97 | let rec get l r = function 98 | | Leaf v -> v 99 | | Node (lchd, rchd) -> 100 | let mid = (l + r) / 2 in 101 | if i <= mid 102 | then get l mid lchd 103 | else get (mid + 1) r rchd in 104 | get 0 (n - 1) segt 105 | let set_arr i new_val (segt, n) = 106 | let rec set l r = function 107 | | Leaf v -> Leaf new_val 108 | | Node (lchd, rchd) -> 109 | let mid = (l + r) / 2 in 110 | if i <= mid 111 | then Node (set l mid lchd, rchd) 112 | else Node (lchd, set (mid + 1) r rchd) in 113 | set 0 (n - 1) segt, n 114 | let arr_to_list (segt, _) = 115 | let rec helper = function 116 | | Leaf v -> [v] 117 | | Node (lchd, rchd) -> helper lchd @ helper rchd in 118 | helper segt 119 | 120 | let arr_test = 121 | let one_to_five = init_arr 5 0 122 | |> set_arr 0 1 123 | |> set_arr 1 2 124 | |> set_arr 3 4 125 | |> set_arr 2 3 126 | |> set_arr 4 5 in 127 | arr_to_list one_to_five = [1; 2; 3; 4; 5] 128 | (* This segment_tree based array has a complexity of O(log n) for set and get *) 129 | -------------------------------------------------------------------------------- /Xinyu_Interpreter/dynamic_array_in_c99.c: -------------------------------------------------------------------------------- 1 | /* This example shows how dynamic-sized array will effect the performance 2 | * The .s file is the corresponding assembly code with some comments for key 3 | * code 4 | */ 5 | #include 6 | 7 | void f(int n){ 8 | int i; 9 | int arr[n]; 10 | 11 | arr[0] = arr[1] = 1; 12 | for(i = 2; i < n; i ++){ 13 | arr[i] = arr[i - 1] + arr[i - 2]; 14 | } 15 | printf("%d\n", arr[n - 1]); 16 | } 17 | 18 | int main(){ 19 | int n; 20 | scanf("%d", &n); 21 | f(n); 22 | return 0; 23 | } 24 | -------------------------------------------------------------------------------- /Xinyu_Interpreter/dynamic_array_in_c99.s: -------------------------------------------------------------------------------- 1 | .section __TEXT,__text,regular,pure_instructions 2 | .build_version macos, 10, 15 sdk_version 10, 15 3 | .globl _f ## -- Begin function f 4 | .p2align 4, 0x90 5 | _f: ## @f 6 | .cfi_startproc 7 | ## %bb.0: 8 | pushq %rbp ; Preserve RBP 9 | .cfi_def_cfa_offset 16 10 | .cfi_offset %rbp, -16 11 | movq %rsp, %rbp ; Save Stack Pointer in RBP 12 | .cfi_def_cfa_register %rbp 13 | subq $64, %rsp ; Allocate memory for guard, i, n, etc. But not including arr 14 | movq ___stack_chk_guard@GOTPCREL(%rip), %rax 15 | movq (%rax), %rax 16 | movq %rax, -8(%rbp) 17 | movl %edi, -12(%rbp) ; Memory for n 18 | movl -12(%rbp), %edi 19 | movl %edi, %eax 20 | movq %rsp, %rcx 21 | movq %rcx, -24(%rbp) ; Preserve modified Stack Pointer 22 | leaq 15(,%rax,4), %rcx ; Calculate sizeof(arr) = n * 4 23 | andq $-16, %rcx ; Alignment by 16B 24 | movq %rax, -40(%rbp) ## 8-byte Spill 25 | movq %rcx, %rax 26 | callq ____chkstk_darwin 27 | subq %rax, %rsp ; Allocate memory for arr by RSP -= 4*n 28 | movq %rsp, %rax ; RAX = RSP, which is &a[0] 29 | movq -40(%rbp), %rcx ## 8-byte Reload 30 | movq %rcx, -32(%rbp) 31 | movl $1, 4(%rax) ; a[1] = 1 32 | movl $1, (%rax) ; a[0] = 1 33 | movl $2, -16(%rbp) ; i = 2 34 | movq %rax, -48(%rbp) ## 8-byte Spill 35 | LBB0_1: ## =>This Inner Loop Header: Depth=1 36 | movl -16(%rbp), %eax 37 | cmpl -12(%rbp), %eax 38 | jge LBB0_4 ; if i>= n, goto LBB0_4 39 | ## %bb.2: ## in Loop: Header=BB0_1 Depth=1 40 | movl -16(%rbp), %eax 41 | subl $1, %eax 42 | movslq %eax, %rcx ; RCX = i - 1 43 | movq -48(%rbp), %rdx ## 8-byte Reload 44 | movl (%rdx,%rcx,4), %eax ; EAX = *(a+4*RCX) 45 | movl -16(%rbp), %esi 46 | subl $2, %esi 47 | movslq %esi, %rcx ; RCX = i - 2 48 | addl (%rdx,%rcx,4), %eax ; EAX += *(a+4*RCX) 49 | movslq -16(%rbp), %rcx 50 | movl %eax, (%rdx,%rcx,4) 51 | ## %bb.3: ## in Loop: Header=BB0_1 Depth=1 52 | movl -16(%rbp), %eax 53 | addl $1, %eax 54 | movl %eax, -16(%rbp) ; i += 1 55 | jmp LBB0_1 56 | LBB0_4: 57 | movl -12(%rbp), %eax 58 | subl $1, %eax 59 | movslq %eax, %rcx ; RCX = N - 1 60 | movq -48(%rbp), %rdx ## 8-byte Reload 61 | movl (%rdx,%rcx,4), %esi ; ESI = *(a+4*RCX) 62 | leaq L_.str(%rip), %rdi 63 | movb $0, %al 64 | callq _printf 65 | movq -24(%rbp), %rcx 66 | movq %rcx, %rsp 67 | movq ___stack_chk_guard@GOTPCREL(%rip), %rcx 68 | movq (%rcx), %rcx 69 | movq -8(%rbp), %rdx 70 | cmpq %rdx, %rcx 71 | movl %eax, -52(%rbp) ## 4-byte Spill 72 | jne LBB0_6 73 | ## %bb.5: 74 | movq %rbp, %rsp 75 | popq %rbp 76 | retq 77 | LBB0_6: 78 | callq ___stack_chk_fail 79 | ud2 80 | .cfi_endproc 81 | ## -- End function 82 | .globl _main ## -- Begin function main 83 | .p2align 4, 0x90 84 | _main: ## @main 85 | .cfi_startproc 86 | ## %bb.0: 87 | pushq %rbp 88 | .cfi_def_cfa_offset 16 89 | .cfi_offset %rbp, -16 90 | movq %rsp, %rbp 91 | .cfi_def_cfa_register %rbp 92 | subq $16, %rsp 93 | movl $0, -4(%rbp) 94 | leaq L_.str.1(%rip), %rdi 95 | leaq -8(%rbp), %rsi 96 | movb $0, %al 97 | callq _scanf 98 | movl -8(%rbp), %edi 99 | movl %eax, -12(%rbp) ## 4-byte Spill 100 | callq _f 101 | xorl %eax, %eax 102 | addq $16, %rsp 103 | popq %rbp 104 | retq 105 | .cfi_endproc 106 | ## -- End function 107 | .section __TEXT,__cstring,cstring_literals 108 | L_.str: ## @.str 109 | .asciz "%d\n" 110 | 111 | L_.str.1: ## @.str.1 112 | .asciz "%d" 113 | 114 | 115 | .subsections_via_symbols 116 | -------------------------------------------------------------------------------- /Xinyu_Interpreter/prolog.rkt: -------------------------------------------------------------------------------- 1 | #lang racket 2 | 3 | (define (unify-term lhs rhs) 4 | (cond 5 | ; Identical 6 | [(equal? lhs rhs) '()] 7 | ; >=1 variable 8 | [(symbol? lhs) `((,lhs ,rhs))] 9 | [(symbol? rhs) `((,rhs ,lhs))] 10 | ; >=1 atom (not equal) 11 | [(or (string? lhs) (string? rhs)) #f] 12 | ; All relation 13 | [(not (equal? (length lhs) (length rhs))) #f] 14 | [#t (unify-list lhs rhs)])) 15 | 16 | (define (subst term var value) 17 | (cond 18 | ; If it's a variable 19 | [(symbol? term) (if (equal? term var) value term)] 20 | ; If it's an atom 21 | [(string? term) term] 22 | ; If it's a relation 23 | [#t (map (lambda (t) (subst t var value)) term)])) 24 | 25 | (define (subst-all term lst) 26 | (foldr (lambda (v t) (subst t (car v) (cadr v))) term lst)) 27 | 28 | (define (unify-list llst rlst) 29 | (if (empty? llst) 30 | '() 31 | ; First unify the tail 32 | (let ([tail-result (unify-list (cdr llst) (cdr rlst))]) 33 | (if (not tail-result) 34 | #f 35 | ; Then apply the result to the head of each list 36 | (let* ([new-lh (subst-all (car llst) tail-result)] 37 | [new-rh (subst-all (car rlst) tail-result)] 38 | [head-result (unify-term new-lh new-rh)]) 39 | (if (not head-result) 40 | #f 41 | ; And concatenate the result with tail-result 42 | (append head-result tail-result))))))) 43 | 44 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 45 | (define (map-foldr proc init lst) 46 | (if (empty? lst) 47 | (list '() init) 48 | (let* ([rest-result (map-foldr proc init (cdr lst))] 49 | [tail (car rest-result)] 50 | [result (proc (car lst) (cadr rest-result))] 51 | [ret-list (cons (car result) tail)] 52 | [ret-acc (cadr result)]) 53 | (list ret-list ret-acc)))) 54 | 55 | (define (rename-symbol-aux term table) 56 | (cond 57 | [(string? term) (list term table)] 58 | [(symbol? term) (let* ([old (assoc term table)]) 59 | (if old 60 | (list (cadr old) table) 61 | (let* ([new-sym (gensym)]) 62 | `(,new-sym ((,term ,new-sym) ,@table)))))] 63 | [#t (map-foldr rename-symbol-aux table term)])) 64 | 65 | (define (rename-symbol term) 66 | (car (rename-symbol-aux term '()))) 67 | 68 | (define (resolution clause goals query) 69 | (let* ([sub (unify-term (car clause) (car goals))] 70 | [new-goals (append (cdr clause) (cdr goals))]) 71 | (if (not sub) 72 | #f 73 | (list (map (lambda (t) (subst-all t sub)) new-goals) 74 | (subst-all query sub))))) 75 | 76 | (define (solve goals query program) 77 | (if (empty? goals) 78 | query 79 | (for/or ([c program]) 80 | (let ([trial (resolution (rename-symbol c) goals query)]) 81 | (if trial 82 | (solve (car trial) (cadr trial) program) 83 | #f))))) 84 | 85 | (define (prolog query program) 86 | (solve (list query) query program)) 87 | 88 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 89 | ;plus(z, X, X). 90 | ;plus(s(X), Y, s(Z)) :- plus(X, Y, Z). 91 | ;plus(s(z), s(s(z)), X)? 92 | (define test1-program 93 | '((("plus" "z" X X)) 94 | (("plus" ("s" X) Y ("s" Z)) ("plus" X Y Z)))) 95 | (define test1-query1 96 | '("plus" ("s" "z") ("s" ("s" "z")) X)) 97 | (define test1-query2 98 | '("plus" X ("s" ("s" "z")) ("s" ("s" ("s" "z"))))) 99 | (define test1-query3 100 | '("plus" ("s" "z") X ("s" ("s" ("s" "z"))))) 101 | 102 | ;car(cons(X, Y), X). 103 | ;car(cons(a, nil), X)? 104 | (define test2-program 105 | '((("car" ("cons" X Y) X)))) 106 | (define test2-query 107 | '("car" ("cons" "a" "nil") X)) 108 | 109 | ;plus(z, X, X). 110 | ;plus(s(X), Y, s(Z)) :- plus(X, Y, Z). 111 | ;fib(s(z), s(z)). 112 | ;fib(s(s(z)), s(s(z))). 113 | ;fib(s(s(X)), Y) :- fib(s(X), Y1), fib(X, Y2), plus(Y1, Y2, Y). 114 | ;fib(s(s(s(s(z)))), Y)? 115 | (define test3-program 116 | '((("plus" "z" X X)) 117 | (("plus" ("s" X) Y ("s" Z)) ("plus" X Y Z)) 118 | (("fib" ("s" "z") ("s" "z"))) 119 | (("fib" ("s" ("s" "z")) ("s" ("s" "z")))) 120 | (("fib" ("s" ("s" X)) Y) ("fib" ("s" X) Y1) ("fib" X Y2) ("plus" Y1 Y2 Y)))) 121 | (define test3-query 122 | '("fib" ("s" ("s" ("s" ("s" ("s" "z"))))) Y)) 123 | 124 | ;p(f(Y)) :- q(Y), r(Y). 125 | ;p(b). 126 | ;q(h(Z)) :- t(Z). 127 | ;r(h(a)). 128 | ;t(a). 129 | ;p(X)? 130 | (define test4-program 131 | '((("p" ("f" Y)) ("q" Y) ("r" Y)) 132 | (("p" "b")) 133 | (("q" ("h" Z)) ("t" Z)) 134 | (("r" ("h" "a"))) 135 | (("t" "a")))) 136 | (define test4-query 137 | '("p" X)) -------------------------------------------------------------------------------- /Xinyu_Interpreter/vaarg.c: -------------------------------------------------------------------------------- 1 | /* This example shows how va_arg works 2 | */ 3 | #include 4 | #include 5 | #include 6 | 7 | /* Print Types */ 8 | #define PRINT_INT 0 9 | #define PRINT_BOOL 1 10 | #define PRINT_UINT64 2 11 | #define PRINT_STR 3 12 | 13 | void print_all(int n, ...){ 14 | va_list vl; 15 | int i; 16 | int argType; 17 | int iVal; 18 | bool bVal; 19 | unsigned long long ullVal; 20 | char* szVal; 21 | 22 | printf("The variables are: "); 23 | va_start(vl, n); 24 | for(i = 0; i < n; i ++){ 25 | argType = va_arg(vl, int); 26 | switch (argType) { 27 | case PRINT_INT: 28 | iVal = va_arg(vl, int); /* 4B */ 29 | printf("%d ", iVal); 30 | break; 31 | case PRINT_BOOL: 32 | bVal = (bool)va_arg(vl, int); /* The minimum size of a va_arg is 4B. */ 33 | printf(bVal ? "TRUE " : "FALSE "); 34 | break; 35 | case PRINT_UINT64: 36 | ullVal = va_arg(vl, unsigned long long); /* 8B */ 37 | printf("%llu ", ullVal); 38 | break; 39 | case PRINT_STR: 40 | szVal = va_arg(vl, char*); /* 4B or 8B, unknown */ 41 | printf("%s ", szVal); 42 | break; 43 | default: 44 | break; 45 | } 46 | } 47 | va_end(vl); 48 | printf("\n"); 49 | } 50 | 51 | int main(){ 52 | print_all(4, PRINT_BOOL, true, PRINT_INT, 3, PRINT_UINT64, 999, PRINT_STR, "hello"); 53 | return 0; 54 | } 55 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # UCLA CS131 Coding Helper 2 | 3 | ## Description 4 | This reporitory is a collection of helpful materials that might give you a better experience in learning CS131 taught by [Prof. Eggert](https://samueli.ucla.edu/people/paul-eggert/). Previous quarter helper code could be find in other *branches* (not the master branch). 5 | 6 | ## Written in Advance 7 | 1. Nothing could be more important than the textbook (We refer to as Webber) 8 | * [Modern Programming Languages: 2nd Edition (A Practical Introduction) Author: Adam Brooks Webber](http://www.webber-labs.com/mpl/) 9 | * including slides and corrections of textbook and code on their website 10 | * Typically, the whole textbook is covered in your final exam. 11 | 2. Please **do** goto the lectures and take notes. 12 | 3. Please start early on everything, especially the homework, you may find them take much longer than expected. 13 | 14 | ## Announcements 15 | * CS131 homework and projects 16 | - TA will grade your homework 17 | - By some automatic grading scripts (so that's fair - but those scripts are generally bad in taking care of compilation errors / unexpected variable names, please be careful) 18 | - **HW5** simplest grading script with all test cases omitted is [available here](https://github.com/CS131-TA-team/hw5-grading-script), please go through it carefully and use it wisely. 19 | - **Project** grading script is an enriched complex version of [this sample code](https://github.com/CS131-TA-team/CS131-Project-Sample-Grading-Script), please make sure that your code gets along with this script before your final submission. Feel free to use the sample code as a client that helps you make sure that your servers do the right thing. 20 | * CS131 exams 21 | - Graded on GradeScope 22 | - Midterms grading details will be released to students on GradeScope, but for finals, normally won't 23 | - Regrading requests are always welcomed for midterm and final, but we don't wait forever for the regrading requests, if you do want a regrade please submit a regrading request on GradeScope (midterm, when this option is valid), or reach out to your TAs ASAP asking for it (final, when we don't show you the details, you can ask for them in person). 24 | * CS131 score punishment 25 | - Exponential (<= 1 day -1%, <= 2 days -2%, <=3 days -4%, etc.) --------------------------------------------------------------------------------