1
0
mirror of https://github.com/dhil/phd-dissertation synced 2026-03-13 11:08:25 +00:00

Compare commits

..

385 Commits

Author SHA1 Message Date
Daniel Hillerström
c2d79e1d06 Fix bibliography: add missing year 2025-12-18 14:08:13 +00:00
Daniel Hillerström
47410e4d14 Fix typo in -ctrl+ rule. The delimiter is part of the reified context. 2025-12-18 14:07:59 +00:00
81a4ecec0b UNIX tutorial 2024 2024-10-11 15:45:34 +02:00
cafa8b1ba2 Merge branch 'master' of github.com:dhil/phd-dissertation 2024-02-26 09:51:21 +01:00
2e61275a5b Fix typo; fix sentence structure.
This commit fixes a typo in the type signature of `init` (thanks to
Ramsay Carslaw for spotting it). This commit also structures the last
sentence of Section 2.7 to read slightly better.
2024-02-26 09:50:56 +01:00
e90ba67a4b Update timeline 2023-09-14 09:22:21 +02:00
6aee80a71b Fix typo 2023-09-14 09:14:29 +02:00
aea67c86b4 Fix typo 2023-04-12 14:55:37 +02:00
Daniel Hillerström
5ede30903f Fix typo 2023-02-14 10:59:29 +01:00
Daniel Hillerström
03b7c5b548 Fix typo. Slightly reword an awkward sentence. 2023-02-10 14:31:37 +01:00
7535fe7ecc Fix typos in handler typing rules in the appendix 2023-01-09 17:00:38 +00:00
72b54ad278 Add missing space in 'Evaluationcontexts' in Figure 3.5 2023-01-09 14:45:32 +00:00
01e707822f Fix typo in T-Let Figure 3.4 2023-01-09 14:42:09 +00:00
2cecb13d34 Update all slides 2022-11-17 15:05:18 +00:00
ed634fcaa3 Update slides 2022-11-17 11:10:29 +00:00
c60dc80fde Update slides 2022-11-16 23:42:00 +00:00
e86597f4e4 Draft lecture notes 2022-11-16 22:02:05 +00:00
2b7b1df8db Merge branch 'master' of github.com:dhil/phd-dissertation 2022-11-15 18:01:32 +00:00
20f44ad547 Fix typo 2022-11-15 18:01:26 +00:00
101ac96aa2 NU PRL slides 2022-11-02 15:45:00 +00:00
e6182105de Merge branch 'master' of github.com:dhil/phd-dissertation 2022-10-12 23:56:05 +01:00
63fe9a738a Prepare slides for Huawei Research Centre Zurich seminar 2022-10-12 23:55:57 +01:00
3a9394baf8 Fix a minor typo 2022-07-01 01:19:43 +01:00
6193214890 Update slides 2022-05-26 18:27:32 +01:00
ffe6ebd0b9 Update MSR 2022 slides 2022-05-25 22:29:14 +01:00
01a8a3d581 Draft MSR talk 2022-05-25 22:24:31 +01:00
008e80ea67 Link to thesis.
Update README to reflect the structure of the revised thesis.
2022-03-26 00:18:14 +00:00
3276537ab1 Tweak acknowledgements 2022-03-23 14:56:41 +00:00
20551152b3 Minor tweaks and typo fixes. 2022-03-21 14:12:59 +00:00
8679803146 Fix typo 2022-03-18 14:49:58 +00:00
d7bd881a00 Update latest draft 2021-12-22 16:55:21 +00:00
f5685fe70d Chapter 8 2021-12-22 16:48:14 +00:00
7f3503153f Minor fixes 2021-12-22 16:27:14 +00:00
40c6505ae2 Simplify 2021-12-22 16:15:16 +00:00
b897751a38 Note on reduction relation 2021-12-22 16:13:22 +00:00
3e1bbf3206 Fix todo 2021-12-22 16:10:51 +00:00
40948507e9 CPS outline 2021-12-22 16:08:08 +00:00
2a800f07e2 WIP 2021-12-22 15:58:26 +00:00
d3921f24e3 WIP 2021-12-22 14:23:57 +00:00
7063acb4e7 Related work 2021-12-21 16:14:59 +00:00
c9ff1d9af8 Chapter 3 2021-12-21 16:05:12 +00:00
fff15c9c83 Section 2.6 and 2.7 2021-12-20 23:29:27 +00:00
a24a33dcf8 Section 2.5 2021-12-20 16:08:32 +00:00
6c128a1181 Section 2.4 2021-12-20 13:37:07 +00:00
98784c59ab Section 2.3 2021-12-17 17:57:31 +00:00
6492391ed4 Section 2.2 2021-12-17 17:23:01 +00:00
cea34c85e1 Section 2.1 2021-12-17 16:42:02 +00:00
40b1144d9b Chapter 2 outline, relation to prior work, and terminology. 2021-12-17 01:29:57 +00:00
3067bfb939 fix chapter 2 intro 2021-12-13 22:55:52 +00:00
83b5f7db99 Start implementing the corrections. 2021-11-24 15:20:50 +00:00
981b0d48f8 Update README with viva date. 2021-08-13 12:07:16 +01:00
ee8a4ab2dd Fix a couple of typos 2021-08-13 11:47:23 +01:00
3fda920eae Minor improvement 2021-08-13 11:35:08 +01:00
0b198e7a25 Add paper references 2021-08-12 23:01:29 +01:00
740413ed1b Viva slides 2021-08-12 22:37:01 +01:00
7ed7a44d61 Package the draft as an archive 2021-06-07 13:31:51 +01:00
350d741204 List appendices 2021-06-07 12:35:42 +01:00
f8697be4c7 Remark that the final revision will be made available. 2021-06-07 12:28:06 +01:00
f9b8234221 Link to examiners 2021-06-07 12:26:36 +01:00
67598cee1e Dissertation overview 2021-06-07 12:22:52 +01:00
113b7c4620 Update build instructions 2021-06-07 12:13:26 +01:00
c52edb51f6 Make the latest draft revision available. 2021-06-07 12:10:00 +01:00
a4b802e4e0 Draft compilation 2021-06-07 12:03:47 +01:00
3b7dd13e3d typo 2021-06-01 19:03:06 +01:00
a42bfc25ab Update acknowledgements 2021-06-01 18:35:26 +01:00
97a4a806e1 Fix typos 2021-05-31 10:26:35 +01:00
0e02128d03 Rewording. THANKS AGAIN AMNA. 2021-05-30 20:45:37 +01:00
aa2b963d0e Fix grammar 2021-05-30 20:41:03 +01:00
2f494aae67 Fix grammar 2021-05-30 20:40:16 +01:00
a36b1cf0d4 Another typo 2021-05-30 20:38:54 +01:00
53b54056f8 Fix typo - THANKS AMNA 2021-05-30 20:38:00 +01:00
f80becc368 Spell out anonymous function notation 2021-05-30 20:10:16 +01:00
6c6d8e2aba A little paragraph justifying CPS 2021-05-30 20:04:41 +01:00
bc7d89ec5f Update acknowledgements 2021-05-30 19:51:21 +01:00
69a2c881b7 Declaration signature 2021-05-30 13:43:43 +01:00
6e5d7b01df Acknowledgements 2021-05-30 13:40:48 +01:00
49e53bac03 Acknowledgements 2021-05-30 13:35:04 +01:00
4834a6e5d3 Final example 2021-05-30 13:09:00 +01:00
3f91ab595e Fix rendering of type erasure lemma 2021-05-30 01:01:48 +01:00
333452bed2 Remove todo 2021-05-30 00:58:08 +01:00
51429afdd8 Update related work Chapter 5 2021-05-30 00:56:43 +01:00
e52cc41d40 Dybvig et al. taxonomy 2021-05-29 23:57:24 +01:00
b2eb9334ca Fix wording 2021-05-29 20:36:51 +01:00
754c3b823e Appendices 2021-05-29 20:21:32 +01:00
363628c1d3 Consistency 2021-05-29 16:33:52 +01:00
664956251c another example 2021-05-29 16:02:19 +01:00
d18a5e3058 Syntactic sugar 2021-05-29 12:15:21 +01:00
00f4264547 Minor fix 2021-05-29 11:57:39 +01:00
5597c9657b Lay summary 2021-05-29 11:56:35 +01:00
8b3660b0ce WIP 2021-05-29 10:40:49 +01:00
77475e129b WIP 2021-05-29 00:30:25 +01:00
9c2da2c378 Fix typos in introduction 2021-05-29 00:28:38 +01:00
ee92e3b483 WIP 2021-05-28 22:54:30 +01:00
6c3eb0e9cf another example 2021-05-28 19:41:29 +01:00
a476679810 Another example 2021-05-28 19:03:55 +01:00
3cb5e3622f Example 2021-05-28 18:20:01 +01:00
11b4888263 WIP 2021-05-28 13:19:54 +01:00
68110a67ef missing macros 2021-05-28 12:49:36 +01:00
d4ce54795c Minor fixes 2021-05-28 12:21:14 +01:00
2fbbf04bd4 WIP 2021-05-28 10:51:07 +01:00
0885c75c1e WIP 2021-05-28 01:09:53 +01:00
0c4108cdea WIP 2021-05-28 00:11:34 +01:00
4259ddee4d WIP 2021-05-28 00:07:19 +01:00
5340615c26 WIP 2021-05-28 00:00:00 +01:00
28fd0505ce Asymptotic notation and other fixes 2021-05-27 19:35:06 +01:00
fe6444ff3d Theorem 8.9 2021-05-27 13:49:42 +01:00
9fa5ebe6eb Citation for the three state equations. 2021-05-27 13:15:30 +01:00
79735da80a WIP 2021-05-27 13:04:43 +01:00
75d0dac161 WIP 2021-05-27 11:47:47 +01:00
a7d5117a64 Row polymorphism 2021-05-27 10:50:31 +01:00
75eb07cee1 Typo 2021-05-27 00:57:03 +01:00
ccd1f59d57 WIP 2021-05-27 00:50:09 +01:00
e84b4605c2 WIP 2021-05-27 00:35:40 +01:00
a57ac855c2 Chapter 9 2021-05-26 23:46:57 +01:00
fac68ae974 WIP 2021-05-26 21:41:59 +01:00
a4d9cc4edd WIP 2021-05-26 21:41:09 +01:00
02b9a782f3 Typo 2021-05-26 10:30:55 +01:00
e419d52ee2 WIP 2021-05-26 10:28:44 +01:00
98c79cc70d minor consistency fixes 2021-05-26 01:55:52 +01:00
2c51620a56 WIP 2021-05-26 01:15:07 +01:00
0f31e10582 WIP 2021-05-26 01:07:20 +01:00
9679a3cc82 WIP 2021-05-26 01:02:20 +01:00
559d9c2d37 CLR 2021-05-26 01:02:14 +01:00
5c835f5179 Fiddling with tikz 2021-05-25 21:08:30 +01:00
836d85ea99 Break up tables 2021-05-25 20:18:52 +01:00
622932494d Fix typos 2021-05-25 19:28:17 +01:00
111b4cb35a Update 2021-05-25 14:35:51 +01:00
6f44524750 WIP 2021-05-25 13:28:10 +01:00
3438581826 Reword 2021-05-25 13:03:22 +01:00
650de85238 Effect sugar 2021-05-25 12:59:01 +01:00
b47c60fe57 WIP 2021-05-25 01:19:48 +01:00
696266922a WIP 2021-05-25 00:20:51 +01:00
8fad146499 Note on higher order functions 2021-05-24 18:51:40 +01:00
93793648ef Introduction draft 2021-05-24 15:28:02 +01:00
d9717b7434 Draft introdoctury bit 2021-05-24 14:15:58 +01:00
7c3942a564 WIP 2021-05-24 11:49:38 +01:00
a462aa8a57 WIP 2021-05-24 01:48:25 +01:00
13d76a146b Update state of effectful programming 2021-05-23 22:42:28 +01:00
67a48945e9 Insert a few citations. 2021-05-23 18:48:14 +01:00
b73d9a213f More proper capitalisations 2021-05-23 18:47:58 +01:00
475f82324d Extend acknowledgements 2021-05-23 18:43:33 +01:00
6f8c5364f2 Correct capitalisation 2021-05-23 18:43:24 +01:00
0e2015485a Update acknowledgements 2021-05-23 18:24:44 +01:00
7ec90b216d Fix typos in abstract 2021-05-23 17:26:03 +01:00
35af9ba572 State of effectful programming 2021-05-23 16:26:08 +01:00
a3273afa50 Combining monads 2021-05-23 15:33:28 +01:00
1945a7307c Yallop's thesis 2021-05-23 14:12:35 +01:00
307e4bd259 Fix typo 2021-05-23 11:44:30 +01:00
114252b64f Scope 2021-05-23 11:36:24 +01:00
21fba05959 Other theses 2021-05-23 02:41:26 +01:00
a41fb391fc Update code 2021-05-22 20:33:28 +01:00
85757c48fd Effect handlers primer 2021-05-22 20:08:12 +01:00
28b8503b97 WIP 2021-05-22 01:22:47 +01:00
2c63d11392 WIP 2021-05-22 00:29:13 +01:00
c254d293a9 fix typos 2021-05-21 18:51:24 +01:00
eefa6e4ad4 Monadic reflection example 2021-05-21 14:02:06 +01:00
8cc91fa4b1 WIP 2021-05-20 18:03:38 +01:00
15125f206c Intro WIP 2021-05-20 17:49:38 +01:00
ef04653ad2 WIP 2021-05-20 14:41:25 +01:00
1ede601435 Mention equations 2021-05-20 11:22:22 +01:00
9e7c74ef0f Reword 2021-05-20 11:17:47 +01:00
d1a91fb197 Reword 2021-05-20 11:04:54 +01:00
76d9c00e19 Free monad section 2021-05-20 11:03:43 +01:00
d00227a57b WIP 2021-05-20 01:04:44 +01:00
e46cd37b01 WIP 2021-05-20 00:21:26 +01:00
26b12c123a Transparent state-passing 2021-05-19 21:16:49 +01:00
a3e97f9510 WIP 2021-05-19 19:26:32 +01:00
09cd57fbce Builtin state intro 2021-05-19 19:18:28 +01:00
5981ac986c WIP 2021-05-19 18:47:55 +01:00
a46e2fd5d6 WIP 2021-05-19 18:11:36 +01:00
4ece98ba21 State example with delimited control 2021-05-19 17:49:50 +01:00
a609ca4b81 WIP 2021-05-19 11:16:22 +01:00
d0061e18c2 WIP 2021-05-18 23:54:35 +01:00
c28aef1c9e Notes on why first-class control matters 2021-05-18 23:45:20 +01:00
8ecfadb94e Fix Ref macro 2021-05-18 08:04:20 +01:00
52b12535ae WIP 2021-05-17 23:28:51 +01:00
bce45f10e3 fix typo 2021-05-17 23:20:32 +01:00
1129d2bb71 WIP 2021-05-17 23:18:03 +01:00
9ba7def07b WIP 2021-05-17 23:13:01 +01:00
2eb5b0d4ba WIP 2021-05-15 21:08:57 +01:00
1c692d8cbf WIP 2021-05-15 13:29:49 +01:00
4d5bd3e08e Update conclusion 2021-05-13 23:35:05 +01:00
b13960a5e1 Fix spacing in stepsto type declaration 2021-05-13 13:30:02 +01:00
84fe38105e Contributions and outline 2021-05-13 11:07:36 +01:00
aacee4d72a WIP 2021-05-12 22:51:01 +01:00
1bca580f1f Reword conclusion 2021-05-11 23:04:15 +01:00
b02743df0f WIP 2021-05-11 11:18:30 +01:00
b76e18488c WIP 2021-05-10 23:44:12 +01:00
60976a7013 WIP 2021-05-10 16:26:08 +01:00
e88d27740d WIP 2021-05-06 22:39:08 +01:00
74c25ce63b Rewording and reordering 2021-05-06 10:47:25 +01:00
f9d92a231e Example done 2021-05-05 23:17:43 +01:00
50125e86ac Example 2021-05-05 22:54:14 +01:00
d6b67950b2 WIP 2021-05-04 23:00:40 +01:00
fc0c6a98bb WIP 2021-05-03 22:39:19 +01:00
388dc36b20 WIP 2021-04-27 22:31:26 +01:00
61b2ce4f66 Realisability 2021-04-26 23:22:48 +01:00
08b107323d WIP 2021-04-23 13:42:55 +01:00
1a93d1a5b7 Conclusions notes [WIP] 2021-04-20 22:47:50 +01:00
febf2a06c0 Abstract machine correctness 2021-04-20 21:48:20 +01:00
0861e926ee abstract machine related work 2021-04-20 16:31:34 +01:00
9f5b2ba56c WIP 2021-04-13 23:54:11 +01:00
78e291d602 WIP 2021-04-13 00:38:09 +01:00
d8ac28a9ee Abstract machine WIP 2021-04-12 14:04:01 +01:00
817676f8e8 Edits 2021-04-10 18:47:49 +01:00
4c480a4b6e Abstract machine figures 2021-04-09 00:04:58 +01:00
408b6041f6 WIP 2021-04-07 21:17:26 +01:00
950bee7ce3 Fix typos in chapter 9 2021-04-07 11:59:05 +01:00
25b48c1082 Reword 2021-04-05 19:28:49 +01:00
0cd953ac94 Interdefinability of effect handlers 2021-04-05 17:11:15 +01:00
34d724919f WIP 2021-03-31 22:39:07 +01:00
2f7da6ed15 WIP 2021-03-29 23:46:16 +01:00
5f7e8eadd2 Prove lemma 2021-03-18 00:42:06 +00:00
284139375a Interdefinability WIP2 2021-03-16 23:58:14 +00:00
28aaebf5ec WIP 2021-03-16 00:10:59 +00:00
f1d88fbcc4 Interdefinability WIP 2021-03-15 23:40:25 +00:00
669b708a79 Related work for CPS 2021-03-15 14:38:35 +00:00
df08169725 Administrative resumptions example. 2021-03-12 18:39:06 +00:00
b609812079 CPS intro 2021-03-12 00:18:08 +00:00
1b2882b1eb Simplify CPS 2021-03-04 11:56:45 +00:00
7f99b18242 CPS for parameterised handlers 2021-03-03 22:41:00 +00:00
95035458ec CPS translation for parameterised handlers (figure) 2021-03-03 14:22:56 +00:00
a29a6dc9c5 CPS intro 2021-03-02 23:36:33 +00:00
bd3e2c8b9f Update related work 2021-02-24 22:12:50 +00:00
485d02f101 Merge branch 'master' of github.com:dhil/phd-dissertation 2021-02-17 19:33:53 +00:00
d890a327a7 Note 2021-02-17 19:33:48 +00:00
e9cd4315be Spacing. 2021-02-17 18:04:05 +00:00
f1e1b75ef7 Fix more typos 2021-02-17 18:02:49 +00:00
2f7a6ec818 More minor fixes 2021-02-17 17:52:13 +00:00
2b21cfcb4e Minor fixes 2021-02-17 17:49:34 +00:00
dd0aaa32f6 Fix typos 2021-02-17 17:39:40 +00:00
6588c0581c idiom => saying 2021-02-17 17:27:05 +00:00
12e24d7051 Minor edits 2021-02-15 15:50:59 +00:00
ace6a5b37c Local/global state 2021-02-15 15:42:54 +00:00
7917c2ca0b Abstract 2021-02-11 21:15:29 +00:00
b8fd8ea43d Update abstract 2021-02-11 11:11:40 +00:00
617fd1112c Update parameterised example. 2021-02-10 18:34:16 +00:00
cf2422a312 citet => cite 2021-02-08 16:13:13 +00:00
9959b211e4 Bits and edits 2021-02-08 15:01:29 +00:00
d128895361 Some related work 2021-02-05 12:30:13 +00:00
b977c35d91 typo 2021-02-05 01:05:47 +00:00
e907a526e5 More related work 2021-02-05 01:04:50 +00:00
5560b73cc5 note 2021-02-04 23:24:07 +00:00
afb7c4b5cb Related work 2021-02-04 23:23:21 +00:00
9f83249765 Parameterised handlers section. 2021-02-04 18:18:27 +00:00
9ae478047d runNext 2021-02-04 16:28:32 +00:00
9fdcf19ee5 Parameterised semantics 2021-02-04 15:04:41 +00:00
86269f6de2 Process synchronisation code. 2021-02-04 12:14:06 +00:00
f6613484ca skeleton code 2021-02-04 00:25:50 +00:00
756ce77e5a Edits 2021-02-03 22:29:38 +00:00
33781a94e2 Start parameterised handlers. 2021-02-03 22:26:47 +00:00
9fc66e6b62 Frequency 2021-02-03 18:04:15 +00:00
9dcac3cf29 Filters 2021-02-03 16:07:36 +00:00
ebca80d4b7 Pipes 2021-02-02 23:56:33 +00:00
fa823432ed Shallow handlers intro 2021-02-02 15:26:59 +00:00
e5bc7f52b9 Update references 2021-02-01 17:43:34 +00:00
a4b3053d17 Shallow handlers intro 2021-02-01 16:00:24 +00:00
3fa47f2ae6 Summary 2021-02-01 13:50:26 +00:00
eea76a0979 File linking/unlinking. 2021-01-26 23:48:43 +00:00
a34a2c9775 File linking 2021-01-22 20:57:36 +00:00
5c2e028445 File linking and unlinking skeletons 2021-01-21 23:36:48 +00:00
83769bf406 Stream redirection 2021-01-21 21:14:49 +00:00
5668c2be45 WIP 2021-01-18 22:53:03 +00:00
3cd12d216d File system WIP 2021-01-14 20:00:46 +00:00
46e36b5318 Chap 6 rewrite WIP 2021-01-14 16:13:00 +00:00
7e71992709 WIP 2021-01-12 23:09:20 +00:00
dbc52adcdc Chapter 6 intro. 2021-01-11 22:41:17 +00:00
ea3c6a7345 Structured interface explanation 2021-01-08 16:16:05 +00:00
672d67fc72 WIP 2021-01-08 13:08:01 +00:00
427a24e7f8 Abstract WIP 2020-12-14 22:26:09 +00:00
aff97c44fa Abstract WIP 2020-12-12 17:16:41 +00:00
32044351e5 Promote section to chapter. Chapter 6 intro WIP. 2020-12-10 22:47:52 +00:00
b8b0007b8c Update slide deck 2020-12-08 13:59:01 +00:00
d6a83c2442 PLUG 2020 slides 2020-12-08 00:06:11 +00:00
1593660461 Effect handlers. 2020-12-06 00:27:35 +00:00
828c173b58 Deep handlers static semantics. 2020-12-05 18:53:54 +00:00
a4e504e24b Restore consistency between control/prompt and shift/reset example. 2020-12-05 17:56:47 +00:00
9f8bbe7ff4 Composable continuations. Controlling continuations intro. 2020-12-05 15:23:47 +00:00
fc0e40dbf9 Abortive continuations 2020-12-05 14:10:20 +00:00
5c7483cb31 Delimited and undelimited continuations 2020-12-04 23:40:00 +00:00
e2b07fbf5f Continuations introduction 2020-12-03 22:03:22 +00:00
a2e53135b3 Continuation introduction rewrite [WIP] 2020-12-02 23:47:55 +00:00
7d4bf2224f Implementing continuations 2020-12-02 22:26:40 +00:00
326b1f1a50 Begin paragraph on CPS 2020-12-02 00:03:51 +00:00
aaf6e3d9f0 Clean up 2020-12-01 23:33:34 +00:00
cc7a39647c Reorganise 2020-12-01 23:28:29 +00:00
bebb40ce9f Remove static semantics paragraphs from escape and catch. 2020-12-01 23:23:50 +00:00
ab36a78a50 Segmented stacks. 2020-12-01 23:19:09 +00:00
aece9e532b {Programming,Constraining} continuations. Working on Implementing continuations. 2020-12-01 20:19:15 +00:00
de7074a1da {Programming,Constraining} continuations WIP 2020-11-30 22:39:21 +00:00
1c955bf57e Change control into a computation form. 2020-11-30 00:05:55 +00:00
83a8457b26 Effect handlers paragraph WIP 2020-11-29 22:58:35 +00:00
6b3296d8a8 Splitter 2020-11-29 19:05:55 +00:00
e7a64dd145 Reword fcontrol paragraph 2020-11-29 16:14:53 +00:00
673958e406 fcontrol 2020-11-28 00:44:48 +00:00
9e343cb064 fcontrol WIP 2020-11-27 22:49:55 +00:00
5c27694161 cupto WIP 2020-11-27 18:47:29 +00:00
9804ad6713 Shift/reset 2020-11-27 16:45:30 +00:00
fcadc31110 Refinement 2020-11-27 01:17:44 +00:00
c45099b8aa Delimited control intro 2020-11-26 22:30:41 +00:00
43f33038f0 Update bibliography 2020-11-24 22:37:06 +00:00
eec734c014 Control calculus 2020-11-24 20:45:57 +00:00
c0afe9e548 More on control and prompt 2020-11-23 23:56:46 +00:00
1cffe1e0d6 Undelimited intro 2020-11-23 23:13:08 +00:00
303b76b990 Notes on control and prompt 2020-11-23 21:45:45 +00:00
073dca248e J 2020-11-21 23:55:39 +00:00
10eaab3979 C and F start. 2020-11-10 20:02:57 +00:00
6cf32d824c Question about interdefinability of callcc and callcc* 2020-11-10 15:30:40 +00:00
509044bd8f Callcc and callcc* 2020-11-09 14:36:01 +00:00
ca707ccac4 Change section title 2020-11-09 01:46:30 +00:00
ea9763fd70 Callcc 2020-11-09 01:37:05 +00:00
293bdae1d3 Catch 2020-11-09 00:47:29 +00:00
2800e2bd75 Notes on escape 2020-11-08 22:32:28 +00:00
f56901ad4b Extend Table 4.2 2020-11-08 16:54:50 +00:00
3c5be3b401 Add note 2020-11-08 00:35:41 +00:00
70a5d4a9ae Progress on undelimited control. 2020-11-08 00:23:11 +00:00
8500ce5796 Notes on J 2020-11-07 19:57:33 +00:00
ae6b233525 A first stab at some typing rules. 2020-11-06 23:30:15 +00:00
53a2f691c5 Use 'dump' contexts 2020-11-06 00:55:16 +00:00
a75f22eb50 C and F 2020-11-06 00:17:56 +00:00
a656f426b8 Some minor fixes 2020-11-05 22:29:19 +00:00
b92a96bc79 Update reductions 2020-11-04 15:00:45 +00:00
bdb6b31f29 Classification of control operators [WIP]. 2020-11-03 22:33:56 +00:00
e058e7804d Add note about call-with-composable-continuation 2020-11-02 19:20:12 +00:00
da0fc108d7 Controlling continuations [WIP] 2020-10-30 09:11:24 +00:00
ab38da7102 Some more references on control operators. 2020-10-28 22:41:25 +00:00
5e7ce98c0e Some notes on control operators and resumptions. 2020-10-28 21:49:32 +00:00
de8158d6ec Pass through parameterised handlers section 2020-10-27 13:26:30 +00:00
c047b061c7 File system example code. 2020-10-27 13:24:30 +00:00
e2af947cbd Update code 2020-10-27 00:58:20 +00:00
8700c0f439 File I/O [WIP] 2020-10-27 00:22:39 +00:00
604e8047f1 Update code 2020-10-26 23:26:46 +00:00
6038d790f1 Minor fixes 2020-10-24 11:41:15 +01:00
397c753ce3 Add a some new references, apply minor adjustments to some existing references. 2020-10-23 13:36:29 +01:00
8889ecb463 More control operator references. 2020-10-23 00:43:57 +01:00
36f2035003 Control operator references 2020-10-22 17:03:08 +01:00
c707eb769e Fix definition style 2020-10-21 14:36:30 +01:00
5f7bf83332 Section 2.1 intro 2020-10-21 13:06:56 +01:00
a0ed7d2dfd Rewording 2020-10-21 01:53:27 +01:00
efcdcd49a2 Simplify 2020-10-21 01:37:58 +01:00
e1407b2eab Slight elaboration 2020-10-21 01:36:14 +01:00
16aff4f445 Rewording 2020-10-21 01:26:14 +01:00
de88350786 Some scribbles on relations and functions. 2020-10-21 01:24:08 +01:00
ba4c2aac96 Dump content 2020-10-19 22:15:26 +01:00
97e0a787bd Rewording 2020-10-16 12:52:43 +01:00
9373716166 Add reference on local and global state. 2020-10-16 00:16:32 +01:00
c442a711a9 State 2020-10-15 23:29:48 +01:00
53c76a0934 Fix macro use 2020-10-14 22:44:19 +01:00
95244693f4 Interruption via interception, last example. 2020-10-14 22:43:32 +01:00
003c8e4d6c Dedication. 2020-10-13 21:19:48 +01:00
5e602afb68 Rewording 2020-10-13 00:41:09 +01:00
653b1fc56e Interruptions via interceptions 2020-10-13 00:39:20 +01:00
f8c3798cd1 Fix typo 2020-10-12 22:43:28 +01:00
29798f2c43 Timesharing example. 2020-10-12 22:41:10 +01:00
1c77c64f83 Shakespeare 2020-10-12 22:41:02 +01:00
50216c6d8c WIP nondeterminism example. 2020-10-12 16:24:04 +01:00
11ad068943 Non-blind backtracking reference 2020-10-12 15:31:49 +01:00
0a40c9d72b Update bibliography 2020-10-12 12:41:41 +01:00
99b42ee7f1 Move some text around. 2020-10-11 21:46:47 +01:00
0a13628c16 Declaration, bibliography, and a few other fixes. 2020-10-11 21:08:30 +01:00
48ed305a8e Revert dedication 2020-10-10 13:54:44 +01:00
6457753ca6 Something about fork 2020-10-09 23:04:29 +01:00
837fc51651 fix overflow 2020-10-08 00:27:37 +01:00
ceb74e43a3 User session management example. 2020-10-08 00:15:43 +01:00
f605fb78f2 Putc => Write. Don't mention file descriptors. 2020-10-07 21:19:05 +01:00
e08923dadc Note on dynamic binding. 2020-10-07 21:16:22 +01:00
39824fcf18 Exceptions example and figures. 2020-10-07 16:51:08 +01:00
d30ffb2a39 UNIX example figures. 2020-10-07 00:23:19 +01:00
caee5d3a94 Stream redirection example 2020-10-06 23:43:40 +01:00
ca84083998 TCP handshake 2020-10-06 22:44:30 +01:00
75174524c0 File I/O 2020-10-05 20:28:52 +01:00
925d4319d2 Pure file system manipulation functions. 2020-10-03 00:26:51 +01:00
d767e78b44 Try a new syntax for operation cases. 2020-10-02 22:45:51 +01:00
92aed1134a Generic state handling code. 2020-10-02 16:26:29 +01:00
5f0faa13c8 minor code revision. 2020-10-02 16:11:10 +01:00
70ebcde70a Time-sharing code. 2020-10-02 16:10:52 +01:00
495258cf0b Tiny UNIX rev. 2 [WIP] 2020-10-02 16:03:49 +01:00
92172beb30 Remove space 2020-10-02 02:02:01 +01:00
2a50b7402c Code for session management 2020-10-02 01:48:39 +01:00
fe255ba70e Code for non-local exits 2020-10-02 01:22:21 +01:00
313b8a7779 Reword 2020-10-02 01:01:38 +01:00
fcb63fa94f Rewording. 2020-10-02 00:56:59 +01:00
a9ab791261 Fix GNU coreutils bibtex entry. 2020-10-02 00:49:52 +01:00
972b556831 UNIX example: environment [WIP]. 2020-10-02 00:47:59 +01:00
90f1791983 Start UNIX example: basic IO. 2020-10-01 23:09:03 +01:00
18 changed files with 31430 additions and 2076 deletions

