-
Notifications
You must be signed in to change notification settings - Fork 0
/
types-as-macros-old.tex
550 lines (466 loc) · 24.6 KB
/
types-as-macros-old.tex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
%% For double-blind review submission
%\documentclass[acmlarge,review,anonymous]{acmart}\settopmatter{printfolios=true}
%% For single-blind review submission
%\documentclass[acmlarge,review]{acmart}\settopmatter{printfolios=true}
%% For final camera-ready submission
\documentclass[acmlarge]{acmart}\settopmatter{}
%% Note: Authors migrating a paper from PACMPL format to traditional
%% SIGPLAN proceedings format should change 'acmlarge' to
%% 'sigplan,10pt'.
%% Some recommended packages.
%\usepackage{booktabs} %% For formal tables:
% %% http://ctan.org/pkg/booktabs
%\usepackage{subcaption} %% For complex figures with subfigures/subcaptions
% %% http://ctan.org/pkg/subcaption
\usepackage{listings}
\lstdefinelanguage{clojure}%
{morekeywords={*,*1,*2,*3,*agent*,*allow-unresolved-vars*,*assert*,*clojure-version*,*command-line-args*,%
*compile-files*,*compile-path*,*e,*err*,*file*,*flush-on-newline*,*in*,*macro-meta*,%
*math-context*,*ns*,*out*,*print-dup*,*print-length*,*print-level*,*print-meta*,*print-readably*,%
*read-eval*,*source-path*,*use-context-classloader*,*warn-on-reflection*,+,-,->,->>,..,/,:else,%
<,<=,=,==,>,>=,@,accessor,aclone,add-classpath,add-watch,agent,agent-errors,aget,alength,alias,%
all-ns,alter,alter-meta!,alter-var-root,amap,ancestors,and,apply,areduce,array-map,aset,%
aset-boolean,aset-byte,aset-char,aset-double,aset-float,aset-int,aset-long,aset-short,assert,%
assoc,assoc!,assoc-in,associative?,atom,await,await-for,await1,bases,bean,bigdec,bigint,binding,%
bit-and,bit-and-not,bit-clear,bit-flip,bit-not,bit-or,bit-set,bit-shift-left,bit-shift-right,%
bit-test,bit-xor,boolean,boolean-array,booleans,bound-fn,bound-fn*,butlast,byte,byte-array,%
bytes,cast,char,char-array,char-escape-string,char-name-string,char?,chars,chunk,chunk-append,%
chunk-buffer,chunk-cons,chunk-first,chunk-next,chunk-rest,chunked-seq?,class,class?,%
clear-agent-errors,clojure-version,coll?,comment,commute,comp,comparator,compare,compare-and-set!,%
compile,complement,concat,cond,condp,conj,conj!,cons,constantly,construct-proxy,contains?,count,%
counted?,create-ns,create-struct,cycle,dec,decimal?,declare,def,definline,defmacro,defmethod,%
defmulti,defn,defn-,defonce,defprotocol,defstruct,deftype,delay,delay?,deliver,deref,derive,%
descendants,destructure,disj,disj!,dissoc,dissoc!,distinct,distinct?,do,do-template,doall,doc,%
dorun,doseq,dosync,dotimes,doto,double,double-array,doubles,drop,drop-last,drop-while,empty,empty?,%
ensure,enumeration-seq,eval,even?,every?,false,false?,ffirst,file-seq,filter,finally,find,find-doc,%
find-ns,find-var,first,float,float-array,float?,floats,flush,fn,fn?,fnext,for,force,format,future,%
future-call,future-cancel,future-cancelled?,future-done?,future?,gen-class,gen-interface,gensym,%
get,get-in,get-method,get-proxy-class,get-thread-bindings,get-validator,hash,hash-map,hash-set,%
identical?,identity,if,if-let,if-not,ifn?,import,in-ns,inc,init-proxy,instance?,int,int-array,%
integer?,interleave,intern,interpose,into,into-array,ints,io!,isa?,iterate,iterator-seq,juxt,%
key,keys,keyword,keyword?,last,lazy-cat,lazy-seq,let,letfn,line-seq,list,list*,list?,load,load-file,%
load-reader,load-string,loaded-libs,locking,long,long-array,longs,loop,macroexpand,macroexpand-1,%
make-array,make-hierarchy,map,map?,mapcat,max,max-key,memfn,memoize,merge,merge-with,meta,%
method-sig,methods,min,min-key,mod,monitor-enter,monitor-exit,name,namespace,neg?,new,newline,%
next,nfirst,nil,nil?,nnext,not,not-any?,not-empty,not-every?,not=,ns,ns-aliases,ns-imports,%
ns-interns,ns-map,ns-name,ns-publics,ns-refers,ns-resolve,ns-unalias,ns-unmap,nth,nthnext,num,%
number?,odd?,or,parents,partial,partition,pcalls,peek,persistent!,pmap,pop,pop!,pop-thread-bindings,%
pos?,pr,pr-str,prefer-method,prefers,primitives-classnames,print,print-ctor,print-doc,print-dup,%
print-method,print-namespace-doc,print-simple,print-special-doc,print-str,printf,println,println-str,%
prn,prn-str,promise,proxy,proxy-call-with-super,proxy-mappings,proxy-name,proxy-super,%
push-thread-bindings,pvalues,quot,rand,rand-int,range,ratio?,rational?,rationalize,re-find,%
re-groups,re-matcher,re-matches,re-pattern,re-seq,read,read-line,read-string,recur,reduce,ref,%
ref-history-count,ref-max-history,ref-min-history,ref-set,refer,refer-clojure,reify,%
release-pending-sends,rem,remove,remove-method,remove-ns,remove-watch,repeat,repeatedly,%
replace,replicate,require,reset!,reset-meta!,resolve,rest,resultset-seq,reverse,reversible?,%
rseq,rsubseq,second,select-keys,send,send-off,seq,seq?,seque,sequence,sequential?,set,set!,%
set-validator!,set?,short,short-array,shorts,shutdown-agents,slurp,some,sort,sort-by,sorted-map,%
sorted-map-by,sorted-set,sorted-set-by,sorted?,special-form-anchor,special-symbol?,split-at,%
split-with,str,stream?,string?,struct,struct-map,subs,subseq,subvec,supers,swap!,symbol,symbol?,%
sync,syntax-symbol-anchor,take,take-last,take-nth,take-while,test,the-ns,throw,time,to-array,%
to-array-2d,trampoline,transient,tree-seq,true,true?,try,type,unchecked-add,unchecked-dec,%
unchecked-divide,unchecked-inc,unchecked-multiply,unchecked-negate,unchecked-remainder,%
unchecked-subtract,underive,unquote,unquote-splicing,update-in,update-proxy,use,val,vals,%
var,var-get,var-set,var?,vary-meta,vec,vector,vector?,when,when-first,when-let,when-not,%
while,with-bindings,with-bindings*,with-in-str,with-loading-context,with-local-vars,%
with-meta,with-open,with-out-str,with-precision,xml-seq,zero?,zipmap
},%
sensitive,% ???
alsodigit=-,%
morecomment=[l];,%
morestring=[b]"%
}[keywords,comments,strings]%
\definecolor{mygreen}{rgb}{0,0.6,0}
\definecolor{mygray}{rgb}{0.5,0.5,0.5}
\definecolor{stringgray}{rgb}{0.4,0.4,0.4}
\definecolor{mymauve}{rgb}{0.58,0,0.82}
\definecolor{types}{rgb}{0.16, 0.32, 0.75}
%\definecolor{types}{rgb}{0.0, 0.75, 1.0}
\definecolor{turnstile}{rgb}{0.0, 0.5, 1.0}
%\definecolor{interop}{rgb}{0,0.8,0}
%\definecolor{interop}{rgb}{0.89, 0.44, 0.48}
\definecolor{interop}{rgb}{0.01, 0.75, 0.24}
\definecolor{invoke}{rgb}{0,0,0}
\lstset{ %
upquote=true,
language=clojure, % choose the language of the code
columns=fixed,basewidth=.5em,
basicstyle=\ttfamily, % the size of the fonts that are used for the code
%numbers=left, % where to put the line-numbers
%numberstyle=\small\ttfamily, % the size of the fonts that are used for the line-numbers
%stepnumber=1, % the step between two line-numbers. If it is 1 each line will be numbered
%numbersep=5pt, % how far the line-numbers are from the code
%backgroundcolor=\color{white}, % choose the background color. You must add \usepackage{color}
%showspaces=false, % show spaces adding particular underscores
showstringspaces=false, % underline spaces within strings
%showtabs=false, % show tabs within strings adding particular underscores
%frame=single, % adds a frame around the code
%tabsize=2, % sets default tabsize to 2 spaces
%captionpos=t, % sets the caption-position to bottom
%breaklines=true, % sets automatic line breaking
%breakatwhitespace=true, % sets if automatic breaks should only happen at whitespace
%escapeinside={\%*}{*)}, % if you want to add a comment within your code
literate=
%{\#\{*set\ }{{\textcolor{red}{\#\{}}}1
%{\ set*\}} {{\textcolor{red}{\}}}}1
{\{}{{\textcolor{mygray}{\{}}}1
{\}} {{\textcolor{mygray}{\}}}}1
{\{*map\ }{{\textcolor{red}{\{}}}1
{\ map*\}} {{\textcolor{red}{\}}}}1
{[} {{\textcolor{mygray}{[}}}1
{]} {{\textcolor{mygray}{]}}}1
{(} {{\textcolor{mygray}{(}}}1
{)} {{\textcolor{mygray}{)}}}1
{:-} {{\textcolor{types}{:-}}}1
{->} {{\textcolor{mygray}{->}}}1
{[*vec\ } {{\textcolor{red}{[}}}1
{\ vec*]} {{\textcolor{red}{]}}}1
{(*list\ } {{\textcolor{red}{(}}}1
{\ list*)} {{\textcolor{red}{)}}}1
{(*interop\ } {{\textcolor{interop}{(}}}1
{\ interop*)} {{\textcolor{interop}{)}}}1
{(*typed\ } {{\textcolor{types}{(}}}1
{\ typed*)} {{\textcolor{types}{)}}}1
{(*invoke\ } {{\textcolor{invoke}{(}}}1
{\ invoke*)} {{\textcolor{invoke}{)}}}1
}
\lstset{ %
%backgroundcolor=\color{white}, % choose the background color
%basicstyle=\footnotesize, % size of fonts used for the code
commentstyle=\color{mygray}, % comment style
escapeinside={(*@}{@*)},
%escapeinside={\%*}{*)}, % if you want to add LaTeX within your code
keywordstyle=\textbf, % keyword style
stringstyle=\color{stringgray}\textit, % string literal style
}
\newcommand{\clj}[1]{\lstinline{#1}}
\newcommand{\java}[1]{\lstinline{#1}}
\newcommand{\rkt}[1]{\lstinline{#1}}
\usepackage{fancyvrb}
\usepackage{amsmath}
\usepackage{mathpartir}
\usepackage{alltt,fancyvrb}
\usepackage{mmm}
\usepackage{style}
\usepackage{tikz}
\usepackage{tikz-qtree}
\bibliographystyle{abbrvnat}
\include{bibliography.bib}
\newcommand{\cL}{{\cal L}}
\makeatletter\if@ACM@journal\makeatother
%% Journal information (used by PACMPL format)
%% Supplied to authors by publisher for camera-ready submission
\acmJournal{PACMPL}
\acmVolume{1}
\acmNumber{1}
\acmArticle{1}
\acmYear{2017}
\acmMonth{1}
\acmDOI{10.1145/nnnnnnn.nnnnnnn}
\startPage{1}
\else\makeatother
%% Conference information (used by SIGPLAN proceedings format)
%% Supplied to authors by publisher for camera-ready submission
\acmConference[PL'17]{ACM SIGPLAN Conference on Programming Languages}{January 01--03, 2017}{New York, NY, USA}
\acmYear{2017}
\acmISBN{978-x-xxxx-xxxx-x/YY/MM}
\acmDOI{10.1145/nnnnnnn.nnnnnnn}
\startPage{1}
\fi
%% Copyright information
%% Supplied to authors (based on authors' rights management selection;
%% see authors.acm.org) by publisher for camera-ready submission
\setcopyright{none} %% For review submission
%\setcopyright{acmcopyright}
%\setcopyright{acmlicensed}
%\setcopyright{rightsretained}
%\copyrightyear{2017} %% If different from \acmYear
%% Bibliography style
\bibliographystyle{ACM-Reference-Format}
%% Citation style
%% Note: author/year citations are required for papers published as an
%% issue of PACMPL.
\citestyle{acmauthoryear} %% For author/year citations
\begin{document}
\title{Typed Clojure: From Practice to Ubiquity}
%% Author with single affiliation.
\author{Ambrose Bonnaire-Sergeant}
%\authornote{with author1 note} %% \authornote is optional;
%% can be repeated if necessary
%\orcid{nnnn-nnnn-nnnn-nnnn} %% \orcid is optional
\affiliation{
%\position{Position1}
\department{Computer Science} %% \department is recommended
\institution{Indiana University} %% \institution is required
%\streetaddress{Street1 Address1}
%\city{City1}
%\state{State1}
%\postcode{Post-Code1}
\country{USA}
}
\email{[email protected]} %% \email is recommended
%% Paper note
%% The \thanks command may be used to create a "paper note" ---
%% similar to a title note or an author note, but not explicitly
%% associated with a particular element. It will appear immediately
%% above the permission/copyright statement.
%\thanks{with paper note} %% \thanks is optional
%% can be repeated if necesary
%% contents suppressed with 'anonymous'
%% Abstract
%% Note: \begin{abstract}...\end{abstract} environment must come
%% before \maketitle command
\begin{abstract}
\end{abstract}
%% 2012 ACM Computing Classification System (CSS) concepts
%% Generate at 'http://dl.acm.org/ccs/ccs.cfm'.
%\begin{CCSXML}
%<ccs2012>
%<concept>
%<concept_id>10011007.10011006.10011008</concept_id>
%<concept_desc>Software and its engineering~General programming languages</concept_desc>
%<concept_significance>500</concept_significance>
%</concept>
%<concept>
%<concept_id>10003456.10003457.10003521.10003525</concept_id>
%<concept_desc>Social and professional topics~History of programming languages</concept_desc>
%<concept_significance>300</concept_significance>
%</concept>
%</ccs2012>
%\end{CCSXML}
%\ccsdesc[500]{Software and its engineering~General programming languages}
%\ccsdesc[300]{Social and professional topics~History of programming languages}
%% End of generated code
%% Keywords
%% comma separated list
%\keywords{keyword1, keyword2, keyword3} %% \keywords is optional
%% \maketitle
%% Note: \maketitle command must come after title commands, author
%% commands, abstract environment, Computing Classification System
%% environment and commands, and keywords command.
\maketitle
\section{Introduction}
\subsection{Thesis statement}
\begin{verbatim}
Top level annotations are all that's needed to infer local annotations
in most Clojure code.
\end{verbatim}
%\begin{verbatim}
%Typed Clojure can be extended to be user friendly while still
%retaining most of its strong properties in practice.
%\end{verbatim}
\subsection{History}
The initial spark to develop a type system for Clojure came about
after the release and successes of Typed Racket, a gradual typing system
for Racket. The surface similarities of Racket and Clojure raised the
obvious question: could a similar type system be developed for Clojure?
Initial investigation revealed that yes, many ideas in Typed Racket
were directly applicable to a Clojure type system. The novelties
in Typed Racket's static semantics in particular (typically the least interesting part
of a gradual typing system) yielded surprisingly good results in the context of Clojure.
We found the ``occurrence typing'' approach to type checking local control flow
to be as applicable to Clojure's idioms as Racket's,
where it was initially invented.
Emulating the dynamic semantics of Typed Racket in a Clojure type system
was initially deferred in lieu of building an ``optional'' type system---roughly
a ``gradual'' type system without any runtime mediation. Later investigations
found that building a gradual typing system for Clojure raised interesting questions,
but fundamental limitations on creating proxies on many runtime objects stopped
much progress in this area (most classes are declared ``final'', and therefore wrapping
them could break existing ``instanceof'' checks and method calls).
We hypothesize that a proxy-based gradual typing system
for ClojureScript would fare better, where proxies are freely allowed for any object,
but we defer this work indefinitely.
Other approaches like ``transient'' gradual typing would probably work in either Clojure
or ClojureScript, but we have not investigated this.
So, Typed Clojure remains an ``optional'' type system for now, sharing identical
runtime semantics as Clojure. Why, then, has porting the static semantics of a gradually
typed language yielded interesting research in Clojure?
\subsection{Why Typed Clojure implements the static semantics of a gradual type system}
There are several key insights into why this decision was made.
\begin{enumerate}
\item Clojure strongly favors immutability, Typed Racket's approach
to flow typing (called ``occurrence typing'') was
arguably even more effective in this context.
\item Besides occurrence typing, Typed Racket's static checker is a
straightforward bidirectional checking algorithm, utilizing Pierce
and Turner's Local Type Inference for polymorphic invocations.
In contrast to previous attempts at type checking untyped languages,
this approach is simple to implement, yields good error messages,
and acts predictably in practice.
\item Clojure and Racket programming style are similar, in that they favour
manipulating data with a largely functional style, and they are both
untyped.
\item Clojure and Racket both feature Lisp-style macros, which Typed Racket approaches
by supporting the fixed number of special core forms Racket provides, and
simply expanding all macros before type checking. This approach is equally
applicable in Clojure.
\end{enumerate}
\subsection{Downsides to Typed Clojure's implementation}
\begin{enumerate}
\item Macroexpansion occurs before type checking
\begin{itemize}
\item macros hold valuable structure that are expanded away before type checking
\item must first expand arbitrary macro calls and then type check its results
\item in practice, must define "typed" version of macro that carefully constructs
necessary conditions for the expansion to type check successfully
\end{itemize}
\item Compilation unit is a file
\begin{itemize}
\item type checking quickly becomes viral without planning and effort in
working around the type system.
\end{itemize}
\item Abundance of top-level and local annotations needed
\begin{itemize}
\item In practice, every top-level variable, including library imports
requires an annotation
\item limitations in Local Type Inference mean local lambdas and many
polymorphic calls must also be annotated
\end{itemize}
\item Users cannot distinguish between user-errors and limitations of
the type system.
\begin{itemize}
\item Typed Clojure chooses a subset of Clojure idioms to support,
and this is not always conveyed to the user in a helpful manner.
\end{itemize}
\item Over-conservative implementation limits dynamism during development
of Typed Clojure programs compared to Clojure.
\begin{itemize}
\item Tradeoffs should be made, documented and implemented to bring the balance
of development agility that Clojure developers require, with a strong
level of verification options.
\end{itemize}
\end{enumerate}
\subsection{Initiatives to improve this situation}
\begin{enumerate}
\item Use runtime observations to automatically generate annotations for variables,
cutting the manual effort in the untyped-typed conversion.
\begin{itemize}
\item extensions: polymorphic functions
\end{itemize}
\item ``Type systems as macros'' approaches
\begin{itemize}
\item interleave type checking and macro expansion so type system can have custom
rules for each macro expansion to provide better error messages
\item provide DSL/API for users to write their own custom type systems for any macro
\end{itemize}
\item ``Colored local type inference''-style partial type information propagation
\begin{itemize}
\item local lambda annotations are frustrating for users
\item not needed in clojure.spec and other runtime-based verification tools
\item often, argument types can be inferred from context
\item but partial information flow is needed
\item pairing colored LTI with extensible typing rules can eliminate most local annotations
in typical Clojure programs
\item use polymorphic function types to influence type checking order of arguments
\end{itemize}
\item letfn-rewriting to eliminate local letfn annotations
\item Repurpose clojure.spec annotations as type annotations
\begin{itemize}
\item clojure.spec annotations are ubiquitous, and the de-facto tool for specifying functions
\item less expressive, but still valuable as static annotations
\item if granularity of type checking is satisfying, could provide quickest
path to static type checking for many projects
\end{itemize}
\end{enumerate}
Answering CircleCI's complaints:
\subsection{Slower Iteration Time}
The biggest complaint is that transitive dependencies are eagerly rechecked,
which is a huge performance hit for large projects. This has since been fixed.
The key was to collect type annotations at runtime, instead of typechecking time,
so we don't need to manually search through dependencies for type annotations.
That said, there is a clear performance hit over regular untyped evaluation.
Some ideas.
\begin{enumerate}
\item asynchronous type checking will allow very fast compiles, but slow
feedback from the type checker.
\item type systems as macros may allow us to avoid many polymorphic type reconstructions.
\item another performance hit is occurrence typing. Try and type check things with
naive occurrence typing, if it doesn't work, try again. Or perhaps, opt-in to
more sophisticated type checking (we can suggest this to user).
\item only recheck functions whose types have changed
\item dependency analysis on function dependencies to ensure we only retype-check
things that matter.
\item instrument functions so that they type check at runtime if/when they are called.
\item extensive benchmarking and profiling cases
\item disable union simplification (this takes up a lot of time and it isn't obvious
it's always needed.
\item by default, don't type check anything. Provide a function that will type check
a given top-level variable (like clojure.spec's 'instrument' function). So
give complete power to the user at the level of granularity of functions.
\end{enumerate}
\subsection{Core.typed Does Not Implement The Entire Clojure Language}
Several important points are made here.
\begin{enumerate}
\item if a Clojure idiom is not supported by core.typed, the error message
that core.typed throws is not informative. The user cannot immediately tell the
difference between a genuine type error and an undersupported idiom
\begin{itemize}
\item this could be addressed for common core functions with custom errors in types-as-macros
\end{itemize}
\item it's frustrating for the programmer to have idioms that are not supported, and
they keep trying to make it work but this isn't what the type system was designed
to solve.
\item trying to type check usages of helper functions can be very hard to do.
\begin{itemize}
\item Perhaps type systems as macros can provide a more pleasant UI to direct the
type system than spending much more time on inventing more sophisticated function
types
\item helper functions are often simple variations on existing functions. We could provide
a base set of templates to easily characterise how to check usages (eg. filter,
map, or apply variations)
\end{itemize}
\end{enumerate}
\subsection{Third Party Code}
The main complaint is the effort needed to annotate libraries.
\begin{enumerate}
\item This is currently being addressed in the runtime-type inference work.
\item perhaps this could be automated: the type system detected an unannotated library
function, and walks you through how to generate a type annotation for it (if it
isn't already on github)
\item Another approach is to leverage existing clojure.spec annotations as type annotations
\item Yet another approach: provide a sweetened DSL for annotating clojure.spec code
that is a superset of core.typed annotations. (tagged unions, functions with argument names)
\end{enumerate}
\section{Eliminating Local Annotations}
A large problem in day to day usages of core.typed are boilerplate annotations that
are required to be manually written to drive type checking. These are often redundant
and annoying to write.
For example, the following code requires an annoying type annotation: the variable
'a' needs an 'Int' annotation.
\begin{verbatim}
(map (fn [a] (inc a)) [1 2 3])
\end{verbatim}
Interestingly, a human type checking this in a bidirectional fashion can do a good
job at type checking this invocation, without oracles or complicated global
type inference. All they require is to propagate partial type information
to local functions (like Colored Local Type Inference).
The recipe is: first, type check the collection:
\begin{verbatim}
[1 2 3] : (Seqable Int)
\end{verbatim}
Then, type check the function argument:
\begin{verbatim}
(fn [a] (inc a)) : [Int -> ?]
\end{verbatim}
Finally, take the inferred return type of the function, here 'Int'
and synthesize the entire 'map' expression as type:
\begin{verbatim}
(map (fn [a] (inc a)) [1 2 3]) : (Seqable Int)
\end{verbatim}
How can we encode this procedure into a type checking rule?
We propose several possible approaches.
\subsection{Automatically decide argument type checking order from function type}
Here is the type of map (with 2 arguments):
\begin{verbatim}
(All [x y] [[x -> y] (Seqable x) -> (Seqable y)])
\end{verbatim}
Let's use the number of occurrences to the left of an arrow
to decide which argument to type check first.
In the first argument [x -> y], x appears once to the left of the arrow.
In the second argument (Seqable x), x appears zero times to the left of an arrow.
So, we should check the second argument first, and then propagate the type of
x derived so far to check the first argument.
\subsection{Custom typing rules with types-as-macros}
\bibliography{bibliography}
\end{document}