1: 
2: Files and Interprocess Communication
3: 
4: Accessing files is very easy though the syntax may look unfamiliar. 
5: Here for example is the code to number each line in a file.
6: 
7: ==========
8: 
9: /  Numbers the lines in a file
10: / q number  filename
11: 
12: 
13: / APPLICATION
14: 
15: / Does the numbering
16: myparse:{[line]
17:   linenum+: 1;
18:   :(string linenum), (": "),(line)}
19: 
20: / EXECUTION
21: 
22: if[0 = count .z.x; til -3] / should have a file argument
23: file: .z.x[0]
24: 
25: linenum: 0 / global variable
26: a: read0 ` $ (":"),file / read the file
27: 
28: (` $ (":"),file,("out")) 0: myparse each a / parse and output the file
29: 
30: 
31: ===============
32: 
33: q number.q file
34: 
35: Points to understand:
36: 1. How to read in a file.
37: 2. How globals work.
38: 3. How to construct an output file name.
39: 4. How to do the output.
40: 
41: 
42: Exercise 1. (Easy) 
43: Read in a file and count the number of characters per line then output
44: the numbers in the form
45: 1: 23
46: 2: 0
47: ...
48: 
49: 	q countchar.q <filename>
50: 
51: 
52: Now we might want to parse all the words in the file (where
53: words are  delimited by blanks) and count the number of instances
54: of words.
55: Let's work up to this.
56: We will have the same basic structure in which we read in one line
57: at a time and we parse it.
58: Only this time, parsing it will consist of separating the words
59: based on spaces.
60: 
61: Consider how to parse a line so we can get just the words:
62: 
63: / deletes all blanks
64: delblanks:{[x]
65:  ii: where not x = " ";
66:  x[ii] }
67: 
68: / separate into words
69: sepwords:{[x]
70:   ii: where x = " ";
71:   ii: distinct 0, ii;
72:   y: delblanks each ii _ x;
73:   c: count each y;
74:   ii: where not c = 0;
75:   y[ii]}
76: 
77: Points to notice:
78: 1. Use of where
79: 2. Need for 0
80: 3. The underbar (_) construction
81: 4. Getting rid of blanks
82: 5. Use of count
83: 
84: A more concise sepwords:
85: 
86: / separate into words
87: sepwords:{[x]
88:   y: (" ")vs x;
89:   c: count each y;
90:   ii: where not c = 0;
91:   y[ii]}
92: 
93: 
94: Exercise 2: (Medium)
95: Parse all the words in the file (where
96: words are  delimited by blanks) and find all
97: distinct words.
98: 
99: Exercise 2a: (Medium)
100: Parse all the words in the file (where
101: words are  delimited by blanks) and 
102: count the number of instances
103: of words.
104: Display the pair (word, number) for all words having at least 3 instances
105: in descending order by count.
106: 
107: 	q wordcount.q filename
108: 
109: In the following exercise, we read a q program and try to find
110: elementary syntax errors.
111: A q program needs semi-colons within its procedures except 
112: on the last line of a procedure or if we're inside parentheses.
113: Note that we don't want to put the semi-colon after the 
114: comment in a line or on blank lines.
115: 
116: Hints:
117: 
118:  line: "5 + 2" / this is an addition
119:  (line til 6),("; "),(6 _ line)
120:  jj: line ss " / "
121: 
122: 
123: 
124: Exercise 3 (Middle). Read 
125: in a file and check that it has semicolons where needed
126: and add them.
127: 	q findmissing.q test.q -- Adds in semi-colons where needed
128: 
129: Client-server communication
130: 
131: Doing client-server communication is easy.
132: Let's think about the information that is required.
133: The server has to establish an address.
134: The client sends to that address.
135: The client has to make a few decisions:
136: a. which function to call on the server
137: b. whether the call is
138: synchronous (client waits for the response before proceeding)
139: or asynchronous (client goes on).
140: 
141: For example, here is a simple server:
142: 
143: 
144: / q simpleserver.q -p 1111
145: 
146: / Returns twice the number sent in
147: simple:{[num]
148:   2*num}
149:   
150: 
151: And here is a simple synchronous client:
152: 
153: h: hopen`::1111; / opens the port on the current machine
154: h"simple[9876.5]" / calls the function with an argument
155: 
156: 
157: Here is an asynchronous client:
158: 
159: h: hopen`::1111;
160: neg[h]"simple[9876.5]"
161: 
162: The trouble with the asynchronous client is that it doesn't
163: return anything. So we will need to keep state in the server
164: and call for it using a synchronous call.
165: Let's see if you can figure that out.
166: 
167: 
168: 4. (Easy) Communicate from a client to a server where the server computes
169: the present value of an income stream
170: given as a list given a certain interest rate value.
171: Use synchronous  calls.
172: 
173: 	q presvalserver.q -p 1234
174: 	q presvalclient.q
175: 
176: 4 async. (Easy) Communicate from a client to a server where the server computes
177: the present value given a certain interest rate value for four different
178: asynchronous calls to presvalue 
179: e.g.
180: neg[h]"presval[6.5; 100 200 100 300]"
181: neg[h]"presval[6.0; 100 200 100 300]"
182: neg[h]"presval[5.5; 100 200 100 300]"
183: neg[h]"presval[5.0; 100 200 100 300]"
184: The client then makes a synchronous
185: call to collect all these results.
186: 	q presvalserverasync.q -p 1234
187: 	q presvalclientasync.q 
188: 
189: 
190: Communicating to many servers is just a matter of declaring
191: those servers and then using the appropriate handles.
192: Note you can do e.g.
193: \sleep 3
194: if you think the server will take time.
195: 	q presvalclientasyncwithdelay.q 
196: 
197: 5. (Middle) Communicate from a client to three servers to compute the
198: present value assuming a variety of interest rates.
199: 	q presvalserver.q -p 1000
200: 	q presvalserver.q -p 1001
201: 	q presvalserver.q -p 1002
202: 	q presvalclientmulti.q
203: 
204: 
205: One way in which we might wish to parallelize jobs is to have
206: a reliable client which has a queue of jobs (jobqueue)
207: and acts as client
208: to a bunch of servers.
209: Each time the client dispatches a job to a server it puts
210: the job on the back of the jobqueue.
211: Periodically, the client queries each server to see which 
212: jobs the server has done.
213: The client reports these in its answer queue.
214: The client eliminates all jobs that
215: are in its answer queue from its jobqueue.
216: 
217: pseudo-code of client:
218: 
219: do several asynchronous calls to the servers
220:  for jobs that haven't completed
221: do synchronous calls to servers to get results
222:  and cause the server to reset its answer buffer
223: 
224: pseudo-code of server:
225: 
226: put the result of each call on its answer buffer.
227: 
228: 	q presvalserverasyncslow.q -p 10001
229: 	q presvalserverasyncslow.q -p 10002
230: 	q presvalserverasyncslow.q -p 10003
231: 	q presvalclientasyncslow.q
232: 
233: 
234: 