View File

@@ -3,8 +3,10 @@ CFLAGS=-interaction=nonstopmode -halt-on-error -file-line-error
BIBC=bibtex
PAPER=thesis
BIBLIO=$(PAPER)
LATEST_COMMIT=$(shell git log --format="%h" -n 1)
all: $(PAPER).pdf
draft: $(PAPER).pdf-draft
$(PAPER).aux: $(PAPER).tex
$(TEXC) $(CFLAGS) $(PAPER)
@@ -16,6 +18,11 @@ $(PAPER).pdf: $(PAPER).aux $(BIBLIO).bbl
$(TEXC) $(CFLAGS) $(PAPER)
$(TEXC) $(CFLAGS) $(PAPER)
$(PAPER).pdf-draft: CFLAGS:=$(CFLAGS) "\def\DRAFT{$(LATEST_COMMIT)}\input{$(PAPER)}"
$(PAPER).pdf-draft: all
mv $(PAPER).pdf $(PAPER)-draft.pdf
tar cf thesis-draft.tar.gz $(PAPER)-draft.pdf
clean:
rm -f *.log *.aux *.toc *.out
rm -f *.bbl *.blg *.fls *.xml

120
README.md
View File

@@ -1,6 +1,120 @@
# PhD dissertation on foundations for programming and implementing effect handlers
# Foundations for programming and implementing effect handlers
A copy of my dissertation can be [downloaded via my
website](https://dhil.net/research/papers/thesis.pdf).
----
Submitted on May 30, 2021. Examined on August 13, 2021.
The board of examiners were
* [Andrew Kennedy](https://github.com/andrewjkennedy) (Facebook London)
* [Edwin Brady](https://www.type-driven.org.uk/edwinb/) (University of St Andrews)
* [Ohad Kammar](http://denotational.co.uk/) (The University of Edinburgh)
* [Stephen Gilmore](https://homepages.inf.ed.ac.uk/stg/) (The University of Edinburgh)
## Thesis structure
The dissertation is structured as follows.
### Introduction
* Chapter 1 puts forth an argument for why effect handlers
matter. Following this argument it provides a basic introduction to
several different approaches to effectful programming through the
lens of the state effect. In addition, it also declares the scope
and contributions of the dissertation, and discusses some related
work.
### Programming
* Chapter 2 illustrates effect handler oriented programming by
example by implementing a small operating system dubbed Tiny UNIX,
which captures some essential traits of Ritchie and Thompson's
UNIX. The implementation starts with a basic notion of file i/o,
and then, it evolves into a feature-rich operating system with full
file i/o, multiple user environments, multi-tasking, and more, by
composing ever more effect handlers.
* Chapter 3 introduces a polymorphic fine-grain call-by-value core
calculus, λ<sub>b</sub>, which makes key use of Rémy-style row
polymorphism to implement polymorphic variants, structural records,
and a structural effect system. The calculus distils the essence of
the core of the Links programming language. The chapter also
presents three extensions of λ<sub>b</sub>, which are λ<sub>h</sub>
that adds deep handlers, λ<sup>†</sup> that adds shallow handlers,
and λ<sup>‡</sup> that adds parameterised handlers.
### Implementation
* Chapter 4 develops a higher-order continuation passing style
translation for effect handlers through a series of step-wise
refinements of an initial standard continuation passing style
translation for λ<sub>b</sub>. Each refinement slightly modifies
the notion of continuation employed by the translation. The
development ultimately leads to the key invention of generalised
continuation, which is used to give a continuation passing style
semantics to deep, shallow, and parameterised handlers.
* Chapter 5 demonstrates an application of generalised continuations
to abstract machine as we plug generalised continuations into
Felleisen and Friedman's CEK machine to obtain an adequate abstract
runtime with simultaneous support for deep, shallow, and
parameterised handlers.
### Expressiveness
* Chapter 6 shows that deep, shallow, and parameterised notions of
handlers can simulate one another up to specific notions of
administrative reduction.
* Chapter 7 studies the fundamental efficiency of effect handlers. In
this chapter, we show that effect handlers enable an asymptotic
improvement in runtime complexity for a certain class of
functions. Specifically, we consider the *generic count* problem
using a pure PCF-like base language λ<sub>b</sub><sup>→</sup> (a
simply typed variation of λ<sub>b</sub>) and its extension with
effect handlers λ<sub>h</sub><sup>→</sup>. We show that
λ<sub>h</sub><sup>→</sup> admits an asymptotically more efficient
implementation of generic count than any λ<sub>b</sub><sup>→</sup>
implementation.
### Conclusions
* Chapter 8 concludes and discusses future work.
### Appendices
* Appendix A contains a literature survey of continuations and
first-class control. I classify continuations according to their
operational behaviour and provide an overview of the various
first-class sequential control operators that appear in the
literature. The application spectrum of continuations is discussed
as well as implementation strategies for first-class control.
* Appendix B contains a proof that shows the `Get-get` equation for
state is redundant.
* Appendix C contains the proof details and gadgetry for the
complexity of the effectful generic count program.
* Appendix D provides a sample implementation of the Berger count
program and discusses it in more detail.
## Building
To build the dissertation you need the [Informatics thesis LaTeX
class](https://github.com/dhil/inf-thesis-latex-cls).
class](https://github.com/dhil/inf-thesis-latex-cls) with the
University of Edinburgh crests. Invoking `make` on the command line
ought to produce a PDF copy of the dissertation named `thesis.pdf`,
e.g.
Don't hold your breath... This thing isn't due for a while...
```shell
$ make
```
## Timeline
I submitted my thesis on May 30, 2021. It was examined on August 13,
2021, where I received pass with minor corrections. The revised thesis
was submitted on December 22, 2021. It was approved on March
14, 2022. The final revision was submitted on March 23, 2022. I
received my PhD award letter on March 24, 2022. My graduation
ceremony took place in McEwan Hall on July 11, 2022.

124
code/State.hs Normal file
View File

@@ -0,0 +1,124 @@
{- A Haskell version of the companion code for "State of effectful programming".
Tested with GHCi 8.6.5. -}
import Control.Monad.ST (runST)
import Data.STRef (newSTRef, readSTRef, writeSTRef)
-- State monad
newtype State s a = State { runState :: s -> (a,s) }
-- | State is a functor
instance Functor (State s) where
fmap f m = State (\st -> let (x, st') = runState m st in
(f x, st'))
-- | State is an applicative functor
instance Applicative (State s) where
pure x = State (\st -> (x, st))
m1 <*> m2 = State (\st -> let (f, st') = runState m1 st in
runState (fmap f m2) st')
-- | State is a monad
instance Monad (State s) where
return = pure
m >>= k = State (\st -> let (x, st') = runState m st in
runState (k x) st')
-- | State operations
get :: () -> State s s
get () = State (\st -> (st, st))
put :: s -> State s ()
put st = State (\st' -> ((), st))
-- Continuation monad
newtype Cont r a = Cont { runCont :: (a -> r) -> r }
-- | Cont is a functor
instance Functor (Cont r) where
fmap f k = Cont (\g -> runCont k (\x -> g (f x)))
-- | Cont is an applicative functor
instance Applicative (Cont r) where
pure x = Cont (\k -> k x)
k <*> k' = Cont (\r -> runCont k
(\k'' -> runCont k'
(\x -> r (k'' x))))
-- | Cont is a monad
instance Monad (Cont r) where
return = pure
m >>= k = Cont (\k' -> runCont m
(\x -> runCont (k x)
(\y -> k' y)))
-- | State operations
getk :: () -> Cont (State s a) s
getk () = Cont (\k -> State (\st -> runState (k st) st))
putk :: s -> Cont (State s a) ()
putk st' = Cont (\k -> State (\st -> runState (k ()) st'))
-- Free monad
data Free f a = Return a
| Op (f (Free f a))
-- | Free is a functor
instance Functor f => Functor (Free f) where
fmap f (Return x) = Return (f x)
fmap f (Op y) = Op (fmap (fmap f) y)
-- | Free is an applicative functor
instance Functor f => Applicative (Free f) where
pure = Return
(Return f) <*> xs = fmap f xs
(Op f) <*> xs = Op (fmap (\g -> g <*> xs) f)
-- | Free is a monad
instance Functor f => Monad (Free f) where
return = Return
(Return x) >>= k = k x
(Op y) >>= k = Op (fmap (\m' -> m' >>= k) y)
-- | Auxiliary function for constructing operation nodes
do' :: Functor f => f a -> Free f a
do' op = Op (fmap Return op)
-- Instantiate Free with state
data FreeState s r = Get (s -> r)
| Put s (() -> r)
-- | FreeState is a functor
instance Functor (FreeState s) where
fmap f (Get k) = Get (\st -> f (k st))
fmap f (Put st' k) = Put st' (\() -> f (k ()))
-- | State operations
get' :: () -> Free (FreeState s) s
get' () = do' (Get (\x -> x))
put' :: s -> Free (FreeState s) ()
put' st = do' (Put st (\() -> ()))
-- | State handler
runState' :: s -> Free (FreeState s) a -> (a, s)
runState' st0 (Op (Get k)) = runState' st0 (k st0)
runState' st0 (Op (Put st k)) = runState' st (k ())
runState' st0 (Return x) = (x, st0)
-- Generic state example
incrEven :: Monad m => (() -> m Int, Int -> m ()) -> () -> m Bool
incrEven (get, put) () = get () >>= (\st -> put (1 + st) >>= (\() -> return (even st)))
runExamples :: Int -> [(String, (Bool, Int))]
runExamples st0 = map (\(s, f) -> (s, f st0)) examples
where examples = [ ("builtin state", \st -> runST $ do
st' <- newSTRef st
v <- readSTRef st'
writeSTRef st' (v + 1)
v' <- readSTRef st'
return (even v, v'))
, ("pure state passing", \st -> (even st, st + 1))
, ("state monad", \st -> runState (incrEven (get, put) ()) st)
, ("continuation monad", \st -> runState (runCont (incrEven (getk, putk) ())
(\x -> State (\st -> (x, st)))) st)
, ("free monad", \st -> runState' st (incrEven (get', put') ())) ]

1469
code/ehop2022.links Normal file

File diff suppressed because it is too large Load Diff

396
code/state.ml Normal file
View File

@@ -0,0 +1,396 @@
(* Companion for "State of effectful programming"
Tested with OCaml 4.10.0+multicore. *)
(* Generic direct-style incr_even *)
let even : int -> bool
= fun n -> n mod 2 = 0
let incr_even : (unit -> int) * (int -> unit) -> unit -> bool
= fun (get, put) () ->
let st = get () in
put (1 + st);
even st
(* Delimited control *)
module Prompt : sig
type 'a t
val make : unit -> 'a t
val reify : 'a t -> (('b -> 'a) -> 'a) -> 'b
val install : 'a t -> (unit -> 'a) -> 'a
end = struct
type 'a t = {
install : (unit -> 'a) -> 'a;
reify : 'b. (('b -> 'a) -> 'a) -> 'b
}
let make (type a) () =
let module M = struct
effect Prompt : (('b -> a) -> a) -> 'b
end
in
let reify f = perform (M.Prompt f) in
let install f =
match f () with
| x -> x
| effect (M.Prompt f) k -> f (continue k)
in
{ install; reify }
let install { install; _ } = install
let reify { reify; _ } = reify
let resume k v = continue k v
end
module type CTRL = sig
type ans
val reset : (unit -> ans) -> ans
val shift : (('a -> ans) -> ans) -> 'a
end
module Ctrl(R : sig type ans end) : sig
include CTRL with type ans = R.ans
end = struct
type ans = R.ans
let p : ans Prompt.t = Prompt.make ()
let reset m =
Prompt.install p m
let shift f =
Prompt.reify p
(fun k ->
Prompt.install p
(fun () ->
f (fun x ->
Prompt.install p
(fun () -> k x))))
end
module CtrlState
(S : sig type s end)
(R : sig type ans end): sig
type s = S.s
type ans = s -> R.ans * s
val get : unit -> s
val put : s -> unit
val run : (unit -> R.ans) -> ans
end = struct
type s = S.s
type ans = s -> R.ans * s
module Ctrl = Ctrl(struct type nonrec ans = ans end)
let get () = Ctrl.shift (fun k -> fun st -> k st st)
let put st' = Ctrl.shift (fun k -> fun st -> k () st')
let run m =
Ctrl.reset
(fun () ->
let x = m () in
fun st -> (x, st))
end
module CtrlIntState = CtrlState(struct type s = int end)(struct type ans = bool end)
(* Monadic programming *)
module type MONAD = sig
type 'a t
val return : 'a -> 'a t
val (>>=) : 'a t -> ('a -> 'b t) -> 'b t
end
(** State monad **)
module type STATE_MONAD = sig
type ans
type s
include MONAD
val get : unit -> s t
val put : s -> unit t
val run : (unit -> ans t) -> s -> ans * s
end
module StateMonad(S : sig type s end)(R : sig type ans end): sig
include STATE_MONAD with type s = S.s
and type ans = R.ans
end = struct
type ans = R.ans
type s = S.s
type 'a t = s -> 'a * s
let return : 'a -> 'a t
= fun x -> fun st -> (x, st)
let (>>=) : 'a t -> ('a -> 'b t) -> 'b t
= fun m k -> fun st ->
let (x, st') = m st in
k x st'
let get : unit -> s t
= fun () st -> (st, st)
let put : s -> unit t
= fun st st' -> ((), st)
let run : (unit -> ans t) -> s -> ans * s
= fun m st -> m () st
end
module IntStateMonad = StateMonad(struct type s = int end)(struct type ans = bool end)
(** Continuation monad **)
module type CONTINUATION_MONAD = sig
type r
include MONAD with type 'a t = ('a -> r) -> r
end
module ContinuationMonad(R : sig type ans end): sig
include CONTINUATION_MONAD with type r = R.ans
end = struct
type r = R.ans
type 'a t = ('a -> r) -> r
let return : 'a -> 'a t
= fun x -> fun k -> k x
let (>>=) : 'a t -> ('a -> 'b t) -> 'b t
= fun m k -> fun c ->
m (fun x -> k x c)
end
module ContinuationStateMonad
(S : sig type s end)
(R : sig type ans end): sig
type s = S.s
type ans = R.ans
include CONTINUATION_MONAD with type r = s -> ans * s
val get : unit -> s t
val put : s -> unit t
val run : (unit -> ans t) -> s -> ans * s
end = struct
type s = S.s
type ans = R.ans
module ContinuationMonad : CONTINUATION_MONAD with type r = s -> ans * s
= ContinuationMonad(struct type nonrec ans = s -> ans * s end)
include ContinuationMonad
let get : unit -> s t
= fun () -> fun k -> fun st -> k st st
let put : s -> unit t
= fun st' -> fun k -> fun st -> k () st'
let run : (unit -> R.ans t) -> s -> R.ans * s =
fun m st -> m () (fun x -> fun st -> (x, st)) st
end
module ContinuationIntStateMonad
= ContinuationStateMonad(struct type s = int end)(struct type ans = bool end)
(** Free monad **)
module type FUNCTOR = sig
type 'a t
val fmap : ('a -> 'b) -> 'a t -> 'b t
end
module type FREE_MONAD = sig
type 'a op
type 'a free = Return of 'a
| Op of 'a free op
include MONAD with type 'a t = 'a free
val do' : 'a op -> 'a free
end
module FreeMonad(F : FUNCTOR) : sig
include FREE_MONAD with type 'a op = 'a F.t
end = struct
type 'a op = 'a F.t
type 'a free = Return of 'a
| Op of 'a free F.t
type 'a t = 'a free
let return : 'a -> 'a t
= fun x -> Return x
let rec (>>=) : 'a t -> ('a -> 'b t) -> 'b t
= fun m k ->
match m with
| Return x -> k x
| Op y -> Op (F.fmap (fun m' -> m' >>= k) y)
let do' : 'a F.t -> 'a free
= fun op -> Op (F.fmap (fun x -> Return x) op)
end
module type FREE_STATE = sig
type s
type 'r opsig = Get of (s -> 'r)
| Put of s * (unit -> 'r)
include FUNCTOR with type 'r t = 'r opsig
end
module FreeState(S : sig type s end) = struct
type s = S.s
type 'r opsig = Get of (s -> 'r)
| Put of s * (unit -> 'r)
type 'r t = 'r opsig
let fmap : ('a -> 'b) -> 'a t -> 'b t
= fun f op ->
match op with
| Get k -> Get (fun st -> f (k st))
| Put (st', k) -> Put (st', fun st -> f (k ()))
end
module FreeIntStateMonad: sig
include STATE_MONAD with type s = int
and type ans = bool
end = struct
module rec FreeIntState : FREE_STATE with type s = int
= FreeState(struct type s = int end)
and FreeIntStateMonad : FREE_MONAD with type 'r op = 'r FreeIntState.opsig
= FreeMonad(FreeIntState)
open FreeIntState
include FreeIntStateMonad
type s = int
type ans = bool
let get : unit -> s t
= fun () -> do' (Get (fun st -> st))
let put : s -> unit t
= fun st -> do' (Put (st, fun () -> ()))
let rec run : (unit -> ans t) -> s -> ans * s
= fun m st ->
match m () with
| Return x -> (x, st)
| Op (Get k) -> run (fun () -> k st) st
| Op (Put (st', k)) -> run k st'
end
(** Monadic reflection **)
module Reflect
(M : MONAD)
(R : sig type ans end): sig
type ans = R.ans
val reify : (unit -> ans) -> ans M.t
val reflect : 'a M.t -> 'a
end = struct
type ans = R.ans
effect Reflect : 'a M.t -> 'a
let reify : (unit -> ans) -> ans M.t
= fun f ->
let open M in
match f () with
| x -> return x
| effect (Reflect m) k -> m >>= (continue k)
let reflect : 'a M.t -> 'a
= fun m ->
perform (Reflect m)
end
module ReflectIntStateMonad
= Reflect(IntStateMonad)(struct type ans = bool end)
module ReflectIntState = struct
open ReflectIntStateMonad
let get : unit -> int
= fun () -> reflect (IntStateMonad.get ())
let put : int -> unit
= fun st -> reflect (IntStateMonad.put st)
let run : (unit -> bool) -> int -> bool * int
= fun m st -> IntStateMonad.run (fun () -> reify m) st
end
(* Generic monadic incr_even *)
module MonadExample(T : STATE_MONAD with type s = int) = struct
let incr_even : unit -> bool T.t
= fun () ->
let open T in
(get ()) >>= (fun st -> put (1 + st)
>>= (fun () -> return (even st)))
end
(** Effect handlers **)
module type STATE_HANDLER = sig
type s
val get : unit -> s
val put : s -> unit
val run : (unit -> 'a) -> s -> 'a * s
end
module StateHandler(S : sig type s end) : STATE_HANDLER with type s = S.s = struct
type s = S.s
effect Put : s -> unit
let put st = perform (Put st)
effect Get : unit -> s
let get () = perform (Get ())
let run
= fun m st ->
let f = match m () with
| x -> (fun st -> (x, st))
| effect (Put st') k -> (fun st -> continue k () st')
| effect (Get ()) k -> (fun st -> continue k st st)
in f st
end
module IntStateHandler = StateHandler(struct type s = int end)
let run_examples () =
let examples = [
"builtin", (fun st ->
let st = ref st in let v = !st in st := 1 + v; (even v, !st));
"pure state passing", (fun st -> (even st, 1 + st));
"shift/reset", (fun st ->
CtrlIntState.run (incr_even CtrlIntState.(get, put)) st);
"state monad", (fun st ->
let module MonadStateExample = MonadExample(IntStateMonad) in
IntStateMonad.run MonadStateExample.incr_even st);
"continuation monad", (fun st ->
let module ContinuationMonadExample = MonadExample(ContinuationIntStateMonad) in
ContinuationIntStateMonad.run ContinuationMonadExample.incr_even st);
"free monad", (fun st ->
let module FreeMonadExample = MonadExample(FreeIntStateMonad) in
FreeIntStateMonad.run FreeMonadExample.incr_even st);
"monadic reflection", (fun st ->
ReflectIntState.run (incr_even ReflectIntState.(get, put)) st);
"state handler", (fun st ->
IntStateHandler.run (incr_even IntStateHandler.(get, put)) st) ]
in
List.map (fun (s, f) -> (s, f 4)) examples
(* module IntStateMRefl : MREFL with type ans := bool and type 'a t = 'a IntState.t
* = MRefl(struct type ans = bool end)(IntState)
*
* let get () = IntStateMRefl.reflect (IntState.get ())
* let put st = IntStateMRefl.reflect (IntState.put st)
* let run m st = IntState.run (IntStateMRefl.reify m) st
*
* let even : int -> bool
* = fun n -> n mod 2 = 0
*
* let incr_even : unit -> bool
* = fun () ->
* let st = get () in
* put (1 + st);
* even st *)

1352
code/unix-huawei2022.links Normal file

File diff suppressed because it is too large Load Diff

1372
code/unix-msr2022.links Normal file

File diff suppressed because it is too large Load Diff

1352
code/unix-nuprl2022.links Normal file

File diff suppressed because it is too large Load Diff

782
code/unix-plug2020.links Normal file
View File

@@ -0,0 +1,782 @@
## Prelude
typename Option(a) = [|None|Some:a|];
sig todo : (String) ~> a
fun todo(s) { error("TODO: " ^^ s) }
sig fail : () {Fail:Zero |_}-> a
fun fail() { switch (do Fail) { } }
sig lookup : (a, [(a, b)]) {Fail:Zero |_}~> b
fun lookup(k, kvs) {
switch (kvs) {
case [] -> fail()
case (k', v) :: kvs' ->
if (k == k') v
else lookup(k, kvs')
}
}
sig modify : (a, b, [(a, b)]) ~> [(a, b)]
fun modify(k, v, kvs) {
switch (kvs) {
case [] -> []
case (k', v') :: kvs' ->
if (k == k') (k, v) :: kvs'
else (k', v') :: modify(k, v, kvs')
}
}
sig remove : (a, [(a, b)]) ~> [(a, b)]
fun remove(k, kvs) {
switch (kvs) {
case [] -> []
case (k', v') :: kvs' ->
if (k == k') kvs'
else (k', v') :: remove(k, kvs')
}
}
sig has : (a, [(a, b)]) ~> Bool
fun has(k, kvs) {
switch (kvs) {
case [] -> false
case (k', _) :: kvs' ->
k == k' || has(k, kvs')
}
}
#!
#
# UNIX in 50 lines of code or less
# Daniel Hillerström
# Laboratory for Foundations of Computer Science
# The University of Edinburgh
#
# PLUG talk
# University of Glasgow
# December 8, 2020
#
# https://dhil.net/research/
#
#?
#!
#
# What is an operating system? (very abstractly)
#
# An operating system responds to a collection of system calls
#
# Example tasks:
# - Signalling errors
# - Scheduling processes
# - Reading/writing I/O
#?
#!
#
# What is an effect handler? (very abstractly)
#
# An effect handler responds a collection of abstract operation calls
#
# Example tasks:
# - Signalling errors
# - Scheduling processes
# - Reading/writing I/O
#
#
#
#
#
#?
#!
#
# What is an effect handler? (very abstractly)
#
# An effect handler responds a collection of abstract operation calls
#
# Example tasks:
# - Signalling errors
# - Scheduling processes
# - Reading/writing I/O
#
# Thus an effect handler is an operating system (credit James McKinna)
# (Kiselyov and Shan (2007) used delimited continuations to model
# operating systems)
#
#?
#!
#
# Objectives of this talk
#
# - Demonstrate the versatility of handlers
# - Explain operating systems as the combination of
# + Exceptions
# + Dynamic binding
# + Nondeterminism
# + State
#
#?
#
#
# What is UNIX?
#
# UNIX is an operating system designed by Ritchie and Thompson (1974)
#
# Components
# - Commands (system calls)
# + I/O interaction, user session management, inter-process
# communication, etc
# - Kernel (interpreter)
# + Handling of I/O, managing user sessions, scheduling of
# processes
# - Development environment
# + Compiler tool-chains (e.g. `cc`)
# - Documentation
# + manual pages (e.g. `man`)
#
#
#!
#
# Key characteristics of UNIX (Ritchie & Thompson, 1974)
#
# - Support for multiple user sessions
# - Time-sharing between processes
# - "Everything is a file"
#
#?
#!
#
# Basic I/O: Performing writes
#
typename File = String;
typename FileDescr = Int;
sig stdout : FileDescr
var stdout = 1;
sig echo : (String) {Write:(FileDescr,String) -> () |%}-> ()
fun echo(cs) { todo("implement echo") }
#?
#!
#
# Basic I/O: Handling writes
#
sig basicIO : ( () {Write:(FileDescr,String) -> () |%}-> a ) { |%}-> (a, File)
fun basicIO(m) {
todo("implement basicIO")
}
#?
#!
#
# Basic I/O: Example
#
sig example0 : () { |%}-> ((), File)
fun example0() {
basicIO(fun() {
echo("Hello"); echo("World")
})
}
#?
#!
#
# Dynamic semantics of handlers
#
# (ret) handle(V) { case Return(x) -> N case ... }
# ~> N[V/x]
#
# (op) handle(E[do Op(V)]) { case Op(p,r) -> N case ... }
# ~> N[V/p
# ,fun(x){ handle(E[x]) { case Op(p,r) -> N case ... }}/r]
# (if Op \notin E)
#
#?
#!
#
# Exceptions: Premature exits
#
sig exit : (Int) {Exit:(Int) -> Zero |%}-> a
fun exit(n) { todo("implement exit") }
#?
#!
#
# Handling exits
#
sig status : (() {Exit:(Int) -> Zero |%}-> a) { |%}-> Int
fun status(m) {
todo("implement status")
}
#?
#!
#
# Handling exits: Example
#
sig example1 : () { |%}-> (Int, File)
fun example1() {
basicIO(fun() {
status(fun() {
echo("dead"); exit(1); echo("code")
})
})
}
#?
#!
#
# Dynamic binding: User-specific environments (1)
#
typename User = [|Alice|Bob|Root|];
sig whoami : () {Ask:String |%}-> String
fun whoami() { do Ask }
#?
#!
#
# Dynamic binding: User-specific environments (2)
#
sig env : (User, () {Ask:String |%}-> a) { |%}-> a
fun env(user, m) {
handle(m()) {
case Return(x) -> x
case Ask(resume) ->
switch (user) {
case Alice -> resume("alice")
case Bob -> resume("bob")
case Root -> resume("root")
}
}
}
sig example2 : () { |%}-> String
fun example2() {
env(Root, whoami)
}
#?
#!
#
# Aside: Dynamic binding with delimited continuations
#
# The idea of dynamic binding dates back to at least McCarthy (1960)
#
# Kiselyov, Shan, and Sabry (2006) demonstrated dynamic binding can be
# simulated with delimited continuations
#
#?
#!
#
# User session management
#
sig su : (User) {Su:(User) -> () |%}-> ()
fun su(user) { do Su(user) }
sig sessionmgr : (User, () {Ask:String, Su:(User) -> () |%}-> a) { |%}-> a
fun sessionmgr(user, m) {
env(user, fun() {
handle(m()) {
case Return(x) -> x
case Su(user', resume) ->
env(user', fun() { resume(()) })
}
})
}
#?
#!
#
# Multiple user sessions example
#
sig example3 : () { |%}-> (Int, File)
fun example3() {
basicIO(fun() {
sessionmgr(Root, fun() {
status(fun() {
su(Alice); echo(whoami()); echo(" ");
su(Bob); echo(whoami()); echo(" ");
su(Root); echo(whoami())
})
})
})
}
#?
#!
#
# Nondeterminism: Multi-tasking (1)
#
# From the man pages.
#
# Description
# fork() creates a new process by duplicating the calling process. The
# new process is referred to as the child process. The calling process
# is referred to as the parent process.
#
# Return value
# On success, the PID of the child process is returned in the parent,
# and 0 is returned in the child.
#
#?
#!
#
# Nondeterminism: Multi-tasking (2)
#
sig fork : () {Fork:Bool |_}-> Bool
fun fork() { do Fork }
sig nondet : (() {Fork:Bool |%}-> a) { |%}-> [a]
fun nondet(m) {
handle(m()) {
case Return(ans) -> todo("implement Return case")
case Fork(resume) -> todo("implement Fork case")
}
}
#?
#!
#
# Nondeterminism: Example (1)
#
sig ritchie : () {Write:(FileDescr, String) -> () |%}-> ()
fun ritchie() {
echo("UNIX is basically ");
echo("a simple operating system, ");
echo("but ");
echo("you have to be a genius to understand the simplicity.\n")
}
sig hamlet : () {Write:(FileDescr, String) -> () |%}-> ()
fun hamlet() {
echo("To be, or not to be,\n");
echo("that is the question:\n");
echo("Whether 'tis nobler in the mind to suffer\n")
}
#?
#!
#
# Nondeterminism: Example (2)
#
sig example4 : () { |%}-> ([Int], File)
fun example4() {
basicIO(fun() {
nondet(fun() {
sessionmgr(Root, fun() {
status(fun() {
if (fork()) {
su(Alice);
ritchie()
} else {
su(Bob);
hamlet()
}
})
})
})
})
}
#?
#
#
# Mathematically well-founded nondeterminism
#
# The handler `nondet` is _exactly_ the handler Plotkin and Pretnar (2013)
# give for nondeterminism
# It satisfies the usual (semi-lattice) equations for nondeterministic choice, i.e.
#
# if (fork()) M else M = M
# if (fork()) M else N = if (fork()) N else M
# if (fork()) L else { if (fork()) M else N } = if (fork()) { if (fork()) L else M } else N
#
#
#!
#
# Interrupting processes
#
sig interrupt : () {Interrupt:() |%}-> ()
fun interrupt() { do Interrupt }
# Process reification
typename Pstate(a,e::Eff)
= forall q::Presence.
[|Done:a
|Paused:() {Interrupt{q} |e}-> Pstate(a, { |e})|];
sig reifyProcess : (() {Interrupt:() |%}-> a) { |%}-> Pstate(a, { |%})
fun reifyProcess(m) {
handle(m()) {
case Return(ans) -> Done(ans)
case Interrupt(resume) -> Paused(fun() { resume(()) })
}
}
#?
#!
#
# Time-sharing via interrupts
#
sig schedule : ([Pstate(a, { Fork:Bool |%})]) { |%}~> [a]
fun schedule(ps) {
fun schedule(ps, done) {
switch (ps) {
case [] -> done
case Done(res) :: ps' ->
schedule(ps', res :: done)
case Paused(resume) :: ps' ->
schedule(ps' ++ nondet(resume), done)
}
}
schedule(ps, [])
}
sig timeshare : (() {Fork:Bool,Interrupt:() |%}-> a) { |%}-> [a]
fun timeshare(m) {
var p = Paused(fun() { reifyProcess(m) });
schedule([p])
}
#?
#!
#
# Injecting interrupts
#
# First idea: external source injects interrupts (Ahman and Pretnar (2021))
#
# Second idea: bundle interrupts with other operations
sig echo' : (FileDescr,String) {Interrupt:(), Write:(FileDescr,String) -> () |%}-> ()
fun echo'(fd, cs) { interrupt(); do Write(fd, cs) }
#
# Third idea: overload interpretations of operations
sig interruptWrite : (() {Write:(FileDescr,String) -> () |%}-> a)
{Write:(FileDescr,String) -> () |%}-> a
fun interruptWrite(m) {
handle(m()) {
case Return(res) -> res
case Write(fd, cs, resume) ->
interrupt(); resume(do Write(fd, cs))
}
}
#?
#!
#
# Time-sharing example
#
sig example5 : () { |%}-> ([Int], File)
fun example5() {
basicIO(fun() {
timeshare(fun() {
interruptWrite(fun() {
sessionmgr(Root, fun() {
status(fun() {
if (fork()) {
su(Alice);
ritchie()
} else {
su(Bob);
hamlet()
}
})
})
})
})
})
}
#?
#!
#
# State: File I/O
#
# Generic state handling
sig get : () {Get:s |_}-> s
fun get() { do Get }
sig put : (s) {Put:(s) -> () |_}-> ()
fun put(st) { do Put(st) }
sig runState : (s, () {Get:() -> s,Put:(s) -> () |%}-> a) { |%}-> (a, s)
fun runState(st0, m) {
var f = handle(m()) {
case Return(x) -> fun(st) { (x, st) }
case Get(resume) -> fun(st) { resume(st)(st) }
case Put(st',resume) -> fun(_) { resume(())(st') }
};
f(st0)
}
#?
#!
#
# State: Example
#
sig incr : () {Get:Int,Put:(Int) -> () |%}-> ()
fun incr() { put(get() + 1) }
sig example6 : () { |%}-> ((), Int)
fun example6() {
runState(41, incr)
}
#?
#!
#
# Basic Serial File System
#
# Directory I-List Data region
# +----------------+ +-------+ +--------------------------+
# | "hamlet" |------> | 2 |---> | "To be, or not to be..." |
# +----------------+ / +-------+ +--------------------------+
# | "richtie.txt" |------> | 1 |---> | "UNIX is basically..." |
# +----------------+ / +-------+ +--------------------------+
# | ... | | | ... | | ... |
# +----------------+ | +-------+ +--------------------------+
# | "stdout" |------> | 1 |---> | "" |
# +----------------+ | +-------+ +--------------------------+
# | ... | /
# +----------------+ /
# | "act3" |---
# +----------------+
#
# Simplifications:
# - Operating directly on inode pointers
# - Reads and writes will be serial
#
#?
#!
#
# BSFS structures
#
typename INode = (loc:Int,lno:Int);
typename IList = [(Int, INode)]; # INode index -> INode
typename Directory = [(String, Int)]; # Filename -> INode index
typename DataRegion = [(Int, File)]; # Loc -> File
typename FileSystem = (dir:Directory,dregion:DataRegion,inodes:IList
,lnext:Int ,inext:Int );
sig fsys0 : FileSystem
var fsys0 = ( dir = [("stdout", 0)]
, inodes = [(0, (loc=0, lno=1))]
, dregion = [(0, "")]
, lnext = 1, inext = 1 );
# Utility functions
sig lookup : (a, [(a, b)]) {Fail:Zero |%}-> b
var lookup = lookup;
sig withDefault : (a, () {Fail:Zero |%}-> a) { |%}-> a
fun withDefault(x', m) {
handle(m()) {
case Return(x) -> x
case Fail(_) -> x'
}
}
#?
sig fwrite : (Int, String, FileSystem) {Fail:Zero |%}-> FileSystem
fun fwrite(ino, cs, fsys) {
var inode = lookup(ino, fsys.inodes);
var file = lookup(inode.loc, fsys.dregion);
var file' = file ^^ cs;
(fsys with dregion = modify(inode.loc, file', fsys.dregion))
}
sig fread : (Int, FileSystem) {Fail:Zero |%}-> String
fun fread(ino, fsys) {
var inode = lookup(ino, fsys.inodes);
lookup(inode.loc, fsys.dregion)
}
#!
#
# Handling BSFS operations: file reading and writing
#
sig fwrite : (FileDescr, String, FileSystem) {Fail:Zero |%}-> FileSystem
var fwrite = fwrite;
sig fread : (FileDescr, FileSystem) {Fail:Zero |%}-> String
var fread = fread;
sig fileRW : ( () { Read :(FileDescr) -> Option(String)
, Write:(FileDescr, String) -> () |%}-> a )
{Get:FileSystem,Put:(FileSystem) -> () |%}-> a
fun fileRW(m) {
handle(m()) {
case Return(ans) -> ans
case Read(fd, resume) ->
var cs = withDefault(None, fun() {
Some(fread(fd, get()))
}); resume(cs)
case Write(fd, cs, resume) ->
withDefault((), fun() {
var fsys = fwrite(fd, cs, get());
put(fsys)
}); resume(())
}
}
#?
sig fopen : (String, FileSystem) {Fail:Zero |%}-> FileDescr
fun fopen(fname, fsys) { lookup(fname, fsys.dir) }
sig fcreate : (String, FileSystem) {Fail:Zero |%}-> (FileDescr, FileSystem)
fun fcreate(fname, fsys) {
if (has(fname, fsys.dir)) {
var ino = fopen(fname, fsys);
# Truncate file
var inode = lookup(ino, fsys.inodes);
var dregion = modify(inode.loc, "", fsys.dregion);
(ino, (fsys with =dregion))
} else {
var loc = fsys.lnext;
var dregion = (loc, "") :: fsys.dregion;
var ino = fsys.inext;
var inode = (loc=loc,lno=1);
var inodes = (ino, inode) :: fsys.inodes;
var dir = (fname, ino) :: fsys.dir;
(ino, (=dir, =dregion, =inodes, lnext=loc+1, inext=ino+1))
}
}
#!
#
# BSFS operation: file opening and creation
#
sig fopen : (String, FileSystem) {Fail:Zero |%}-> FileDescr
var fopen = fopen;
sig fcreate : (String, FileSystem) {Fail:Zero |%}-> (FileDescr, FileSystem)
var fcreate = fcreate;
sig fileOC : ( () { Open :(String) -> Option(FileDescr)
, Create:(String) -> Option(FileDescr) |%}-> a )
{Get:FileSystem,Put:(FileSystem) -> () |%}-> a
fun fileOC(m) {
handle(m()) {
case Return(ans) -> ans
case Open(fname, resume) ->
var fd = withDefault(None, fun() {
Some(fopen(fname, get()))
}); resume(fd)
case Create(fname, resume) ->
var fd = withDefault(None, fun() {
var (fd, fsys) = fcreate(fname, get());
put(fsys); Some(fd)
}); resume(fd)
}
}
#?
#!
#
# BSFS version 0
#
sig bsfs0 : ( () { Open :(String) -> Option(FileDescr)
, Create:(String) -> Option(FileDescr)
, Read :(FileDescr) -> Option(String)
, Write:(FileDescr, String) -> () |%}-> a )
{Get:FileSystem,Put:(FileSystem) -> () |%}-> a
fun bsfs0(m) {
fileOC(fun() {
fileRW(m)
})
}
#?
#!
#
# Stream redirection
#
sig >- : (() { |%}-> a, String)
{ Create:(String) -> Option(FileDescr)
, Exit : (Int) -> Zero
, Write :(FileDescr,String) -> () |%}-> a
op f >- fname {
var fd = switch (do Create(fname)) {
case None -> exit(-1)
case Some(fd) -> fd
}; handle(f()) {
case Return(x) -> x
case Write(_, cs, resume) ->
resume(do Write(fd, cs))
}
}
#?
#!
#
# Crude copy
#
sig ccp : (String, String) { Create:(String) -> Option(FileDescr)
, Exit :(Int) -> Zero
, Read :(FileDescr) -> Option(String)
, Open :(String) -> Option(FileDescr)
, Write :(FileDescr,String) -> () |%}-> ()
fun ccp(src, dst) {
var srcfd = switch (do Open(src)) {
case None -> exit(-1)
case Some(fd) -> fd
};
switch (do Read(srcfd)) {
case None -> exit(-1)
case Some(cs) -> fun() {echo(cs)} >- dst
}
}
#?
#!
#
# Plugging everything together
#
sig example7 : () { |%}-> ([Int], FileSystem)
fun example7() {
runState(fsys0, fun() {
bsfs0(fun() {
timeshare(fun() {
sessionmgr(Root, fun() {
status(fun() {
if (fork()) {
su(Alice);
ritchie >- "ritchie.txt"
} else {
su(Bob);
hamlet >- "hamlet";
ccp("hamlet", "act3")
}
})
})
})
})
})
}
#?
#!
#
# Conclusion
#
# Effect handlers are a versatile programming abstraction
# Operating systems can be explained in terms of handlers
# "Every problem can be solved by adding another handler"
#
#?

1393
code/unix-tutorial.links Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -45,8 +45,6 @@ module Queue {
fun singleton(x) { enqueue(x, empty) }
}
##
## Environment
##
@@ -106,6 +104,27 @@ fun usermgr(user, envs, m) {
## Basic IO
##
typename FileDescr = Int;
typename FileCursor = Int;
module File {
typename T = [String];
sig empty : T
var empty = [];
sig read : (FileCursor, T) ~> Option(String)
fun read(start, file) {
switch (drop(start, file)) {
case [] -> None
case x :: _ -> Some(x)
}
}
sig write : (String, FileCursor, T) ~> T
fun write(contents, fptr, file) {
take(fptr, file) ++ [contents] ++ drop(fptr, file)
}
}
sig stdout : FileDescr
var stdout = 1;
@@ -113,7 +132,7 @@ var stdout = 1;
sig puts : (FileDescr,String) {Puts:(FileDescr,String) -> () |_}-> ()
fun puts(fd, s) { do Puts(fd, s) }
sig basicIO : (Comp(a, {Puts:(FileDescr,String) -> () |e})) {Puts{_} |e}~> [String]
sig basicIO : (Comp(a, {Puts:(FileDescr,String) -> () |e})) {Puts{_} |e}~> File.T
fun basicIO(m) {
handle(m()) {
case Return(_) -> []
@@ -121,8 +140,6 @@ fun basicIO(m) {
}
}
# TODO: implement file space.
##
## Generic state handling.
##
@@ -153,118 +170,125 @@ var stderr = 2;
sig eof : String
var eof = "\x00";
sig gets : (FileDescr) {Gets:(FileDescr) -> String |_}-> String
fun gets(fd) { do Gets(fd) }
typename Mode = [|Read|Write|];
typename Mode = [|Create|Append|];
typename FileDescr = Int;
typename INode = (loc:Option(Int),refc:Int);
sig fopen : (Mode, String) {Fopen:(Mode, String) -> FileDescr |_}-> FileDescr
fun fopen(mode, filename) { do Fopen(mode, filename) }
typename INodeTable = [(INode, File.T)];
typename FileTable = [(Mode, INode)];
typename
sig fclose : (FileDescr) {Fclose:(FileDescr) -> () |_}-> ()
fun fclose(fd) { do Fclose(fd) }
# sig gets : (FileDescr) {Gets:(FileDescr) -> String |_}-> String
# fun gets(fd) { do Gets(fd) }
typename File = Queue.T(String);
# sig fopen : (Mode, String) {Fopen:(Mode, String) -> FileDescr |_}-> FileDescr
# fun fopen(mode, filename) { do Fopen(mode, filename) }
sig emptyFile : File
var emptyFile = Queue.empty;
# sig fclose : (FileDescr) {Fclose:(FileDescr) -> () |_}-> ()
# fun fclose(fd) { do Fclose(fd) }
sig writeFile : (String, File) -> File
fun writeFile(s, file) { Queue.enqueue(s, file) }
# typename File = Queue.T(String);
sig readFile : (File) ~> (String, File)
fun readFile(file) {
switch (Queue.dequeue(file)) {
case (None, file) -> (eof, file)
case (Some(s), file) -> (s, file)
}
}
# sig emptyFile : File
# var emptyFile = Queue.empty;
typename FileTable = [(FileDescr, File)];
typename FileStore = [(String, FileDescr)];
typename FileSystem = (next:Int,ft:FileTable,fs:FileStore);
# sig writeFile : (String, File) -> File
# fun writeFile(s, file) { Queue.enqueue(s, file) }
sig defaultFileSystem : () -> FileSystem
fun defaultFileSystem() {
var defaultTable = [ (stdin , emptyFile)
, (stdout, emptyFile)
, (stderr, emptyFile) ];
# sig readFile : (File) ~> (String, File)
# fun readFile(file) {
# switch (Queue.dequeue(file)) {
# case (None, file) -> (eof, file)
# case (Some(s), file) -> (s, file)
# }
# }
var defaultStore = [ ("stdin" , stdin)
, ("stdout", stdout)
, ("stderr", stderr) ];
# typename FileTable = [(FileDescr, File)];
# typename FileStore = [(String, FileDescr)];
# typename FileSystem = (next:Int,ft:FileTable,fs:FileStore);
(next=3,ft=defaultTable,fs=defaultStore)
}
# sig defaultFileSystem : () -> FileSystem
# fun defaultFileSystem() {
# var defaultTable = [ (stdin , emptyFile)
# , (stdout, emptyFile)
# , (stderr, emptyFile) ];
sig lookupFile : (FileDescr, FileSystem) ~> File
fun lookupFile(fd, fsys) {
switch (lookup(fd, fsys.ft)) {
case Nothing -> error("err: No such file(" ^^ intToString(fd) ^^ ")")
case Just(file) -> file
}
}
# var defaultStore = [ ("stdin" , stdin)
# , ("stdout", stdout)
# , ("stderr", stderr) ];
sig replaceFile : (FileDescr, File, FileSystem) ~> FileSystem
fun replaceFile(fd, file, fsys) {
var ft = modify(fd, file, fsys.ft);
(fsys with ft = ft) # TODO handle nonexistent file.
}
# (next=3,ft=defaultTable,fs=defaultStore)
# }
sig createFile : (String, FileSystem) -> (FileDescr, FileSystem)
fun createFile(filename, fsys) {
var fd = fsys.next;
(fd, (next = fd + 1, fs = (filename, fd) :: fsys.fs, ft = (fd, emptyFile) :: fsys.ft))
}
# sig lookupFile : (FileDescr, FileSystem) ~> File
# fun lookupFile(fd, fsys) {
# switch (lookup(fd, fsys.ft)) {
# case Nothing -> error("err: No such file(" ^^ intToString(fd) ^^ ")")
# case Just(file) -> file
# }
# }
sig openFile : (Mode, String, FileSystem) ~> (FileDescr, FileSystem)
fun openFile(mode, filename, fsys) {
var (fd, fsys') = switch (lookup(filename, fsys.fs)) {
case Nothing -> createFile(filename, fsys)
case Just(fd) -> (fd, fsys)
};
switch (mode) {
case Create -> error("erase")
case Append -> (fd, fsys')
}
}
# sig replaceFile : (FileDescr, File, FileSystem) ~> FileSystem
# fun replaceFile(fd, file, fsys) {
# var ft = modify(fd, file, fsys.ft);
# (fsys with ft = ft) # TODO handle nonexistent file.
# }
sig closeFile : (File) ~> File
fun closeFile((=front,=rear)) {
(front=front ++ reverse(rear), rear=[])
}
# sig createFile : (String, FileSystem) -> (FileDescr, FileSystem)
# fun createFile(filename, fsys) {
# var fd = fsys.next;
# (fd, (next = fd + 1, fs = (filename, fd) :: fsys.fs, ft = (fd, emptyFile) :: fsys.ft))
# }
sig allowState : (() {Get-,Put- |e}~> a) -> () {Get:s,Put:(s) -> () |e}~> a
fun allowState(f) { (f : (() {Get:s,Put:(s) -> () |e}~> a) <- (() {Get-,Put- |e}~> a)) }
# sig openFile : (Mode, String, FileSystem) ~> (FileDescr, FileSystem)
# fun openFile(mode, filename, fsys) {
# var (fd, fsys') = switch (lookup(filename, fsys.fs)) {
# case Nothing -> createFile(filename, fsys)
# case Just(fd) -> (fd, fsys)
# };
# switch (mode) {
# case Create -> error("erase")
# case Append -> (fd, fsys')
# }
# }
sig fileIO : (Comp(a, {Get-,Put-,Gets:(FileDescr) -> String,Puts:(FileDescr,String) -> (),Fclose:(FileDescr) -> (),Fopen:(Mode,String) -> FileDescr |e})) {Get:() {}-> FileSystem,Put:(FileSystem) -> (),Gets{_},Puts{_},Fclose{_},Fopen{_} |e}~> a
fun fileIO(m) {
handle(allowState(m)()) {
case Gets(fd, resume) ->
var fsys = get();
var (ch, file) = readFile(lookupFile(fd, fsys));
put(replaceFile(fd, file, fsys)); resume(ch)
case Puts(fd, ch, resume) ->
var fsys = get();
var fsys' = replaceFile(fd, writeFile(ch, lookupFile(fd, fsys)), fsys);
put(fsys'); resume(())
case Fopen(mode, filename, resume) ->
var fsys = get();
var (fd, fsys') = openFile(mode, filename, fsys);
put(fsys'); resume(fd)
case Fclose(fd, resume) ->
var fsys = get();
var fsys' = replaceFile(fd, closeFile(lookupFile(fd, fsys)), fsys);
put(fsys'); resume(())
}
}
# sig closeFile : (File) ~> File
# fun closeFile((=front,=rear)) {
# (front=front ++ reverse(rear), rear=[])
# }
sig redirect : (Comp(a, {Puts:(FileDescr,String) -> () |e}), FileDescr) {Puts:(FileDescr,String) -> () |e}~> a
fun redirect(m, fd) {
handle(m()) {
case Puts(_,s,resume) -> resume(puts(fd, s))
}
}
# sig allowState : (() {Get-,Put- |e}~> a) -> () {Get:s,Put:(s) -> () |e}~> a
# fun allowState(f) { (f : (() {Get:s,Put:(s) -> () |e}~> a) <- (() {Get-,Put- |e}~> a)) }
# sig fileIO : (Comp(a, {Get-,Put-,Gets:(FileDescr) -> String,Puts:(FileDescr,String) -> (),Fclose:(FileDescr) -> (),Fopen:(Mode,String) -> FileDescr |e})) {Get:() {}-> FileSystem,Put:(FileSystem) -> (),Gets{_},Puts{_},Fclose{_},Fopen{_} |e}~> a
# fun fileIO(m) {
# handle(allowState(m)()) {
# case Gets(fd, resume) ->
# var fsys = get();
# var (ch, file) = readFile(lookupFile(fd, fsys));
# put(replaceFile(fd, file, fsys)); resume(ch)
# case Puts(fd, ch, resume) ->
# var fsys = get();
# var fsys' = replaceFile(fd, writeFile(ch, lookupFile(fd, fsys)), fsys);
# put(fsys'); resume(())
# case Fopen(mode, filename, resume) ->
# var fsys = get();
# var (fd, fsys') = openFile(mode, filename, fsys);
# put(fsys'); resume(fd)
# case Fclose(fd, resume) ->
# var fsys = get();
# var fsys' = replaceFile(fd, closeFile(lookupFile(fd, fsys)), fsys);
# put(fsys'); resume(())
# }
# }
# sig redirect : (Comp(a, {Puts:(FileDescr,String) -> () |e}), FileDescr) {Puts:(FileDescr,String) -> () |e}~> a
# fun redirect(m, fd) {
# handle(m()) {
# case Puts(_,s,resume) -> resume(puts(fd, s))
# }
# }
##
## Processes
@@ -331,70 +355,70 @@ fun whoami() { getenv("USER") }
##
# Tags puts with the name of the current user.
sig provenance : (Comp(a, {Getenv:(String) -> String,Puts:(FileDescr,String) -> () |e})) {Getenv:(String) -> String,Puts:(FileDescr,String) -> () |e}~> a
fun provenance(m) {
handle(m()) {
case Puts(fd, s, resume) ->
var user = whoami();
resume(do Puts(fd, user ^^ "> " ^^ s))
}
}
# sig provenance : (Comp(a, {Getenv:(String) -> String,Puts:(FileDescr,String) -> () |e})) {Getenv:(String) -> String,Puts:(FileDescr,String) -> () |e}~> a
# fun provenance(m) {
# handle(m()) {
# case Puts(fd, s, resume) ->
# var user = whoami();
# resume(do Puts(fd, user ^^ "> " ^^ s))
# }
# }
# An example of everything plugged together: a time-shared 'Hello World'.
sig example : () {Fork:Bool,Getenv:(String) -> String,Su:(User) -> (),Puts:(FileDescr,String) -> (),Yield:() |_}~> ()
fun example() {
var pid = fork();
var () = {
if (pid) redirect(fun(){puts(stdout, "dummy")}, stderr)
else if (fork()) su(Alice)
else su(Bob)
};
var user = whoami();
puts(stdout, "Hello World!");
var uid = getenv("UID");
echo("My UID is " ^^ uid);
(if (amiroot()) { yield(); echo(user ^^ " is running as root.") } else ());
echo("My home dir is /home/" ^^ user)
}
# # An example of everything plugged together: a time-shared 'Hello World'.
# sig example : () {Fork:Bool,Getenv:(String) -> String,Su:(User) -> (),Puts:(FileDescr,String) -> (),Yield:() |_}~> ()
# fun example() {
# var pid = fork();
# var () = {
# if (pid) redirect(fun(){puts(stdout, "dummy")}, stderr)
# else if (fork()) su(Alice)
# else su(Bob)
# };
# var user = whoami();
# puts(stdout, "Hello World!");
# var uid = getenv("UID");
# echo("My UID is " ^^ uid);
# (if (amiroot()) { yield(); echo(user ^^ " is running as root.") } else ());
# echo("My home dir is /home/" ^^ user)
# }
# Wiring of handlers.
sig init : () {Fork{_},Getenv{_},Su{_},Puts{_},Yield{_} |_}~> [String]
fun init() {
basicIO(fun() {
schedule(fun() {
usermgr(Root, envs, fun() {
provenance(example)
})
})
})
}
# # Wiring of handlers.
# sig init : () {Fork{_},Getenv{_},Su{_},Puts{_},Yield{_} |_}~> [String]
# fun init() {
# basicIO(fun() {
# schedule(fun() {
# usermgr(Root, envs, fun() {
# provenance(example)
# })
# })
# })
# }
sig example' : () {Fork:Bool,Fclose:(FileDescr) -> (),Fopen:(Mode,String) -> FileDescr,Getenv:(String) -> String,Su:(User) -> (),Puts:(FileDescr,String) -> (),Yield:() |_}~> ()
fun example'() {
var pid = fork();
var () = {
if (pid) redirect(fun(){puts(stdout, "dummy")}, stderr)
else if (fork()) su(Alice)
else su(Bob)
};
var user = whoami();
var fd = fopen(Append, user ^^ ".txt");
puts(fd, "Hello World!");
var uid = getenv("UID");
echo("My UID is " ^^ uid);
(if (amiroot()) { yield(); echo(user ^^ " is running as root.") } else ());
echo("My home dir is /home/" ^^ user);
fclose(fd)
}
# sig example' : () {Fork:Bool,Fclose:(FileDescr) -> (),Fopen:(Mode,String) -> FileDescr,Getenv:(String) -> String,Su:(User) -> (),Puts:(FileDescr,String) -> (),Yield:() |_}~> ()
# fun example'() {
# var pid = fork();
# var () = {
# if (pid) redirect(fun(){puts(stdout, "dummy")}, stderr)
# else if (fork()) su(Alice)
# else su(Bob)
# };
# var user = whoami();
# var fd = fopen(Append, user ^^ ".txt");
# puts(fd, "Hello World!");
# var uid = getenv("UID");
# echo("My UID is " ^^ uid);
# (if (amiroot()) { yield(); echo(user ^^ " is running as root.") } else ());
# echo("My home dir is /home/" ^^ user);
# fclose(fd)
# }
sig init' : (FileSystem) {Fclose{_},Fopen{_},Fork{_},Get{_},Getenv{_},Gets{_},Put{_},Puts{_},Su{_},Yield{_}|_}~> ((), FileSystem)
fun init'(fsys) {
runState(fsys, fun() {
fileIO(fun() {
schedule(fun() {
usermgr(Root, envs, example')
})
})
})
}
# sig init' : (FileSystem) {Fclose{_},Fopen{_},Fork{_},Get{_},Getenv{_},Gets{_},Put{_},Puts{_},Su{_},Yield{_}|_}~> ((), FileSystem)
# fun init'(fsys) {
# runState(fsys, fun() {
# fileIO(fun() {
# schedule(fun() {
# usermgr(Root, envs, example')
# })
# })
# })
# }

697
code/unix2.links Normal file
View File

@@ -0,0 +1,697 @@
# Tiny UNIX revision 2.
typename Option(a) = [|None|Some:a|];
sig fail : () {Fail:Zero |_}-> a
fun fail() { switch (do Fail) {} }
sig optionalise : (Comp(a, {Fail:Zero |e})) {Fail{_} |e}~> Option(a)
fun optionalise(m) {
handle(m()) {
case Return(x) -> Some(x)
case Fail(_) -> None
}
}
sig withDefault : (a, Comp(a, {Fail:Zero |e})) {Fail{_} |e}~> a
fun withDefault(x', m) {
handle(m()) {
case Return(x) -> x
case Fail(_) -> x'
}
}
sig lookup : (a, [(a, b)]) {Fail:Zero |_}~> b
fun lookup(k, kvs) {
switch (kvs) {
case [] -> fail()
case (k', v) :: kvs' ->
if (k == k') v
else lookup(k, kvs')
}
}
sig modify : (a, b, [(a, b)]) ~> [(a, b)]
fun modify(k, v, kvs) {
switch (kvs) {
case [] -> []
case (k', v') :: kvs' ->
if (k == k') (k, v) :: kvs'
else (k', v') :: modify(k, v, kvs')
}
}
sig remove : (a, [(a, b)]) ~> [(a, b)]
fun remove(k, kvs) {
switch (kvs) {
case [] -> []
case (k', v') :: kvs' ->
if (k == k') kvs'
else (k', v') :: remove(k, kvs')
}
}
sig has : (a, [(a, b)]) ~> Bool
fun has(k, kvs) {
switch (kvs) {
case [] -> false
case (k', _) :: kvs' ->
k == k' || has(k, kvs')
}
}
##
## Basic i/o
##
typename File = String;
typename FileDescr = Int;
sig stdout : FileDescr
var stdout = 1;
sig basicIO : (Comp(a, {Write:(FileDescr,String) -> () |e})) {Write{_} |e}~> (a, File)
fun basicIO(m) {
handle(m()) {
case Return(res) -> (res, "")
case Write(_, s, resume) ->
var (res, file) = resume(());
(res, s ^^ file)
}
}
sig echo : (String) {Write:(FileDescr,String) -> () |_}~> ()
fun echo(cs) { do Write(stdout,cs) }
fun example0() {
basicIO(fun() {
echo("Hello"); echo("World")
})
}
##
## Exceptions: non-local exits
##
sig exit : (Int) {Exit:(Int) -> Zero |_}-> a
fun exit(n) { switch(do Exit(n)) {} }
sig status : (Comp(a, {Exit:(Int) -> Zero |e})) {Exit{_} |e}~> Int
fun status(m) {
handle(m()) {
case Return(_) -> 0
case Exit(n, _) -> n
}
}
fun example1() {
basicIO(fun() {
status(fun() {
echo("dead"); exit(1); echo("code")
})
})
}
##
## Dynamic binding: user-specific environments.
##
typename User = [|Alice|Bob|Root|];
sig whoami : () {Ask:String |_}-> String
fun whoami() { do Ask }
sig env : (User, Comp(a, {Ask:String |e})) {Ask{_} |e}~> a
fun env(user, m) {
handle(m()) {
case Return(x) -> x
case Ask(resume) ->
switch (user) {
case Alice -> resume("alice")
case Bob -> resume("bob")
case Root -> resume("root")
}
}
}
fun example2() {
env(Root, whoami)
}
###
### Session management.
###
sig su : (User) {Su:(User) -> () |_}-> ()
fun su(user) { do Su(user) }
sig sessionmgr : (User, Comp(a, {Ask:String,Su:(User) -> () |e})) {Ask{_},Su{_} |e}~> a
fun sessionmgr(user, m) {
env(user, fun() {
handle(m()) {
case Return(x) -> x
case Su(user', resume) ->
env(user', fun() { resume(()) })
}
})
}
fun example3() {
basicIO(fun() {
sessionmgr(Root, fun() {
status(fun() {
su(Alice); echo(whoami()); echo(" ");
su(Bob); echo(whoami()); echo(" ");
su(Root); echo(whoami())
})
})
})
}
##
## Nondeterminism: time sharing.
##
sig fork : () {Fork:Bool |_}-> Bool
fun fork() { do Fork }
sig nondet : (Comp(a, {Fork:Bool |e})) {Fork{_} |e}~> [a]
fun nondet(m) {
handle(m()) {
case Return(res) -> [res]
case Fork(resume) -> resume(true) ++ resume(false)
}
}
sig interrupt : () {Interrupt:() |_}-> ()
fun interrupt() { do Interrupt }
typename Pstate(a,e::Eff) = forall q::Presence.
[|Done:a
|Paused:() {Interrupt{q} |e}~> Pstate(a, { |e})|];
sig slice : (Comp(a, {Interrupt:() |e})) {Interrupt{_} |e}~> Pstate(a, { |e})
fun slice(m) {
handle(m()) {
case Return(res) -> Done(res)
case Interrupt(resume) -> Paused(fun() { resume(()) })
}
}
sig schedule : ([Pstate(a, { Fork:Bool |e})]) {Fork{_},Interrupt{_} |e}~> [a]
fun schedule(ps) {
# sig run : (Pstate (a, { Fork:() {}-> Bool|e })) {Fork{_},Interrupt{_} |e}~> [a]
# fun run(p) {
# switch(p) {
# case Done(res) -> [res]
# case Paused(resume) -> runNext(nondet(resume))
# }
# }
# concatMap(run, ps)
fun schedule(ps, done) {
switch (ps) {
case [] -> done
case Done(res) :: ps' ->
schedule(ps', res :: done)
case Paused(resume) :: ps' ->
schedule(ps' ++ nondet(resume), done)
}
}
schedule(ps, [])
}
sig timeshare : (Comp(a, {Fork:Bool,Interrupt:() |e})) {Fork{_},Interrupt{_} |e}~> [a]
fun timeshare(m) {
var p = Paused(fun() { slice(m) });
schedule([p])
}
fun example4() {
basicIO(fun() {
timeshare(fun() {
sessionmgr(Root, fun() {
status(fun() {
var parent = fork();
(if (parent) su(Alice) else su(Bob));
echo(whoami() ^^ "> Hello ");
interrupt();
echo(whoami() ^^ "> Bye ");
interrupt();
if (parent) exit(0)
else {
var parent = fork();
interrupt();
(if (parent) su(Root)
else {
echo(whoami() ^^ "> oops ");
exit(1)
});
echo(whoami() ^^ "> !! ")
}
})
})
})
})
}
fun forktest(n) {
fun loop(i, n) {
if (i >= n) (-1)
else {
var x = fork();
println("< x = " ^^ (if (x) "true" else "false") ^^ ", i = " ^^ intToString(i));
ignore(loop(i+1,n));
println("> x = " ^^ (if (x) "true" else "false") ^^ ", i = " ^^ intToString(i));
exit(i)
}
}
loop(0, n)
}
fun test(i) {
if (i == 2) ()
else {
println("< i = " ^^ intToString(i));
var x = fork();
test(i+1);
println("> i = " ^^ intToString(i))
}
}
fun ritchie() {
echo("UNIX is basically ");
echo("a simple operating system, ");
echo("but ");
echo("you have to be a genius to understand the simplicity.\n")
}
fun hamlet() {
echo("To be, or not to be,\n");
echo("that is the question:\n");
echo("Whether 'tis nobler in the mind to suffer\n")
}
fun example5() {
basicIO(fun() {
nondet(fun() {
sessionmgr(Root, fun() {
status(fun() {
if (fork()) {
su(Alice);
ritchie()
} else {
su(Bob);
hamlet()
}
})
})
})
})
}
fun interruptWrite(m) {
handle(m()) {
case Return(res) -> res
case Write(fd, cs, resume) ->
interrupt(); resume(do Write(fd, cs))
}
}
fun example5'() {
basicIO(fun() {
timeshare(fun() {
interruptWrite(fun() {
sessionmgr(Root, fun() {
status(fun() {
if (fork()) {
su(Alice);
ritchie()
} else {
su(Bob);
hamlet()
}
})
})
})
})
})
}
##
## Generic state handling
##
sig get : () {Get:s |_}-> s
fun get() { do Get }
sig put : (s) {Put:(s) -> () |_}-> ()
fun put(st) { do Put(st) }
sig runState : (s, Comp(a, {Get:() -> s,Put:(s) -> () |e})) {Get{_},Put{_} |e}~> (a, s)
fun runState(st0, m) {
var f = handle(m()) {
case Return(x) -> fun(st) { (x, st) }
case Get(resume) -> fun(st) { resume(st)(st) }
case Put(st,resume) -> fun(_) { resume(())(st) }
};
f(st0)
}
fun example6() {
runState(0, fun() {
var x = 3;
put(x);
assert(x == get(), "Put;Get");
var y = get();
var z = get();
assert(y == z, "Get;Get");
put(x+1);
put(x+2);
assert(get() == x + 2, "Put;Put")
})
}
##
## State: file i/o
##
typename FilePtr = Option(FileDescr);
typename INode = (loc:Int,lno:Int);
typename IList = [(Int, INode)]; # INode index -> INode
typename Directory = [(String, Int)]; # Filename -> INode index
typename DataRegion = [(Int, File)]; # Loc -> File
typename FileSystem = (dir:Directory,dregion:DataRegion,inodes:IList
,lnext:Int ,inext:Int );
sig fsys0 : FileSystem
var fsys0 = (dir = [("stdout", 0)], inodes = [(0, (loc=0, lno=1))], dregion = [(0, "")], lnext = 1, inext = 1);
sig fopen : (String, FileSystem) {Fail:Zero |_}~> (Int, FileSystem)
fun fopen(fname, fsys) { (lookup(fname, fsys.dir), fsys) }
sig ftruncate : (Int, FileSystem) {Fail:Zero |_}~> FileSystem
fun ftruncate(ino, fsys) {
var inode = lookup(ino, fsys.inodes);
var dregion = modify(inode.loc, "", fsys.dregion);
(fsys with =dregion)
}
sig fcreate : (String, FileSystem) {Fail:Zero |_}~> (Int, FileSystem)
fun fcreate(fname, fsys) {
if (has(fname, fsys.dir)) {
var (ino, fsys) = fopen(fname, fsys);
(ino, ftruncate(ino, fsys))
} else {
var loc = fsys.lnext;
var dregion = (loc, "") :: fsys.dregion;
var ino = fsys.inext;
var inode = (loc=loc,lno=1);
var inodes = (ino, inode) :: fsys.inodes;
var dir = (fname, ino) :: fsys.dir;
(ino, (=dir, =dregion, =inodes, lnext=loc+1, inext=ino+1))
}
}
sig ftruncate : (Int, FileSystem) {Fail:Zero |_}~> FileSystem
fun ftruncate(ino, fsys) {
var inode = lookup(ino, fsys.inodes);
var dregion = modify(inode.loc, "", fsys.dregion);
(fsys with =dregion)
}
sig fopen : (String, FileSystem) {Fail:Zero |_}~> Int
fun fopen(fname, fsys) { lookup(fname, fsys.dir) }
sig fclose : (Int, FileSystem) ~> FileSystem
fun fclose(_, fsys) { fsys }
sig fwrite : (Int, String, FileSystem) {Fail:Zero |_}~> FileSystem
fun fwrite(ino, cs, fsys) {
var inode = lookup(ino, fsys.inodes);
var file = lookup(inode.loc, fsys.dregion);
var file' = file ^^ cs;
(fsys with dregion = modify(inode.loc, file', fsys.dregion))
}
sig fread : (Int, FileSystem) {Fail:Zero |_}~> String
fun fread(ino, fsys) {
var inode = lookup(ino, fsys.inodes);
lookup(inode.loc, fsys.dregion)
}
sig flink : (String, String, FileSystem) {Fail:Zero |_}~> FileSystem
fun flink(src, dest, fsys) {
var ino = lookup(dest, fsys.dir);
var inode = lookup(ino, fsys.inodes);
var inode' = (inode with lno = inode.lno + 1);
var inodes = modify(ino, inode', fsys.inodes);
var dir = (src, ino) :: fsys.dir;
(fsys with inodes = inodes, dir = dir)
}
sig funlink : (String, FileSystem) {Fail:Zero |_}~> FileSystem
fun funlink(fname, fsys) {
var i = lookup(fname, fsys.dir);
var dir = remove(fname, fsys.dir);
var inode = lookup(i, fsys.inodes);
var inode' = (inode with lno = inode.lno - 1);
if (inode'.lno > 0) {
var inodes = modify(i, inode', fsys.inodes);
(fsys with inodes = inodes, dir = dir)
} else {
var dregion = remove(inode'.loc, fsys.dregion);
var inodes = remove(i, fsys.inodes);
(fsys with inodes = inodes, dir = dir, dregion = dregion)
}
}
sig create : (String) {Create:(String) -> FileDescr |_}-> FileDescr
fun create(fname) { do Create(fname) }
sig truncate : (FileDescr) {Truncate:(FileDescr) -> () |_}-> ()
fun truncate(fd) { do Truncate(fd) }
sig open' : (String) {Open:(String) -> Option(FileDescr) |_}-> Option(FileDescr)
fun open'(fname) { do Open(fname) }
sig close : (FileDescr) {Close:(FileDescr) -> () |_}-> ()
fun close(fd) { do Close(fd) }
sig write : (FileDescr, String) {Write:(FileDescr, String) -> () |_}-> ()
fun write(fd, cs) { do Write(fd, cs) }
sig read : (FileDescr) {Read:(FileDescr) -> Option(String) |_}-> Option(String)
fun read(fd) { do Read(fd) }
sig link : (String, String) {Link:(String, String) -> () |_}-> ()
fun link(src, dest) { do Link(src, dest) }
sig unlink : (String) {Unlink:(String) -> () |_}-> ()
fun unlink(fname) { do Unlink(fname) }
sig injectState : (() { |e}~> a) -> () {Get:s,Put:(s) -> () |e}~> a
fun injectState(f) { (f : (() {Get:s,Put:(s) -> () |e}~> a) <- (() { |e}~> a)) }
sig fileIO : (Comp(a, { #Close:(FileDescr) -> ()
Create:(String) -> FileDescr
, Read:(FileDescr) -> Option(String)
, Open:(String) -> Option(FileDescr)
, Truncate:(FileDescr) -> ()
, Write:(FileDescr, String) -> ()
, Fail{p}|e}))
{Create{_},Read{_},Open{_},Truncate{_},Write{_},Get:FileSystem,Put:(FileSystem) -> (),Fail{p} |e}~> a
fun fileIO(m) {
handle(injectState(m)()) {
case Return(x) -> x
case Create(fname, resume) ->
var ino = withDefault(-1, fun() {
var (ino, fsys) = fcreate(fname, get());
put(fsys); ino
}); resume(ino)
case Read(ino, resume) ->
var contents = optionalise(fun() { fread(ino, get()) });
resume(contents)
case Open(fname, resume) ->
var ino = optionalise(fun() { fopen(fname, get()) });
resume(ino)
case Truncate(ino, resume) ->
withDefault((), fun() {
var fsys = ftruncate(ino, get());
put(fsys)
}); resume(())
case Write(ino, cs, resume) ->
withDefault((), fun() {
var fsys = fwrite(ino, cs, get());
put(fsys)
}); resume(())
}
}
fun init(fsys, main) {
runState(fsys, fun() {
fileIO(fun() {
timeshare(fun() {
sessionmgr(Root, fun() {
status(fun() {
if(fork()) exit(0) else main()
})
})
})
})
})
}
###
### Stream redirection
###
sig >> : (Comp(a, { Create: (String) -> FileDescr
, Write:(FileDescr, String) -> () |e}), String)
{ Create:(String) -> FileDescr
, Write:(FileDescr, String) -> () |e}~> a
op f >> fname {
var fd = create(fname);
handle(f()) {
case Return(x) -> x
case Write(_, cs, resume) ->
resume(write(fd, cs))
}
}
sig >>> : (Comp(a, { Create: (String) -> FileDescr
, Open: (String) -> Option (FileDescr)
, Write:(FileDescr, String) -> () |e}), String)
{ Create:(String) -> FileDescr
, Open:(String) -> Option (FileDescr)
, Write:(FileDescr, String) -> () |e}~> ()
op f >>> fname {
var fd = switch (open'(fname)) {
case None -> create(fname)
case Some(fd) -> fd
};
handle(f()) {
case Return(_) -> ()
case Write(_, cs, resume) ->
resume(write(fd, cs))
}
}
fun example7() {
if (fork()) {
su(Alice);
ritchie >> "ritchie.txt"
} else {
su(Bob);
hamlet >> "hamlet"
}
}
###
### TCP threeway handshake
###
sig strsplit : (Char, String) ~> [String]
fun strsplit(c, str) {
fun loop(c, str, i, j) {
if (i >= strlen(str)) [strsub(str, j, i - j)]
else if (charAt(str, i) == c)
strsub(str, j, i - j) :: loop(c, str, i+1, i+1)
else
loop(c,str, i+1, j)
}
loop(c, str, 0, 0)
}
sig read1 : (FileDescr) {Read:(FileDescr) -> Option(String) |e}-> Option(String)
fun read1(fd) {
switch (read(fd)) {
case Some("") -> None
case x -> x
}
}
sig truncread : (FileDescr) {Read:(FileDescr) -> Option(String),Truncate:(FileDescr) -> () |_}-> Option(String)
fun truncread(fd) {
var cs = read1(fd);
truncate(fd); cs
}
sig synced : (Comp(Option(a), {Interrupt:() |e})) {Interrupt:() |e}~> a
fun synced(f) {
switch (f()) {
case None -> interrupt(); synced(f)
case Some(x) -> x
}
}
sig fail : () {Fail:Zero |_}-> a
fun fail() { switch(do Fail) {} }
fun tcpclient(seq, inp, out) {
write(out, "SYN " ^^ intToString(seq));
var resp = synced(fun() { truncread(inp) });
var [syn, ack] = strsplit(';', resp);
var seqn = stringToInt(strsub(syn, 4, strlen(syn) - 4));
var ackn = stringToInt(strsub(ack, 4, strlen(ack) - 4));
if (ackn <> seq + 1) fail()
else write(out, "ACK " ^^ intToString(seqn + 1))
}
fun tcpserver(seq, inp, out) {
var req = synced(fun() { truncread(inp) });
var reqn = stringToInt(strsub(req, 4, strlen(req) - 4));
var resp = "SYN " ^^ intToString(seq) ^^ ";ACK " ^^ intToString(reqn + 1);
write(out, resp);
var resp' = synced(fun() { truncread(inp) });
var ackn = stringToInt(strsub(resp', 4, strlen(resp') - 4));
if (ackn <> seq + 1) fail()
else ()
}
fun performTCP(tcpf, seq, inp, out) {
var fd = create(whoami() ^^ ".log");
handle(tcpf(seq, inp, out)) {
case Return(_) -> write(fd, "Handshake completed.")
case Fail(_) -> write(fd, "Handshake failed.")
}
}
fun tcphandshake() {
var (cfd, sfd) = (create("client.sock"), create("server.sock"));
if (fork()) {
su(Alice);
performTCP(tcpclient, 42, cfd, sfd)
} else {
su(Bob);
performTCP(tcpserver, 84, sfd, cfd)
}
}
fun tcphandshakeFail() {
var (cfd, sfd) = (create("client.sock"), create("server.sock"));
if (fork()) {
su(Alice);
handle(performTCP(tcpclient, 42, cfd, sfd)) {
case Write(fd, cs, resume) ->
resume(if (strsub(cs, 0, 3) == "ACK") write(fd, "ACK 0")
else write(fd, cs))
}
} else {
su(Bob);
performTCP(tcpserver, 84, sfd, cfd)
}
}
#
# Grep
#
#sig grep : (String) {Await:Char,Yield:(Char) -> () |_}~> ()
fun grep(str) {
var cs = explode(str);
fun match(c,cs) {
switch (cs) {
case c' :: cs' ->
if (c == '\n') fail()
if (c == c')
}
}
}

View File

@@ -1,3 +1,41 @@
%%
%% Defined-as equality
%%
\newcommand{\defas}[0]{\mathrel{\overset{\makebox[0pt]{\mbox{\normalfont\tiny\text{def}}}}{=}}}
\newcommand{\defnas}[0]{\mathrel{:=}}
\newcommand{\simdefas}[0]{\mathrel{\overset{\makebox[0pt]{\mbox{\normalfont\tiny\text{def}}}}{\simeq}}}
\newcommand{\adef}[0]{\mathrel{\overset{\makebox[0pt]{\mbox{\normalfont\tiny{\text{$\alpha$-def}}}}}{\simeq}}}
%%
%% Some useful maths abbreviations
%%
\newcommand{\C}{\ensuremath{\mathbb{C}}}
\newcommand{\N}{\ensuremath{\mathbb{N}}}
\newcommand{\R}{\ensuremath{\mathbb{R}}}
\newcommand{\Z}{\ensuremath{\mathbb{Z}}}
\newcommand{\B}{\ensuremath{\mathbb{B}}}
\newcommand{\BB}[1]{\ensuremath{\mathbf{#1}}}
\newcommand{\CC}{\keyw{ctrl}}
% \newcommand{\Delim}[1]{\ensuremath{\langle\!\!\mkern-1.5mu\langle#1\rangle\!\!\mkern-1.5mu\rangle}}
\newcommand{\Delim}[1]{\ensuremath{\keyw{del}.#1}}
\newcommand{\sembr}[1]{\ensuremath{\llbracket #1 \rrbracket}}
\newcommand{\BigO}{\ensuremath{\mathcal{O}}}
\newcommand{\SC}{\ensuremath{\mathsf{S}}}
\newcommand{\ST}{\ensuremath{\mathsf{T}}}
\newcommand{\ar}{\ensuremath{\mathsf{ar}}}
\newcommand{\Tm}{\ensuremath{\mathsf{Tm}}}
\newcommand{\Ty}{\ensuremath{\mathsf{Ty}}}
%%
%% Partiality
%%
\newcommand{\pto}[0]{\ensuremath{\rightharpoonup}}
%%
%% Operation arrows
%%
\newcommand{\opto}[0]{\ensuremath{\twoheadrightarrow}}
%%
%% Calculi names.
%%
@@ -10,6 +48,10 @@
\newcommand{\HSCalc}{\ensuremath{\lambda_{\mathsf{h^\delta}}}\xspace}
\newcommand{\EffCalc}{\ensuremath{\lambda_{\mathsf{eff}}}\xspace}
\newcommand{\UCalc}{\ensuremath{\lambda_{\mathsf{u}}}\xspace}
\newcommand{\param}{\ensuremath{\ddagger}}
\newcommand{\HPCalc}{\ensuremath{\lambda_{\mathsf{h^\param}}}\xspace}
\newcommand{\HPCF}{\ensuremath{\lambda^\rightarrow_{\mathsf{h}}}\xspace}
\newcommand{\BPCF}{\ensuremath{\lambda^\rightarrow_{\mathsf{b}}}\xspace}
%%
%% Calculi terms and types type-setting.
@@ -19,6 +61,7 @@
\newcommand{\dec}[1]{\mathsf{#1}}
\newcommand{\keyw}[1]{\mathbf{#1}}
\newcommand{\Handle}{\keyw{handle}}
\newcommand{\ParamHandle}{\Handle^\param}
\newcommand{\ShallowHandle}{\ensuremath{\keyw{handle}^\dagger}}
\newcommand{\With}{\keyw{with}}
\newcommand{\Let}{\keyw{let}}
@@ -33,10 +76,16 @@
\newcommand{\Else}{\keyw{else}}
\newcommand{\Absurd}{\keyw{absurd}}
\newcommand{\Record}[1]{\ensuremath{\langle #1 \rangle}}
\newcommand{\Op}[1]{\ensuremath{\langle\!\!\langle #1 \rangle\!\!\rangle}}
%\newcommand{\Op}[1]{\ensuremath{\{#1\}}}
\newcommand{\OpCase}[3]{\Op{#1~#2 \opto #3}}
\newcommand{\ExnCase}[2]{\Op{#1~#2}}
\newcommand{\Unit}{\Record{}}
\newcommand{\Inl}{\keyw{inl}}
\newcommand{\Inr}{\keyw{inr}}
\newcommand{\Thunk}{\lambda \Unit.}
\newcommand{\PCFRef}{\dec{Ref}}
\newcommand{\refv}{\keyw{ref}}
\newcommand{\Pre}[1]{\mathsf{Pre}(#1)}
\newcommand{\Abs}{\mathsf{Abs}}
@@ -69,6 +118,8 @@
\newcommand{\Fail}{\dec{Fail}}
\newcommand{\Read}{\dec{Read}}
\newcommand{\Write}{\dec{Write}}
\newcommand{\Char}{\dec{Char}}
\newcommand{\String}{\dec{String}}
\newcommand{\True}{\mathsf{true}}
\newcommand{\False}{\mathsf{false}}
@@ -94,6 +145,10 @@
\newcommand{\Res}{\keyw{res}}
\newcommand{\Cong}{\mathrm{cong}}
\newcommand{\AlgTheory}{\ensuremath{\mathcal{T}}}
%% Handler projections.
\newcommand{\mret}{\mathrm{ret}}
\newcommand{\mops}{\mathrm{ops}}
@@ -102,6 +157,7 @@
\newcommand{\hops}{H^{\mops}}
%\newcommand{\hex}{H^{\mathrm{ex}}}
\newcommand{\hell}{H^{\ell}}
\newcommand{\gell}{\theta^{\ell}}
\newcommand{\depth}{\delta}
@@ -112,7 +168,7 @@
%%
%% Labels
%%
\newcommand{\slab}[1]{\textrm{#1}}
\newcommand{\slab}[1]{\ensuremath{\mathsf{#1}}}
\newcommand{\rulelabel}[2]{\ensuremath{\mathsf{#1\textrm{-}#2}}}
\newcommand{\klab}[1]{\rulelabel{K}{#1}}
\newcommand{\semlab}[1]{\rulelabel{S}{#1}}
@@ -150,6 +206,14 @@
\newcommand{\EvalCat}{\CatName{Cont}}
\newcommand{\UEvalCat}{\CatName{UCont}}
\newcommand{\HandlerCat}{\CatName{HDef}}
\newcommand{\MConfCat}{\CatName{Conf}}
\newcommand{\MEnvCat}{\CatName{Env}}
\newcommand{\MValCat}{\CatName{Mval}}
\newcommand{\MGContCat}{\CatName{GenCont}}
\newcommand{\MGFrameCat}{\CatName{GenFrame}}
\newcommand{\MPContCat}{\CatName{PureCont}}
\newcommand{\MPFrameCat}{\CatName{PureFrame}}
\newcommand{\MHCloCat}{\CatName{HClo}}
%%
%% Lindley's array stuff.
@@ -176,23 +240,6 @@
\newenvironment{smathpar}{\vspace{-3ex}\small\begin{mathpar}}{\end{mathpar}\normalsize\ignorespacesafterend}
%%
%% Defined-as equality
%%
\newcommand{\defas}[0]{\mathrel{\overset{\makebox[0pt]{\mbox{\normalfont\tiny\text{def}}}}{=}}}
\newcommand{\defnas}[0]{\mathrel{:=}}
\newcommand{\simdefas}[0]{\mathrel{\overset{\makebox[0pt]{\mbox{\normalfont\tiny\text{def}}}}{\simeq}}}
%%
%% Partiality
%%
\newcommand{\pto}[0]{\ensuremath{\rightharpoonup}}
%%
%% Operation arrows
%%
\newcommand{\opto}[0]{\ensuremath{\twoheadrightarrow}}
%%
%% Lists
%%
@@ -201,6 +248,7 @@
\newcommand{\concat}{\mathbin{+\!\!+}}
\newcommand{\revconcat}{\mathbin{\widehat{\concat}}}
\newcommand{\snoc}[2]{\ensuremath{#1 \concat [#2]}}
%%
%% CPS notation
@@ -284,8 +332,9 @@
% Canonical variables for handler components
\newcommand{\vhret}{h^{\mret}}
\newcommand{\vhops}{h^{\mops}}
\newcommand{\svhret}{\chi^{\mret}}
\newcommand{\svhops}{\chi^{\mops}}
\newcommand{\sv}{\chi}
\newcommand{\svhret}{\sv^{\mret}}
\newcommand{\svhops}{\sv^{\mops}}
% \newcommand{\dk}{\dRecord{fs,\dRecord{\vhret,\vhops}}}
\newcommand{\dk}{k}
@@ -305,12 +354,26 @@
\newcommand{\Option}{\dec{Option}}
\newcommand{\Some}{\dec{Some}}
\newcommand{\None}{\dec{None}}
\newcommand{\Toss}{\dec{Toss}}
\newcommand{\toss}{\dec{toss}}
\newcommand{\Heads}{\dec{Heads}}
\newcommand{\Tails}{\dec{Tails}}
\newcommand{\Exn}{\dec{Exn}}
\newcommand{\fail}{\dec{fail}}
\newcommand{\optionalise}{\dec{optionalise}}
\newcommand{\bind}{\ensuremath{\gg\!=}}
\newcommand{\return}{\dec{return}}
\newcommand{\return}{\dec{Return}}
\newcommand{\faild}{\dec{withDefault}}
\newcommand{\Free}{\dec{Free}}
\newcommand{\FreeState}{\dec{FreeState}}
\newcommand{\OpF}{\dec{Op}}
\newcommand{\DoF}{\dec{do}}
\newcommand{\getF}{\dec{get}}
\newcommand{\putF}{\dec{put}}
\newcommand{\fmap}{\dec{fmap}}
\newcommand{\toggle}{\dec{toggle}}
\newcommand{\incrEven}{\dec{incrEven}}
\newcommand{\even}{\dec{even}}
% Abstract machine
\newcommand{\cek}[1]{\ensuremath{\langle #1 \rangle}}
@@ -325,3 +388,464 @@
% configurations
\newcommand{\conf}{\mathcal{C}}
% effect sugar
\newcommand{\inward}[1]{\mathcal{I}\sembr{#1}}
\newcommand{\outward}[1]{\mathcal{O}\sembr{#1}}
\newcommand{\xcomp}[1]{\outward{#1}}
\newcommand{\xval}[1]{\outward{#1}}
\newcommand{\xpre}[1]{\outward{#1}}
\newcommand{\xrow}[1]{\outward{#1}}
\newcommand{\xeff}[1]{\outward{#1}}
\newcommand{\pcomp}[1]{\inward{#1}}
\newcommand{\pval}[1]{\inward{#1}}
\newcommand{\ppre}[1]{\inward{#1}}
\newcommand{\prow}[1]{\inward{#1}}
\newcommand{\peff}[1]{\inward{#1}}
\newcommand{\eamb}{\ensuremath{E_{\mathsf{amb}}}}
\newcommand{\trval}[1]{\mathcal{T}\sembr{#1}}
% UNIX example
\newcommand{\UNIX}{UNIX}
\newcommand{\OSname}[0]{Tiny UNIX}
\newcommand{\exit}{\dec{exit}}
\newcommand{\Exit}{\dec{Exit}}
\newcommand{\Status}{\dec{Status}}
\newcommand{\status}{\dec{status}}
\newcommand{\basicIO}{\dec{basicIO}}
\newcommand{\Putc}{\dec{Putc}}
\newcommand{\putc}{\dec{putc}}
\newcommand{\UFile}{\dec{File}}
\newcommand{\UFD}{\dec{FileDescr}}
\newcommand{\fwrite}{\dec{fwrite}}
\newcommand{\iter}{\dec{iter}}
\newcommand{\map}{\dec{map}}
\newcommand{\stdout}{\dec{stdout}}
\newcommand{\IO}{\dec{IO}}
\newcommand{\BIO}{\dec{BIO}}
\newcommand{\Alice}{\dec{Alice}}
\newcommand{\Bob}{\dec{Bob}}
\newcommand{\Root}{\dec{Root}}
\newcommand{\User}{\dec{User}}
\newcommand{\environment}{\dec{env}}
\newcommand{\EnvE}{\dec{Session}}
\newcommand{\Ask}{\dec{Ask}}
\newcommand{\whoami}{\dec{whoami}}
\newcommand{\Su}{\dec{Su}}
\newcommand{\su}{\dec{su}}
\newcommand{\sessionmgr}{\dec{sessionmgr}}
\newcommand{\echo}{\dec{echo}}
\newcommand{\strlit}[1]{\texttt{"#1"}}
\newcommand{\nondet}{\dec{nondet}}
\newcommand{\Fork}{\dec{Fork}}
\newcommand{\fork}{\dec{fork}}
\newcommand{\Interrupt}{\dec{Interrupt}}
\newcommand{\interrupt}{\dec{interrupt}}
\newcommand{\Pstate}{\dec{Pstate}}
\newcommand{\Done}{\dec{Done}}
\newcommand{\Suspended}{\dec{Paused}}
\newcommand{\slice}{\dec{slice}}
\newcommand{\reifyP}{\dec{reifyProcess}}
\newcommand{\timeshare}{\dec{timeshare}}
\newcommand{\runNext}{\dec{runNext}}
\newcommand{\concatMap}{\dec{concatMap}}
\newcommand{\State}{\dec{State}}
\newcommand{\runState}{\dec{runState}}
\newcommand{\Uget}{\dec{get}}
\newcommand{\Uput}{\dec{put}}
\newcommand{\nl}{\textbackslash{}n}
\newcommand{\quoteRitchie}{\dec{ritchie}}
\newcommand{\quoteHamlet}{\dec{hamlet}}
\newcommand{\Proc}{\dec{Proc}}
\newcommand{\schedule}{\dec{schedule}}
\newcommand{\fsname}{BSFS}
\newcommand{\FileSystem}{\dec{FileSystem}}
\newcommand{\Directory}{\dec{Directory}}
\newcommand{\DataRegion}{\dec{DataRegion}}
\newcommand{\INode}{\dec{INode}}
\newcommand{\IList}{\dec{IList}}
\newcommand{\fileRW}{\dec{fileRW}}
\newcommand{\fileAlloc}{\dec{fileCO}}
\newcommand{\URead}{\dec{Read}}
\newcommand{\UWrite}{\dec{Write}}
\newcommand{\UCreate}{\dec{Create}}
\newcommand{\UOpen}{\dec{Open}}
\newcommand{\fread}{\dec{fread}}
\newcommand{\fcreate}{\dec{fcreate}}
\newcommand{\Ucreate}{\dec{create}}
\newcommand{\redirect}{\texttt{>}}
\newcommand{\fopen}{\dec{fopen}}
\newcommand{\lookup}{\dec{lookup}}
\newcommand{\modify}{\dec{modify}}
\newcommand{\fileIO}{\dec{fileIO}}
\newcommand{\ULink}{\dec{Link}}
\newcommand{\UUnlink}{\dec{Unlink}}
\newcommand{\flink}{\dec{flink}}
\newcommand{\funlink}{\dec{funlink}}
\newcommand{\remove}{\dec{remove}}
\newcommand{\FileLU}{\dec{FileLU}}
\newcommand{\fileLU}{\dec{fileLU}}
\newcommand{\FileIO}{\dec{FileIO}}
\newcommand{\FileRW}{\dec{FileRW}}
\newcommand{\FileCO}{\dec{FileCO}}
\newcommand{\cat}{\dec{cat}}
\newcommand{\head}{\dec{head}}
\newcommand{\grep}{\dec{grep}}
\newcommand{\match}{\dec{match}}
\newcommand{\wc}{\dec{wc}}
\newcommand{\forever}{\dec{forever}}
\newcommand{\textnil}{\textbackslash{}0}
\newcommand{\charlit}[1]{\texttt{'#1'}}
\newcommand{\where}{\keyw{where}}
\newcommand{\intToString}{\dec{intToString}}
\newcommand{\freq}{\dec{freq}}
\newcommand{\paste}{\dec{paste}}
\newcommand{\sed}{\dec{sed}}
\newcommand{\printTable}{\dec{renderTable}}
\newcommand{\timesharee}{\dec{timeshare2}}
\newcommand{\Co}{\dec{Co}}
\newcommand{\UFork}{\dec{UFork}}
\newcommand{\ufork}{\dec{ufork}}
\newcommand{\Wait}{\dec{Wait}}
\newcommand{\scheduler}{\dec{scheduler}}
\newcommand{\Sstate}{\dec{Sstate}}
\newcommand{\Ready}{\dec{Ready}}
\newcommand{\Blocked}{\dec{Blocked}}
\newcommand{\init}{\dec{init}}
\newcommand{\Reader}{\dec{Reader}}
\newcommand{\Other}{\dec{Other}}
%%
%% Some control operators
%%
\newcommand{\Cupto}{\keyw{cupto}}
\newcommand{\Set}{\keyw{set}}
\newcommand{\newPrompt}{\keyw{newPrompt}}
\newcommand{\Callcc}{\keyw{callcc}}
\newcommand{\Callcomc}{\ensuremath{\keyw{callcomp}}}
\newcommand{\textCallcomc}{callcomp}
\newcommand{\Throw}{\keyw{throw}}
\newcommand{\Continue}{\keyw{resume}}
\newcommand{\Catch}{\keyw{catch}}
\newcommand{\Catchcont}{\keyw{catchcont}}
\newcommand{\Control}{\keyw{control}}
\newcommand{\Prompt}{\#}
\newcommand{\Controlz}{\ensuremath{\keyw{control_0}}}
\newcommand{\Spawn}{\keyw{spawn}}
\newcommand{\Promptz}{\ensuremath{\#_0}}
\newcommand{\Escape}{\keyw{escape}}
\newcommand{\shift}{\keyw{shift}}
\newcommand{\shiftz}{\ensuremath{\keyw{shift_0}}}
\newcommand{\CCpp}{\ensuremath{+\CC+}}
\newcommand{\CCpm}{\ensuremath{+\CC-}}
\newcommand{\CCmp}{\ensuremath{-\CC+}}
\newcommand{\CCmm}{\ensuremath{-\CC-}}
\def\sigh#1{%
\pmb{\left\langle\vphantom{#1}\right.}%
#1%
\pmb{\left.\vphantom{#1}\right\rangle}}
\newcommand{\llambda}{\ensuremath{\pmb{\lambda}}}
\newcommand{\reset}[1]{\pmb{\langle} #1 \pmb{\rangle}}
\newcommand{\resetz}[1]{\pmb{\langle} #1 \pmb{\rangle}_0}
\newcommand{\dollarz}[2]{\ensuremath{\reset{#2 \mid #1}}}
\newcommand{\dollarzh}[2]{\ensuremath{#1\,\$_0#2}}
\newcommand{\fcontrol}{\keyw{fcontrol}}
\newcommand{\fprompt}{\%}
\newcommand{\splitter}{\keyw{splitter}}
\newcommand{\abort}{\keyw{abort}}
\newcommand{\calldc}{\keyw{calldc}}
\newcommand{\J}{\keyw{J}}
\newcommand{\JI}{\keyw{J}\,\keyw{I}}
\newcommand{\FelleisenC}{\ensuremath{\keyw{C}}}
\newcommand{\FelleisenF}{\ensuremath{\keyw{F}}}
\newcommand{\cont}{\keyw{cont}}
\newcommand{\Cont}{\dec{Cont}}
\newcommand{\Algol}{Algol~60}
\newcommand{\qq}[1]{\ensuremath{\ulcorner #1 \urcorner}}
\newcommand{\prompttype}{\dec{Prompt}}
\newcommand{\async}{\keyw{async}}
\newcommand{\await}{\keyw{await}}
% Language macros
\newcommand{\Frank}{Frank}
\newcommand{\SML}{SML}
\newcommand{\SMLNJ}{\SML{}/NJ}
\newcommand{\OCaml}{OCaml}
%%
%% Asymptotic improvement macros
%%
\newcommand{\LLL}{\ensuremath{\mathcal L}}
\newcommand{\naive}{naïve\xspace}
\newcommand{\naively}{naïvely\xspace}
\newcommand{\Naive}{Naïve\xspace}
\newcommand{\sem}[1]{\ensuremath{\pi_{#1}}}
\newcommand{\Iff}{\Leftrightarrow}
\newcommand{\Implies}{\Rightarrow}
\newcommand{\BCalcS}{\ensuremath{\lambda_{\textrm{\normalfont s}}\xspace}}
\newcommand{\BCalcE}{\ensuremath{\lambda_{\textrm{\normalfont e}}\xspace}}
\newcommand{\BCalcSE}{\ensuremath{\lambda_{\textrm{\normalfont se}}\xspace}}
\newcommand{\BSPCF}{\ensuremath{\lambda^\rightarrow_{\textrm{\normalfont s}}\xspace}}
\newcommand{\BEPCF}{\ensuremath{\lambda^\rightarrow_{\textrm{\normalfont e}}\xspace}}
\newcommand{\BSEPCF}{\ensuremath{\lambda^\rightarrow_{\textrm{\normalfont se}}\xspace}}
\newcommand{\IfZero}{\keyw{ifzero}}
\newcommand{\Superpoint}{\lambda\_.\Do\;\Branch~\Unit}
\newcommand{\ECount}{\dec{effcount}}
\newcommand{\Countprog}{K}
\newcommand{\Plus}{\mathsf{Plus}}
\newcommand{\Minus}{\mathsf{Minus}}
\newcommand{\Eq}{\mathsf{Eq}}
\newcommand{\BList}{\mathbb{B}^\ast}
\newcommand{\CtxCat}{\CatName{Ctx}}
\newcommand{\PureCont}{\mathsf{PureCont}}
\newcommand{\Addr}{\mathsf{Addr}}
\newcommand{\Lab}{\mathsf{Lab}}
\newcommand{\Env}{\mathsf{Env}}
\newcommand{\Time}{\dec{DTIME}}
\newcommand{\query}{\mathord{?}}
\newcommand{\ans}{\mathord{!}}
\newcommand{\labs}{\mathsf{labs}}
\newcommand{\steps}{\mathsf{steps}}
\newcommand{\tree}{\tau}
\newcommand{\tl}{\labs(\tree)}
\newcommand{\ts}{\steps(\tree)}
\newcommand{\T}[1]{\ensuremath{\mathcal{T}_{#1}}}
\newcommand{\Config}{\dec{Config}}
\newcommand{\cekl}{\langle}
\newcommand{\cekr}{\rangle}
\newcommand{\const}[1]{\ulcorner #1 \urcorner}
\newcommand{\HC}{\ensuremath{\mathcal{H}}}
\newcommand{\tr}{\mathcal{T}}
\newcommand{\tru}{\mathcal{U}}
\newcommand{\Tree}{\dec{Tree}}
\newcommand{\TimedTree}{\dec{TimedTree}}
\newcommand{\denotep}[1]{\ensuremath{\mathbb{P}\llbracket #1 \rrbracket}}
\newcommand\ttTwoTree{
\begin{tikzpicture}[->,>=stealth',level/.style={sibling distance = 4cm/##1,
level distance = 2.0cm}]
\node (root) [opnode] {Branch}
child { node [opnode] {Branch}
child { node [leaf] {$\True$}
edge from parent node[above left] {$\True$}
}
child { node [leaf] {$\True$}
edge from parent node[above right] {$\False$}
}
edge from parent node[above left] {$\True$}
}
child { node [opnode] {Branch}
child { node [leaf] {$\True$}
edge from parent node[above left] {$\True$}
}
child { node [leaf] {$\True$}
edge from parent node[above right] {$\False$}
}
edge from parent node[above right] {$\False$}
}
;
\end{tikzpicture}}
\newcommand{\tossTree}{
\begin{tikzpicture}[->,>=stealth',level/.style={sibling distance = 2.5cm/##1,
level distance = 1.0cm}]
\node (root) [opnode] {$\dec{Branch}$}
child { node [leaf] {$\dec{Heads}$}
edge from parent node[above left] {$\True$}
}
child { node [leaf] {$\dec{Tails}$}
edge from parent node[above right] {$\False$}
}
;
\end{tikzpicture}}
\newenvironment{twoeqs}{\ba[t]{@{}r@{~}c@{~}l@{~}c@{~}r@{~}c@{~}l@{}}}{\ea}
\newcommand{\compTreeEx}{
\begin{tikzpicture}[->,>=stealth',level/.style={sibling distance = 2.0cm/##1,
level distance = 2.0cm}]
\node (root) [opnode] {$\getF$}
child { node [yshift=15] {$\dots$}
edge from parent {}
}
child { node [opnode] {$\putF$}
child { node {$\True$}
edge from parent node[left] {$\Unit$}
}
edge from parent node[yshift=5,left] {$-2$}
}
child { node [opnode] {$\putF$}
child { node {$\False$}
edge from parent node[left] {$\Unit$}
}
edge from parent node[yshift=2,left] {$-1$}
}
child { node [opnode] {$\putF$}
child { node {$\True$}
edge from parent node[left] {$\Unit$}
}
edge from parent node[left] {$0$}
}
child { node [opnode] {$\putF$}
child { node {$\False$}
edge from parent node[right] {$\Unit$}
}
edge from parent node[yshift=2,right] {$1$}
}
child { node [opnode] {$\putF$}
child { node {$\True$}
edge from parent node[right] {$\Unit$}
}
edge from parent node[yshift=5,right] {$2$}
}
child { node [yshift=15] {$\dots$}
edge from parent {}
}
;
\end{tikzpicture}}
\newcommand{\smath}[1]{\ensuremath{{\scriptstyle #1}}}
\newcommand{\InfiniteModel}{%
\begin{tikzpicture}[->,>=stealth',level/.style={sibling distance = 3.0cm/##1,
level distance = 1.0cm}]
\node (root) [draw=none] { }
child { node [opnode] {$\smath{\query 0}$}
child { node [opnode] {$\smath{\query 0}$}
child { node [draw=none,rotate=165] {$\vdots$}
edge from parent node { }
}
child { node[leaf] {$\smath{\ans\False}$}
edge from parent node { }
}
edge from parent node { }
}
child { node [leaf] {$\smath{\ans\False}$}
edge from parent node { }
}
edge from parent node { }
}
;
\end{tikzpicture}}
%
\newcommand{\ShortConjModel}{%
\begin{tikzpicture}[->,>=stealth',level/.style={sibling distance = 3.5cm/##1,
level distance = 1.0cm}]
\node (root) [draw=none] { }
child { node [opnode] {$\smath{\query 0}$}
child { node [opnode] {$\smath{\query 0}$}
child { node [treenode] {$\smath{\ans\True}$}
edge from parent node { }
}
child { node[treenode] {$\smath{\ans\False}$}
edge from parent node { }
}
edge from parent node { }
}
child { node [treenode] {$\smath{\ans\False}$}
edge from parent node { }
}
edge from parent node { }
}
;
\end{tikzpicture}}
%
\newcommand{\TTTwoModel}{%
\begin{tikzpicture}[->,>=stealth',level/.style={sibling distance = 8cm/##1,
level distance = 1.5cm}]
\node (root) [draw=none] { }
child { node [opnode] {$\smath{\query 0}$}
child { node [opnode] {$\smath{\query 1}$}
child { node [leaf] {$\smath{\ans\True}$}
edge from parent node { }
}
child { node[leaf] {$\smath{\ans\True}$}
edge from parent node { }
}
edge from parent node { }
}
child { node [opnode] {$\smath{\query 1}$}
child { node [leaf] {$\smath{\ans\True}$}
edge from parent node { }
}
child { node[leaf] {$\smath{\ans\True}$}
edge from parent node { }
}
edge from parent node { }
}
edge from parent node { }
}
;
\end{tikzpicture}}
%
\newcommand{\XORTwoModel}{%
\begin{tikzpicture}[->,>=stealth',level/.style={sibling distance = 5.5cm/##1,
level distance = 1cm}]
\node (root) [draw=none] { }
child { node [opnode] {$\smath{\query 0}$}
child { node [opnode] {$\smath{\query 1}$}
child { node [treenode] {$\smath{\ans\False}$}
edge from parent node { }
}
child { node[treenode] {$\smath{\ans\True}$}
edge from parent node { }
}
edge from parent node { }
}
child { node [opnode] {$\smath{\query 1}$}
child { node [treenode] {$\smath{\ans\True}$}
edge from parent node { }
}
child { node[treenode] {$\smath{\ans\False}$}
edge from parent node { }
}
edge from parent node { }
}
edge from parent node { }
}
;
\end{tikzpicture}}
%
\newcommand{\SXORTwoModel}{%
\begin{tikzpicture}[->,>=stealth',level/.style={sibling distance = 2.5cm/##1,
level distance = 1cm}]
\node (root) [opnode] {$\smath{\query 0}$}
child { node [opnode] {$\smath{\query 1}$}
child { node [treenode] {$\smath{\ans\False}$}
edge from parent node { }
}
child { node[treenode] {$\smath{\ans\True}$}
edge from parent node { }
}
edge from parent node { }
}
child { node [opnode] {$\smath{\query 1}$}
child { node [treenode] {$\smath{\ans\True}$}
edge from parent node { }
}
child { node[treenode] {$\smath{\ans\False}$}
edge from parent node { }
}
edge from parent node { }
}
;
\end{tikzpicture}}
%
\newcommand{\TTZeroModel}{%
\begin{tikzpicture}[->,>=stealth',level/.style={sibling distance = 1cm/##1,
level distance = 1cm}]
\node (root) [draw=none] { }
child { node [treenode] {$\smath{\ans\True}$}
edge from parent node { }
}
;
\end{tikzpicture}}%

32
slides/Makefile Normal file
View File

@@ -0,0 +1,32 @@
TEXC=pdflatex
CFLAGS=-interaction=nonstopmode -halt-on-error -file-line-error
BIBC=bibtex
PAPER=viva
BIBLIO=$(PAPER)
LATEST_COMMIT=$(shell git log --format="%h" -n 1)
all: $(PAPER).pdf
draft: $(PAPER).pdf-draft
$(PAPER).aux: $(PAPER).tex
$(TEXC) $(CFLAGS) $(PAPER)
$(BIBLIO).bbl: $(PAPER).aux $(BIBLIO).bib
$(BIBC) $(PAPER)
$(PAPER).pdf: $(PAPER).aux $(BIBLIO).bbl
$(TEXC) $(CFLAGS) $(PAPER)
$(TEXC) $(CFLAGS) $(PAPER)
$(PAPER).pdf-draft: CFLAGS:=$(CFLAGS) "\def\DRAFT{$(LATEST_COMMIT)}\input{$(PAPER)}"
$(PAPER).pdf-draft: all
mv $(PAPER).pdf $(PAPER)-draft.pdf
tar cf thesis-draft.tar.gz $(PAPER)-draft.pdf
clean:
rm -f *.log *.aux *.toc *.out
rm -f *.bbl *.blg *.fls *.xml
rm -f *.nav *.snm
rm -f *.fdb_latexmk *.vtc *.cut
rm -f $(PAPER).pdf camera-ready.pdf submission.pdf
rm -f *.o *.cmx *.cmo

82
slides/viva.bib Normal file
View File

@@ -0,0 +1,82 @@
@inproceedings{HillerstromL16,
author = {Daniel Hillerstr{\"{o}}m and
Sam Lindley},
title = {Liberating effects with rows and handlers},
booktitle = {TyDe@ICFP},
pages = {15--27},
publisher = {{ACM}},
year = {2016}
}
@inproceedings{HillerstromLAS17,
author = {Daniel Hillerstr{\"{o}}m and
Sam Lindley and
Robert Atkey and
{KC} Sivaramakrishnan},
title = {Continuation Passing Style for Effect Handlers},
booktitle = {{FSCD}},
series = {LIPIcs},
volume = {84},
pages = {18:1--18:19},
OPTpublisher = {Schloss Dagstuhl - Leibniz-Zentrum fuer Informatik},
year = {2017}
}
@inproceedings{HillerstromL18,
author = {Daniel Hillerstr{\"{o}}m and
Sam Lindley},
title = {Shallow Effect Handlers},
booktitle = {{APLAS}},
OPTseries = {Lecture Notes in Computer Science},
series = {{LNCS}},
volume = {11275},
pages = {415--435},
publisher = {Springer},
year = {2018}
}
@article{HillerstromLA20,
author = {Daniel Hillerstr{\"{o}}m and
Sam Lindley and
Robert Atkey},
title = {Effect handlers via generalised continuations},
journal = {J. Funct. Program.},
volume = {30},
pages = {e5},
year = {2020}
}
@article{HillerstromLL20,
author = {Daniel Hillerstr{\"{o}}m and
Sam Lindley and
John Longley},
title = {Effects for Efficiency: Asymptotic Speedup with First-Class Control},
journal = {Proc. {ACM} Program. Lang.},
volume = {4},
number = {{ICFP}},
pages = {100:1--100:29},
year = {2020}
}
# Unix
@article{RitchieT74,
author = {Dennis Ritchie and
Ken Thompson},
title = {The {UNIX} Time-Sharing System},
journal = {Commun. {ACM}},
volume = {17},
number = {7},
pages = {365--375},
year = {1974}
}
# CEK & C
@InProceedings{FelleisenF86,
title={Control Operators, the {SECD}-machine, and the $\lambda$-Calculus},
author={Felleisen, Matthias and Friedman, Daniel P.},
year=1987,
booktitle = {Formal Description of Programming Concepts III},
OPTbooktitle = {The Proceedings of the Conference on Formal Description of Programming Concepts III, Ebberup, Denmark},
pages = {193--217},
OPTpublisher={North Holland}
}

201
slides/viva.tex Normal file
View File

@@ -0,0 +1,201 @@
\documentclass[169,10pt,compress,dvipsnames]{beamer}
%%
%% Slides layout
%%
\beamertemplatenavigationsymbolsempty % hides navigation buttons
\usetheme{Madrid} % standard Madrid theme
\setbeamertemplate{footline}{} % renders the footer empty
%
\setbeamertemplate{bibliography item}{ % this is a hack to prevent Madrid theme + biblatex
\hspace{-0.4cm}\lower3pt\hbox{ % from causing bibliography entries to run over
\pgfuseimage{beamericonarticle} % the slide margins
}}
%%
%% Packages
%%
\usepackage[utf8]{inputenc} % enable UTF-8 compatible typing
\usepackage{hyperref} % interactive PDF
\usepackage[sort&compress,square,numbers]{natbib} % Bibliography
\usepackage{bibentry} % Print bibliography entries inline.
\makeatletter % Redefine bibentry to omit hyperrefs
\renewcommand\bibentry[1]{\nocite{#1}{\frenchspacing
\@nameuse{BR@r@#1\@extra@b@citeb}}}
\makeatother
\nobibliography* % use the bibliographic data from the standard BibTeX setup.
\usepackage{amsmath,amssymb,mathtools} % maths typesetting
\usepackage{../pkgs/mathpartir} % Inference rules
\usepackage{../pkgs/mathwidth} % renders character sequences nicely in math mode
\usepackage{stmaryrd} % semantic brackets
\usepackage{xspace} % proper spacing for macros in text
\usepackage[T1]{fontenc} % 8-bit font encoding
% native support for accented characters.
\usepackage[scaled=0.85]{beramono} % smoother typewriter font
\newcommand*{\Scale}[2][4]{\scalebox{#1}{\ensuremath{#2}}}%
\input{../macros.tex}
%%
%% Meta information
%%
\author{Daniel Hillerström}
\title{Foundations for Programming and Implementing Effect Handlers}
\institute{The University of Edinburgh, Scotland UK}
\subtitle{PhD viva}
\date{August 13, 2021}
%%
%% Slides
%%
\begin{document}
%
% Title slide
%
\begin{frame}
\maketitle
\end{frame}
% Dissertation overview
\begin{frame}
\frametitle{My dissertation at glance}
Three main strands of work
\begin{description}
\item[Programming] Language design and applications of effect handlers.
\item[Implementation] Canonical implementation strategies for effect handlers.
\item[Expressiveness] Exploration of the computational expressiveness of effect handlers.
\end{description}
\end{frame}
\begin{frame}
\frametitle{Calculi for deep, shallow, and parameterised handlers}
The calculi capture key aspects of the implementation of effect
handlers in Links.
\begin{itemize}
\item $\HCalc$ ordinary deep handlers (fold).
\item $\SCalc$ shallow handlers (case-split).
\item $\HPCalc$ parameterised deep handlers (fold+state).
\end{itemize}
The actual implementation is the union of the three calculi.\\[2em]
\textbf{Relevant papers} TyDe'16~\cite{HillerstromL16},
APLAS'18~\cite{HillerstromL18}, JFP'20~\cite{HillerstromLA20}.
\end{frame}
% UNIX
\begin{frame}
\frametitle{Effect handlers as composable operating systems}
An interpretation of \citeauthor{RitchieT74}'s
UNIX~\cite{RitchieT74} in terms of effect handlers.\\[2em]
\[
\bl
\!\!\!\!\!\!\!\!\!\!\!\!\!\!\!\!\!\!\!\!\!\!\!\!\!\!\!\!\textbf{Basic idea}
\ba[m]{@{\qquad}r@{~}c@{~}l}
\text{\emph{system call}} &\approx& \text{\emph{operation invocation}}\\
\text{\emph{system call implementation}} &\approx& \text{\emph{operation interpretation}}
\ea
\el
\]\hfill\\[2em]
\textbf{Key point} Legacy code is modularly retrofitted with functionality.
\end{frame}
% CPS translation
\begin{frame}
\frametitle{CPS transforms for effect handlers}
A higher-order CPS transform for effect handlers with generalised
continuations.\\[1em]
\textbf{Generalised continuation} Structured representation of
delimited continuations.\\[0.5em]
\[
\Scale[1.8]{\kappa = \overline{(\sigma, (\hret,\hops))}}
\]\\[1em]
\textbf{Key point} Separate the \emph{doing} layer ($\sigma$) from the \emph{being} layer ($H$).\\[2em]
\textbf{Relevant papers} FSCD'17~\cite{HillerstromLAS17},
APLAS'18~\cite{HillerstromL18}, JFP'20~\cite{HillerstromLA20}.
\end{frame}
% Abstract machine
\begin{frame}
\frametitle{Abstract machine semantics for effect handlers}
Plugging generalised continuations into \citeauthor{FelleisenF86}'s
CEK machine~\cite{FelleisenF86} yields a runtime for effect
handlers.\\[2em]
\[
\Scale[2]{\cek{C \mid E \mid K = \overline{(\sigma, (H,E))}}}
\]\\[2em]
\textbf{Relevant papers} TyDe'16~\cite{HillerstromL16},
JFP'20~\cite{HillerstromLA20}.
\end{frame}
% Interdefinability of handlers
\begin{frame}
\frametitle{Interdefinability of effect handlers}
Deep, shallow, and parameterised handlers are interdefinable
w.r.t. to typability-preserving macro-expressiveness.
\begin{itemize}
\item Deep as shallow, $\mathcal{D}\llbracket - \rrbracket$, image is computationally lightweight.
\item Shallow as deep, $\mathcal{S}\llbracket - \rrbracket$, image is computationally expensive.
\item Parameterised as deep, $\mathcal{P}\llbracket - \rrbracket$,
image uses explicit state-passing.
\end{itemize}
~\\[1em]
\textbf{Relevant papers} APLAS'18~\cite{HillerstromL18},
JFP'20~\cite{HillerstromLA20}.
\end{frame}
% Asymptotic speed up with first-class control
\begin{frame}
\frametitle{Asymptotic speed up with effect handlers}
Effect handlers can make some programs faster!
\[
\Count_n : ((\Nat_n \to \Bool) \to \Bool) \to \Nat
\]\\[1em]
%
Using type-respecting expressiveness
\begin{itemize}
\item There \textbf{exists} an implementation of $\Count_n \in \HPCF$ with
effect handlers such that the runtime for every $n$-standard predicate $P$ is
$\Count_n~P = \BigO(2^n)$.
\item \textbf{Forall} implementations of $\Count_n \in \BPCF$ the runtime for every $n$-standard predicate $P$ is $\Count_n~P = \Omega(n2^n)$
\end{itemize}
~\\[1em]
\textbf{Relevant paper} ICFP'20~\cite{HillerstromLL20}.
\end{frame}
% Background
% \begin{frame}
% \frametitle{Continuations literature review}
% \end{frame}
%
% References
%
\begin{frame}%[allowframebreaks]
\frametitle{References}
\bibliographystyle{plainnat}
\bibliography{\jobname}
\end{frame}
\end{document}

3061
thesis.bib

File diff suppressed because it is too large Load Diff

20152
thesis.tex

File diff suppressed because it is too large Load Diff