[icfp] all prettier
This commit is contained in:
parent
a425fa840f
commit
f14387469a
|
@ -25,6 +25,7 @@
|
||||||
(define Transactions "Transactions on ")
|
(define Transactions "Transactions on ")
|
||||||
|
|
||||||
|
|
||||||
|
(define/short dsl "DS" (string-append ACM Conference "on Domain-specific languages"))
|
||||||
(define/short asplas "APLAS" (string-append "Asian " Symposium "Programming Languages and Systems"))
|
(define/short asplas "APLAS" (string-append "Asian " Symposium "Programming Languages and Systems"))
|
||||||
(define/short fpca "FPCA" (string-append ACM International Conference "Functional Programming Languages and Computer Architecture"))
|
(define/short fpca "FPCA" (string-append ACM International Conference "Functional Programming Languages and Computer Architecture"))
|
||||||
(define/short icfp "ICFP" (string-append ACM International Conference "on Functional Programming"))
|
(define/short icfp "ICFP" (string-append ACM International Conference "on Functional Programming"))
|
||||||
|
@ -1216,3 +1217,10 @@
|
||||||
#:author (authors "Tiark Rompf" "Nada Amin")
|
#:author (authors "Tiark Rompf" "Nada Amin")
|
||||||
#:location (proceedings-location icfp #:pages '(2 9))
|
#:location (proceedings-location icfp #:pages '(2 9))
|
||||||
#:date 2015))
|
#:date 2015))
|
||||||
|
|
||||||
|
(define lm-dsl-1999
|
||||||
|
(make-bib
|
||||||
|
#:title "Domain Specific Embedded Compilers"
|
||||||
|
#:author (authors "Daan Leijen" "Erik Meijer")
|
||||||
|
#:location (proceedings-location dsl #:pages '(109 122))
|
||||||
|
#:date 1999))
|
||||||
|
|
|
@ -193,9 +193,10 @@ The interesting design challenge is making one pattern that covers all
|
||||||
@; =============================================================================
|
@; =============================================================================
|
||||||
@section[#:tag "sec:impl-interp"]{Illustrative Interpretations}
|
@section[#:tag "sec:impl-interp"]{Illustrative Interpretations}
|
||||||
|
|
||||||
By now we have seen two useful syntax classes: @racket[id] and
|
Both @racket[id] and
|
||||||
@racket[vector/length].@note{The name @racket[vector/length] should
|
@racket[vector/length] are useful syntax classes..@note{The name @racket[vector/length] should
|
||||||
be read as ``vector @emph{with} length information''.}
|
be read as ``vector @emph{with} length information''.}
|
||||||
|
They recognize syntax objects with certain well-defined properties.
|
||||||
In fact, we use syntax classes as the front-end for each function in @exact{$\interp$}.
|
In fact, we use syntax classes as the front-end for each function in @exact{$\interp$}.
|
||||||
@Figure-ref{fig:stxclass} lists all of our syntax classes and ties each to a purpose
|
@Figure-ref{fig:stxclass} lists all of our syntax classes and ties each to a purpose
|
||||||
motivated in @Secref{sec:usage}.
|
motivated in @Secref{sec:usage}.
|
||||||
|
@ -392,12 +393,17 @@ The only question we ask during elaboration is whether a syntax object is associ
|
||||||
Traditional macros may appear only in the head position of an expression.
|
Traditional macros may appear only in the head position of an expression.
|
||||||
For example, the following are illegal uses of the built-in @racket[or]
|
For example, the following are illegal uses of the built-in @racket[or]
|
||||||
macro:
|
macro:
|
||||||
@racketblock[
|
|
||||||
> or
|
@exact|{
|
||||||
or: bad syntax
|
\begin{SCodeFlow}\begin{RktBlk}\begin{SingleColumn}\RktSym{{\Stttextmore}}\mbox{\hphantom{\Scribtexttt{x}}}\RktSym{or}
|
||||||
> (map or '((#t #f #f) (#f #f)))
|
|
||||||
or: bad syntax
|
\evalsto\RktErr{or: bad syntax}
|
||||||
]
|
|
||||||
|
\RktSym{{\Stttextmore}}\mbox{\hphantom{\Scribtexttt{x}}}\RktPn{(}\RktSym{map}\mbox{\hphantom{\Scribtexttt{x}}}\RktSym{or}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{{\textquotesingle}}\RktVal{(}\RktVal{(}\RktVal{\#t}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{\#f}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{\#f}\RktVal{)}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{(}\RktVal{\#f}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{\#f}\RktVal{)}\RktVal{)}\RktPn{)}
|
||||||
|
|
||||||
|
\evalsto\RktErr{or: bad syntax}
|
||||||
|
\end{SingleColumn}\end{RktBlk}\end{SCodeFlow}
|
||||||
|
}|
|
||||||
|
|
||||||
Identifier macros are allowed in both higher-order and top-level positions,
|
Identifier macros are allowed in both higher-order and top-level positions,
|
||||||
just like first-class functions.
|
just like first-class functions.
|
||||||
|
@ -416,7 +422,8 @@ By tagging calls to @racket[vector-map] with a syntax property, our system
|
||||||
|
|
||||||
@centered[
|
@centered[
|
||||||
@codeblock{
|
@codeblock{
|
||||||
(vector-length v) == (vector-length (vector-map f v))
|
(vector-length (vector-map f v))
|
||||||
|
== (vector-length v)
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -436,12 +443,12 @@ Within the binding's scope, the transformer redirects references from a variable
|
||||||
For our purposes, we redirect to an annotated version of the same variable:
|
For our purposes, we redirect to an annotated version of the same variable:
|
||||||
|
|
||||||
@racketblock[
|
@racketblock[
|
||||||
> '(let ([x 4])
|
> ⟦'(let ([x 4])
|
||||||
(+ x 1))
|
(+ x 1))⟧
|
||||||
'(let ([x 4])
|
==> '(let ([x 4])
|
||||||
(let-syntax ([x (make-rename-transformer #'x
|
(let-syntax ([x (make-rename-transformer #'x
|
||||||
secret-key 4)])
|
secret-key 4)])
|
||||||
(+ x 1)))
|
(+ x 1)))
|
||||||
]
|
]
|
||||||
|
|
||||||
For definitions, we use a @emph{free-identifier table}.
|
For definitions, we use a @emph{free-identifier table}.
|
||||||
|
|
|
@ -116,8 +116,6 @@ The arity of the result could also be derived from its textual representation,
|
||||||
|
|
||||||
Our implementation uses a tagging protocol, and this lets us share information
|
Our implementation uses a tagging protocol, and this lets us share information
|
||||||
between unrelated elaboration function in a bottom-up recursive style.
|
between unrelated elaboration function in a bottom-up recursive style.
|
||||||
The same protocol helps us implement binding forms: when interpreting a variable,
|
|
||||||
we check for an associated tag.
|
|
||||||
Formally speaking, this changes either the codomain of functions in @exact{$\elab$}
|
Formally speaking, this changes either the codomain of functions in @exact{$\elab$}
|
||||||
or introduces an elaboration environment mapping expressions to values.
|
or introduces an elaboration environment mapping expressions to values.
|
||||||
|
|
||||||
|
|
|
@ -42,3 +42,4 @@
|
||||||
\newcommand{\trt}[1]{\emph{#1}}
|
\newcommand{\trt}[1]{\emph{#1}}
|
||||||
\newcommand{\tprintf}{\mathsf{t_printf}}
|
\newcommand{\tprintf}{\mathsf{t_printf}}
|
||||||
\newcommand{\mod}[1]{$\mathsf{#1}$}
|
\newcommand{\mod}[1]{$\mathsf{#1}$}
|
||||||
|
\newcommand{\evalsto}{\RktMeta{}\RktSym{=={\Stttextmore}}\RktMeta{}\mbox{\hphantom{\Scribtexttt{x}}}}
|
||||||
|
|
|
@ -25,21 +25,21 @@ This protocol lets us implement our elaborators as macros that expand into
|
||||||
typed code.
|
typed code.
|
||||||
|
|
||||||
Each elaborator is defined as a @emph{local} transformation on syntax.
|
Each elaborator is defined as a @emph{local} transformation on syntax.
|
||||||
Code produced by an elaboration is associated with compile-time data that
|
Code produced by an elaboration may be associated with compile-time values
|
||||||
other elaborators may access.
|
for other elaborators to access.
|
||||||
In this way, we handle binding forms and propagate information through
|
Using these values, we support variable bindings and propagate information upward through
|
||||||
@emph{unrelated} program transformations.
|
nested elaborations.
|
||||||
|
|
||||||
@parag{Conventions}
|
@parag{Conventions}
|
||||||
@itemlist[
|
@itemlist[
|
||||||
@item{
|
@item{
|
||||||
Interpretation and elaboration functions are defined over symbolic expressions
|
Interpretation and elaboration functions are defined over symbolic expressions
|
||||||
and values; specifically, over @emph{syntax objects}.
|
and values; specifically, over @emph{syntax objects}.
|
||||||
To distinguish terms and syntax objects representing
|
To distinguish terms and syntax objects,
|
||||||
terms, we quote the latter and typeset it in green.
|
we quote the latter and typeset it in green.
|
||||||
For example, @racket[(λ (x) x)] is a term implementing the identity
|
Hence @racket[(λ (x) x)] is the identity function
|
||||||
function and @racket['(λ (x) x)] is a representation that will evaluate
|
and @racket['(λ (x) x)] is a syntax object.
|
||||||
to the identity function.
|
} @item{
|
||||||
Values are typeset in @exact|{\RktVal{green}}| because their syntax and
|
Values are typeset in @exact|{\RktVal{green}}| because their syntax and
|
||||||
term representations are identical.
|
term representations are identical.
|
||||||
} @item{
|
} @item{
|
||||||
|
@ -48,7 +48,7 @@ Syntax objects carry lexical information, but our examples treat them as
|
||||||
} @item{
|
} @item{
|
||||||
We use an infix @tt{::} to write explicit type annotations and casts,
|
We use an infix @tt{::} to write explicit type annotations and casts,
|
||||||
for instance @racket[(x :: Integer)].
|
for instance @racket[(x :: Integer)].
|
||||||
These normally have two different syntaxes, respectively
|
Annotations and casts normally have two different syntaxes, respectively
|
||||||
@racket[(ann x Integer)] and @racket[(cast x Integer)].
|
@racket[(ann x Integer)] and @racket[(cast x Integer)].
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -72,7 +72,7 @@ For example, @racket[~s] converts any value to a string and @racket[~b] converts
|
||||||
@exact|{
|
@exact|{
|
||||||
\begin{SCodeFlow}\begin{RktBlk}\begin{SingleColumn}\Scribtexttt{{\Stttextmore} }\RktPn{(}\RktSym{printf}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{"binary($\sim$s) = $\sim$b"}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{7}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{7}\RktPn{)}
|
\begin{SCodeFlow}\begin{RktBlk}\begin{SingleColumn}\Scribtexttt{{\Stttextmore} }\RktPn{(}\RktSym{printf}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{"binary($\sim$s) = $\sim$b"}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{7}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{7}\RktPn{)}
|
||||||
|
|
||||||
\RktOut{binary(7) = 111}
|
\evalsto\RktOut{binary(7) = 111}
|
||||||
|
|
||||||
\begin{SingleColumn}\end{SingleColumn}\end{SingleColumn}\end{RktBlk}\end{SCodeFlow}
|
\begin{SingleColumn}\end{SingleColumn}\end{SingleColumn}\end{RktBlk}\end{SCodeFlow}
|
||||||
}|
|
}|
|
||||||
|
@ -84,28 +84,27 @@ This is a simple kind of value error that could be caught statically.
|
||||||
@exact|{
|
@exact|{
|
||||||
\begin{SCodeFlow}\begin{RktBlk}\begin{SingleColumn}\Scribtexttt{{\Stttextmore} }\RktPn{(}\RktSym{printf}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{"binary($\sim$s) = $\sim$b"}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{"7"}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{"7"}\RktPn{)}
|
\begin{SCodeFlow}\begin{RktBlk}\begin{SingleColumn}\Scribtexttt{{\Stttextmore} }\RktPn{(}\RktSym{printf}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{"binary($\sim$s) = $\sim$b"}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{"7"}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{"7"}\RktPn{)}
|
||||||
|
|
||||||
\RktErr{printf: format string requires argument of type $<$exact{-}number$>$}
|
\evalsto\RktErr{printf: format string requires an exact{-}number}
|
||||||
|
|
||||||
\begin{SingleColumn}\end{SingleColumn}\end{SingleColumn}\end{RktBlk}\end{SCodeFlow}
|
\begin{SingleColumn}\end{SingleColumn}\end{SingleColumn}\end{RktBlk}\end{SCodeFlow}
|
||||||
}|
|
}|
|
||||||
|
|
||||||
Detecting inconsistencies between a format string and its arguments is straightforward
|
Detecting inconsistencies between a format string and its arguments is straightforward
|
||||||
if we define an interpretation @racket[fmt->types] @exact|{$\in \interp$}| for
|
if we define an interpretation @racket[fmt->types] for
|
||||||
reading types from a format string value.
|
reading types from a format string value.
|
||||||
In Typed Racket this function is rather simple because the most common
|
In Typed Racket this function is rather simple because the most common
|
||||||
directives accept @code{Any} type of value.
|
directives accept @code{Any} type of value.
|
||||||
|
|
||||||
@exact|{
|
@exact|{
|
||||||
\hfill\fbox{\RktMeta{fmt->types} $\in \interp$}
|
\hfill\fbox{\RktMeta{fmt->types} $\in \interp$}
|
||||||
|
\vspace{-4mm}
|
||||||
\begin{SCodeFlow}\begin{RktBlk}\begin{SingleColumn}\RktSym{{\Stttextmore}}\mbox{\hphantom{\Scribtexttt{x}}}\RktPn{(}\RktSym{fmt{-}{\Stttextmore}types}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{"binary($\sim$s) = $\sim$b"}\RktPn{)}
|
|
||||||
|
|
||||||
\RktVal{{\textquotesingle}}\RktVal{[}\RktVal{Any}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{Integer}\RktVal{]}
|
|
||||||
|
|
||||||
\RktSym{{\Stttextmore}}\mbox{\hphantom{\Scribtexttt{x}}}\RktPn{(}\RktSym{fmt{-}{\Stttextmore}types}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{{\textquotesingle}}\RktVal{(}\RktVal{$\lambda$}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{(}\RktVal{x}\RktVal{)}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{x}\RktVal{)}\RktPn{)}
|
|
||||||
|
|
||||||
\RktVal{\#false}\end{SingleColumn}\end{RktBlk}\end{SCodeFlow}
|
|
||||||
}|
|
}|
|
||||||
|
@racketblock[
|
||||||
|
> (fmt->types "binary(~s) = ~b")
|
||||||
|
==> '[Any Integer]
|
||||||
|
> (fmt->types '(λ (x) x))
|
||||||
|
==> #false
|
||||||
|
]
|
||||||
|
|
||||||
Now to use @racket[fmt->types] in an elaboration.
|
Now to use @racket[fmt->types] in an elaboration.
|
||||||
Given a call to @racket[printf], we check the number of arguments and
|
Given a call to @racket[printf], we check the number of arguments and
|
||||||
|
@ -113,20 +112,17 @@ Given a call to @racket[printf], we check the number of arguments and
|
||||||
For all other syntax patterns, @racket[t-printf] is the identity elaboration.
|
For all other syntax patterns, @racket[t-printf] is the identity elaboration.
|
||||||
|
|
||||||
@exact|{
|
@exact|{
|
||||||
\hfill\fbox{$\elabf \in \interp$}
|
\hfill\fbox{$\elabf \in \elab$}
|
||||||
|
\vspace{-4mm}
|
||||||
\begin{SCodeFlow}\begin{RktBlk}\begin{SingleColumn}\RktSym{{\Stttextmore}}\mbox{\hphantom{\Scribtexttt{x}}}\RktPn{(}\RktSym{t{-}printf}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{{\textquotesingle}}\RktVal{(}\RktVal{printf}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{"$\sim$a"}\RktVal{)}\RktPn{)}
|
|
||||||
|
|
||||||
\RktSym{$\perp$}
|
|
||||||
|
|
||||||
\RktSym{{\Stttextmore}}\mbox{\hphantom{\Scribtexttt{x}}}\RktPn{(}\RktSym{t{-}printf}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{{\textquotesingle}}\RktVal{(}\RktVal{printf}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{"$\sim$b"}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{"2"}\RktVal{)}\RktPn{)}
|
|
||||||
|
|
||||||
\RktVal{{\textquotesingle}}\RktVal{(}\RktVal{printf}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{"$\sim$b"}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{(}\RktVal{"2"}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{{\hbox{\texttt{::}}}}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{Integer}\RktVal{)}\RktVal{)}
|
|
||||||
|
|
||||||
\RktSym{{\Stttextmore}}\mbox{\hphantom{\Scribtexttt{x}}}\RktPn{(}\RktSym{t{-}printf}\mbox{\hphantom{\Scribtexttt{x}}}\RktSym{printf}\RktPn{)}
|
|
||||||
|
|
||||||
\RktVal{{\textquotesingle}}\RktVal{printf}\end{SingleColumn}\end{RktBlk}\end{SCodeFlow}
|
|
||||||
}|
|
}|
|
||||||
|
@racketblock[
|
||||||
|
> ⟦'(printf "~a")⟧
|
||||||
|
==> ⊥
|
||||||
|
> ⟦'(printf "~b" 2)⟧
|
||||||
|
==> '(printf "~b" (2 :: Integer))
|
||||||
|
> ⟦'printf ⟧
|
||||||
|
==> 'printf
|
||||||
|
]
|
||||||
|
|
||||||
The first example is rejected immediately as a syntax error.
|
The first example is rejected immediately as a syntax error.
|
||||||
The second is a valid elaboration, but will lead to a static type error.
|
The second is a valid elaboration, but will lead to a static type error.
|
||||||
|
@ -141,8 +137,10 @@ The third example demonstrates that higher-order
|
||||||
Regular expressions are often used to capture sub-patterns within a string.
|
Regular expressions are often used to capture sub-patterns within a string.
|
||||||
|
|
||||||
@racketblock[
|
@racketblock[
|
||||||
> (regexp-match #rx"(.*)@(.*)" "toni@merchant.net")
|
> (regexp-match #rx"-(2*)-" "111-222-3333")
|
||||||
'("toni@merchant.net" "toni" "merchant.net")
|
==> '("-222-" "222")
|
||||||
|
> (regexp-match #rx"¥(.*)" "$2,000")
|
||||||
|
==> #false
|
||||||
]
|
]
|
||||||
|
|
||||||
The first argument to @racket[regexp-match] is a regular expression pattern.
|
The first argument to @racket[regexp-match] is a regular expression pattern.
|
||||||
|
@ -154,19 +152,12 @@ If the match succeeds, the result is a list containing the entire matched string
|
||||||
and substrings corresponding to each group captured by a sub-pattern.
|
and substrings corresponding to each group captured by a sub-pattern.
|
||||||
If the match fails, @racket[regexp-match] returns @racket[#false].
|
If the match fails, @racket[regexp-match] returns @racket[#false].
|
||||||
|
|
||||||
@racketblock[
|
Groups may fail to capture even when the overall match succeeds.
|
||||||
> (regexp-match #rx"-(2*)-" "111-222-3333")
|
|
||||||
'("-222-" "222")
|
|
||||||
> (regexp-match #rx"¥(.*)" "$2,000")
|
|
||||||
#false
|
|
||||||
]
|
|
||||||
|
|
||||||
Certain groups can also fail to capture even when the overall match succeeds.
|
|
||||||
This can happen when a group is followed by a Kleene star.
|
This can happen when a group is followed by a Kleene star.
|
||||||
|
|
||||||
@racketblock[
|
@racketblock[
|
||||||
> (regexp-match #rx"(a)*(b)" "b")
|
> (regexp-match #rx"(a)*(b)" "b")
|
||||||
'("b" #f "b")
|
==> '("b" #f "b")
|
||||||
]
|
]
|
||||||
|
|
||||||
Therefore, a catch-all type for @racket[regexp-match] is fairly large:
|
Therefore, a catch-all type for @racket[regexp-match] is fairly large:
|
||||||
|
@ -174,20 +165,18 @@ Therefore, a catch-all type for @racket[regexp-match] is fairly large:
|
||||||
Using this general type is cumbersome for simple patterns
|
Using this general type is cumbersome for simple patterns
|
||||||
where a match implies that all groups will successfully capture.
|
where a match implies that all groups will successfully capture.
|
||||||
|
|
||||||
|
@racketblock[
|
||||||
|
> (define (get-domain (email : String)) : String
|
||||||
|
(cond
|
||||||
|
[(regexp-match #rx"(.*)@(.*)" email)
|
||||||
|
=> third]
|
||||||
|
[else "Match Failed"]))
|
||||||
|
]
|
||||||
|
|
||||||
@exact|{
|
@exact|{
|
||||||
\begin{SCodeFlow}\begin{RktBlk}\begin{SingleColumn}\RktSym{{\Stttextmore}}\mbox{\hphantom{\Scribtexttt{x}}}\RktPn{(}\RktSym{define}\mbox{\hphantom{\Scribtexttt{x}}}\RktPn{(}\RktSym{get{-}domain}\mbox{\hphantom{\Scribtexttt{x}}}\RktPn{[}\RktSym{full{-}name}\mbox{\hphantom{\Scribtexttt{x}}}\RktSym{{\hbox{\texttt{:}}}}\mbox{\hphantom{\Scribtexttt{x}}}\RktSym{String}\RktPn{]}\RktPn{)}\mbox{\hphantom{\Scribtexttt{x}}}\RktSym{{\hbox{\texttt{:}}}}\mbox{\hphantom{\Scribtexttt{x}}}\RktSym{String}
|
\vspace{-1mm}%
|
||||||
|
$\!\!$\evalsto\RktErr{Type Error: expected String, got (U \#false String)}%
|
||||||
\mbox{\hphantom{\Scribtexttt{xxxx}}}\RktPn{(}\RktSym{cond}
|
\vspace{1mm}
|
||||||
|
|
||||||
\mbox{\hphantom{\Scribtexttt{xxxxx}}}\RktPn{[}\RktPn{(}\RktSym{regexp{-}match}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{\#rx"({\hbox{\texttt{.}}}*)@({\hbox{\texttt{.}}}*)"}\mbox{\hphantom{\Scribtexttt{x}}}\RktSym{full{-}name}\RktPn{)}
|
|
||||||
|
|
||||||
\mbox{\hphantom{\Scribtexttt{xxxxxx}}}\RktSym{={\Stttextmore}}\mbox{\hphantom{\Scribtexttt{x}}}\RktSym{third}\RktPn{]}
|
|
||||||
|
|
||||||
\mbox{\hphantom{\Scribtexttt{xxxxx}}}\RktPn{[}\RktSym{else}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{"Match Failed"}\RktPn{]}\RktPn{)}\RktPn{)}
|
|
||||||
|
|
||||||
\RktErr{Error: expected $<$String$>$, got $<$(U \#false String)$>$}
|
|
||||||
|
|
||||||
\end{SingleColumn}\end{RktBlk}\end{SCodeFlow}
|
|
||||||
}|
|
}|
|
||||||
|
|
||||||
|
|
||||||
|
@ -198,15 +187,17 @@ We alleviate the need for casts and guards in simple patterns
|
||||||
If there is any doubt whether a group will capture, we default to the general
|
If there is any doubt whether a group will capture, we default to the general
|
||||||
@racket[regexp-match] type.
|
@racket[regexp-match] type.
|
||||||
|
|
||||||
@todo{fbox} @racket[rx->groups] @exact|{$\in \interp$}|
|
@exact|{
|
||||||
|
\hfill\fbox{$\RktMeta{rx->groups} \in \interp$}
|
||||||
|
\vspace{-4mm}
|
||||||
|
}|
|
||||||
@racketblock[
|
@racketblock[
|
||||||
> (rx->groups #rx"(a)(b)(c)")
|
> (rx->groups #rx"(a)(b)(c)")
|
||||||
3
|
==> 3
|
||||||
> (rx->groups #rx"((a)b)")
|
> (rx->groups #rx"((a)b)")
|
||||||
2
|
==> 2
|
||||||
> (rx->groups #rx"(a)*(b)")
|
> (rx->groups #rx"(a)*(b)")
|
||||||
#false
|
==> #false
|
||||||
]
|
]
|
||||||
|
|
||||||
The corresponding elaboration
|
The corresponding elaboration
|
||||||
|
@ -214,28 +205,36 @@ The corresponding elaboration
|
||||||
It also raises syntax errors when an uncompiled regular expression contains
|
It also raises syntax errors when an uncompiled regular expression contains
|
||||||
unmatched parentheses.
|
unmatched parentheses.
|
||||||
|
|
||||||
@todo{fbox}
|
@exact|{
|
||||||
|
\vspace{1mm}
|
||||||
|
\hfill\fbox{$\elabf \in \elab$}
|
||||||
|
\vspace{-4mm}
|
||||||
|
}|
|
||||||
@racketblock[
|
@racketblock[
|
||||||
> (t-regexp '(regexp-match #rx"(a)b" str))
|
> ⟦'(regexp-match #rx"(a)b" str)⟧
|
||||||
'((regexp-match #rx"(a)b" str)
|
==> '((regexp-match #rx"(a)b" str)
|
||||||
:: (U #f (List String String)))
|
:: (U #f (List String String)))
|
||||||
> (t-regexp '(regexp-match "(" str))
|
> ⟦'(regexp-match "(" str)⟧
|
||||||
⊥
|
==> ⊥
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@; =============================================================================
|
@; =============================================================================
|
||||||
@section{Anonymous Functions}
|
@section{Anonymous Functions}
|
||||||
|
|
||||||
By tokenizing symbolic λ-expressions, we can interpret their domain
|
By tokenizing symbolic λ-expressions, we can statically infer their domain.
|
||||||
statically. @todo{fbox} @racket[fun->domain] @exact|{$\in \interp$}|
|
|
||||||
|
|
||||||
|
@exact|{
|
||||||
|
\hfill\fbox{$\RktMeta{fun->domain} \in \interp$}
|
||||||
|
\vspace{-4mm}
|
||||||
|
}|
|
||||||
@racketblock[
|
@racketblock[
|
||||||
> (fun->domain '(λ (x y z) (x (z y) y)))
|
> (fun->domain '(λ (x y z)
|
||||||
'[Any Any Any]
|
(x (z y) y)))
|
||||||
> (fun->domain '(λ ([x : Real] [y : Real]) x))
|
==> '[Any Any Any]
|
||||||
'[Real Real]
|
> (fun->domain '(λ ([x : Real] [y : Real])
|
||||||
|
x))
|
||||||
|
==> '[Real Real]
|
||||||
]
|
]
|
||||||
|
|
||||||
When domain information is available at calls to a @racket[curry] function,
|
When domain information is available at calls to a @racket[curry] function,
|
||||||
|
@ -243,15 +242,15 @@ When domain information is available at calls to a @racket[curry] function,
|
||||||
Conceptually, we give @racket[curry] the unusable type @racket[(⊥ -> ⊤)] and
|
Conceptually, we give @racket[curry] the unusable type @racket[(⊥ -> ⊤)] and
|
||||||
elaboration produces a subtype @racket[curry_i].
|
elaboration produces a subtype @racket[curry_i].
|
||||||
|
|
||||||
@todo{fbox} @exact|{$\in \elab$}|
|
@exact|{
|
||||||
|
\hfill\fbox{$\elabf \in \elab$}
|
||||||
|
\vspace{-4mm}
|
||||||
|
}|
|
||||||
@racketblock[
|
@racketblock[
|
||||||
> ('(curry (λ (x y) x)))
|
> ⟦'(curry (λ (x y) x))⟧
|
||||||
'(curry_2 (λ (x y) x))
|
==> '(curry_2 (λ (x y) x))
|
||||||
]
|
]
|
||||||
|
|
||||||
@;Our implementation generates each @racket[curry_i] at compile-time by folding
|
|
||||||
@; over the interpreted domain.
|
|
||||||
This same technique can be used to implement generalized @racket[map] in
|
This same technique can be used to implement generalized @racket[map] in
|
||||||
languages without variable-arity polymorphism@~cite[stf-esop-2009].
|
languages without variable-arity polymorphism@~cite[stf-esop-2009].
|
||||||
|
|
||||||
|
@ -263,10 +262,16 @@ This same technique can be used to implement generalized @racket[map] in
|
||||||
> (define defendant*
|
> (define defendant*
|
||||||
'("Bush" "Georgia"))
|
'("Bush" "Georgia"))
|
||||||
> (map cite plaintiff* defendant*)
|
> (map cite plaintiff* defendant*)
|
||||||
Rasul v. Bush, U.S.
|
|
||||||
Chisholm v. Georgia, U.S.
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@exact|{
|
||||||
|
\vspace{-1mm}%
|
||||||
|
$\!\!$\evalsto\RktOut{Rasul v. Bush, U.S.}\\
|
||||||
|
$\hphantom{xxxxx}$\RktOut{Chisholm v. Georgia, U.S.}
|
||||||
|
\vspace{1mm}
|
||||||
|
}|
|
||||||
|
|
||||||
|
|
||||||
Leaving out an argument to @racket[printf] or passing an extra list
|
Leaving out an argument to @racket[printf] or passing an extra list
|
||||||
when calling @racket[map] will raise an arity error during elaboration.
|
when calling @racket[map] will raise an arity error during elaboration.
|
||||||
On the other hand, if we modified @racket[cite] to take a third argument
|
On the other hand, if we modified @racket[cite] to take a third argument
|
||||||
|
@ -280,12 +285,15 @@ The identity interpretation @exact{$\RktMeta{id} \in \interp$}
|
||||||
lifts values to the elaboration environment.
|
lifts values to the elaboration environment.
|
||||||
When composed with a filter, we can recognize types of compile-time constants.
|
When composed with a filter, we can recognize types of compile-time constants.
|
||||||
|
|
||||||
@todo{fbox id-int = int}
|
@exact|{
|
||||||
|
\hfill\fbox{$\RktMeta{int?} \circ \RktMeta{id} = \RktMeta{int?} \in \interp$}
|
||||||
|
\vspace{-4mm}
|
||||||
|
}|
|
||||||
@racketblock[
|
@racketblock[
|
||||||
> (int? 2)
|
> (int? 2)
|
||||||
2
|
==> 2
|
||||||
> (int? "~s")
|
> (int? "~s")
|
||||||
#false
|
==> #false
|
||||||
]
|
]
|
||||||
|
|
||||||
Constant-folding versions of arithmetic operators are now easy to define
|
Constant-folding versions of arithmetic operators are now easy to define
|
||||||
|
@ -293,24 +301,34 @@ Constant-folding versions of arithmetic operators are now easy to define
|
||||||
Our implementation re-uses a single fold/elaborate loop to make
|
Our implementation re-uses a single fold/elaborate loop to make
|
||||||
textualist wrappers over @racket[+], @racket[expt] and others.
|
textualist wrappers over @racket[+], @racket[expt] and others.
|
||||||
|
|
||||||
@todo{fbox}
|
@exact|{
|
||||||
|
\vspace{2mm}
|
||||||
|
\hfill\fbox{$\elabf \in \elab$}
|
||||||
|
\vspace{-4mm}
|
||||||
|
}|
|
||||||
@racketblock[
|
@racketblock[
|
||||||
> (define a 3)
|
> (define a ⟦3⟧)
|
||||||
> (define b (/ 1 (- a a)))
|
> (define b ⟦(/ 1 (- a a))⟧)
|
||||||
Error: division by zero
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@exact|{
|
||||||
|
\vspace{-1mm}%
|
||||||
|
$\!\!$\evalsto\RktErr{Error: division by zero}%
|
||||||
|
\vspace{1mm}
|
||||||
|
}|
|
||||||
|
|
||||||
Partial folds also work as expected.
|
Partial folds also work as expected.
|
||||||
|
|
||||||
@racketblock[
|
@racketblock[
|
||||||
> (* 2 3 7 z)
|
> (* 2 3 7 z)
|
||||||
'(* 42 z)
|
==> '(* 42 z)
|
||||||
]
|
]
|
||||||
|
|
||||||
Taken alone, this re-implementation of constant folding in an earlier compiler
|
Taken alone, this re-implementation of constant folding in an earlier compiler
|
||||||
stage is not terribly exciting.
|
stage is not very exciting.
|
||||||
But our arithmetic elaborators cooperate with other elaborators, for example
|
But since folded expressions propagate their result upwards to arbitrary
|
||||||
size-aware vector operations.
|
analyses, we can combine these elaborations with a size-aware vector library to
|
||||||
|
guard against index errors access at computed locations.
|
||||||
|
|
||||||
|
|
||||||
@; =============================================================================
|
@; =============================================================================
|
||||||
|
@ -321,30 +339,40 @@ Fixed-length data structures are often initialized with a constant or
|
||||||
Racket's vectors are one such structure.
|
Racket's vectors are one such structure.
|
||||||
For each built-in vector constructor, we thus define an interpretation:
|
For each built-in vector constructor, we thus define an interpretation:
|
||||||
|
|
||||||
@todo{fbox vector->size in interp}
|
@exact|{
|
||||||
|
\vspace{2mm}
|
||||||
|
\hfill\fbox{$\RktMeta{vector->size} \in \interp$}
|
||||||
|
\vspace{-4mm}
|
||||||
|
}|
|
||||||
@racketblock[
|
@racketblock[
|
||||||
> (vector->size '#(0 1 2))
|
> (vector->size '#(0 1 2))
|
||||||
3
|
==> 3
|
||||||
> (vector->size '(make-vector 100))
|
> (vector->size '(make-vector 100))
|
||||||
100
|
==> 100
|
||||||
> (vector->size '(make-vector (/ 12 3)))
|
> (vector->size '(make-vector (/ 12 3)))
|
||||||
4
|
==> 4
|
||||||
]
|
]
|
||||||
|
|
||||||
After interpreting, we associate the size with the new vector at compile-time.
|
After interpreting, we associate the size with the new vector at compile-time.
|
||||||
Other elaborators can use and propagate these sizes; for instance, we have
|
Other elaborators can use and propagate these sizes; for instance, we have
|
||||||
implemented elaborating layers for thirteen standard vector operations.
|
implemented elaborating layers for 13 standard vector operations.
|
||||||
Together, they constitute a length-aware vector library that serves as a
|
Together, they constitute a length-aware vector library that serves as a
|
||||||
drop-in replacement for existing code.
|
drop-in replacement for existing code.
|
||||||
If size information is missing, the operators default to Typed Racket's behavior.
|
If size information is ever missing, the operators silently default
|
||||||
|
to Typed Racket's behavior.
|
||||||
|
|
||||||
|
@exact|{
|
||||||
|
\vspace{2mm}
|
||||||
|
\hfill\fbox{$\elabf \in \elab$}
|
||||||
|
\vspace{-4mm}
|
||||||
|
}|
|
||||||
@racketblock[
|
@racketblock[
|
||||||
> (vector-ref (make-vector 3) 4)
|
> ⟦(vector-ref (make-vector 3) (+ 2 2))⟧
|
||||||
⊥
|
==> ⊥
|
||||||
> (vector-length (vector-append '#(A B) '#(C D)))
|
> ⟦(vector-length (vector-append '#(A B) '#(C D)))⟧
|
||||||
4
|
==> 4
|
||||||
> (vector-ref (vector-map add1 '#(3 3 3)) 4)
|
> ⟦(vector-ref (vector-map add1 '#(3 3 3)) 0)⟧
|
||||||
(unsafe-ref (vector-map add1 '#(3 3 3)) 4)
|
==> (unsafe-ref (vector-map add1 '#(3 3 3)) 0)
|
||||||
]
|
]
|
||||||
|
|
||||||
For the most part, these elaborations simply manage sizes and
|
For the most part, these elaborations simply manage sizes and
|
||||||
|
@ -355,29 +383,29 @@ We do, however, optimize vector references to unsafe primitives and
|
||||||
|
|
||||||
@; =============================================================================
|
@; =============================================================================
|
||||||
@section[#:tag "sec:sql"]{Database Schema}
|
@section[#:tag "sec:sql"]{Database Schema}
|
||||||
@; db
|
|
||||||
@; TODO Ocaml, Haskell story
|
|
||||||
@; TODO connect to ew-haskell-2012 os-icfp-2008
|
|
||||||
|
|
||||||
Racket's @racket[db] library provides a string-based API for executing SQL
|
Racket's @racket[db] library provides a string-based API for executing SQL
|
||||||
queries.@note{Technically, we use @tt{sql} as an abbreviation for @tt{postgresql}.
|
queries.@note{In this section, we use @tt{sql} as an abbreviation for @tt{postgresql}.}
|
||||||
Although the Racket library supports many database systems, we have only implemented
|
|
||||||
a postgres front-end.}
|
|
||||||
After connecting to a database, SQL queries embedded in strings can be run
|
After connecting to a database, SQL queries embedded in strings can be run
|
||||||
for effects and row values (represented as Racket vectors).
|
to retrieve row values, represented as Racket vectors.
|
||||||
Queries may optionally contain @emph{query parameters}---natural numbers
|
Queries may optionally contain @emph{query parameters}---natural numbers
|
||||||
prefixed by a dollar sign (@tt{$}).
|
prefixed by a dollar sign (@tt{$}).
|
||||||
Arguments substituted for query parameters are guarded against SQL injection.
|
Arguments substituted for query parameters are guarded against SQL injection.
|
||||||
|
|
||||||
@todo{format the multi-line strings}
|
@exact|{
|
||||||
@racketblock[
|
\begin{SCodeFlow}\begin{RktBlk}\begin{SingleColumn}\RktSym{{\Stttextmore}}\mbox{\hphantom{\Scribtexttt{x}}}\RktPn{(}\RktSym{define}\mbox{\hphantom{\Scribtexttt{x}}}\RktSym{C}\mbox{\hphantom{\Scribtexttt{x}}}\RktPn{(}\RktSym{sql{-}connect}\mbox{\hphantom{\Scribtexttt{x}}}\RktPn{\#{\hbox{\texttt{:}}}user}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{"admin"}
|
||||||
> (define C (sql-connect #:user "admin"
|
|
||||||
#:database "SCOTUS"))
|
\mbox{\hphantom{\Scribtexttt{xxxxxxxxxxxxxxxxxxxxxxxxx}}}\RktPn{\#{\hbox{\texttt{:}}}database}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{"SCOTUS"}\RktPn{)}\RktPn{)}
|
||||||
> (query-row C
|
|
||||||
"SELECT plaintiff FROM rulings WHERE name = '$1' LIMIT 1"
|
\RktSym{{\Stttextmore}}\mbox{\hphantom{\Scribtexttt{x}}}\RktPn{(}\RktSym{query{-}row}\mbox{\hphantom{\Scribtexttt{x}}}\RktSym{C}
|
||||||
2001)
|
|
||||||
'#("Kyllo")
|
\mbox{\hphantom{\Scribtexttt{xxxx}}}\RktVal{"SELECT plaintiff FROM rulings}\\
|
||||||
]
|
\mbox{\hphantom{\Scribtexttt{xxxxx}}}\RktVal{WHERE name = {\textquotesingle}\$1{\textquotesingle} LIMIT 1"}
|
||||||
|
|
||||||
|
\mbox{\hphantom{\Scribtexttt{xxxx}}}\RktVal{2001}\RktPn{)}
|
||||||
|
|
||||||
|
\evalsto\RktVal{\#}\RktVal{(}\RktVal{"Kyllo"}\RktVal{)}\end{SingleColumn}\end{RktBlk}\end{SCodeFlow}
|
||||||
|
}|
|
||||||
|
|
||||||
This is a far cry from language-integrated query@~cite[mbb-sigmod-2006] or
|
This is a far cry from language-integrated query@~cite[mbb-sigmod-2006] or
|
||||||
Scala's LMS@~cite[ra-icfp-2015], but the interface
|
Scala's LMS@~cite[ra-icfp-2015], but the interface
|
||||||
|
@ -396,6 +424,7 @@ The situation worsens if the programmer uses multiple database connections.
|
||||||
One can either alias one query function to multiple identifiers (each with a specific type)
|
One can either alias one query function to multiple identifiers (each with a specific type)
|
||||||
or weaken type signatures and manually type-cast query results.
|
or weaken type signatures and manually type-cast query results.
|
||||||
|
|
||||||
|
@subsection{Phantom Types To the Rescue}
|
||||||
By associating a database schema with each connection, our elaboration technique
|
By associating a database schema with each connection, our elaboration technique
|
||||||
can provide a uniform solution to these issues.
|
can provide a uniform solution to these issues.
|
||||||
We specialize both the input and output of calls to @racket[query-row],
|
We specialize both the input and output of calls to @racket[query-row],
|
||||||
|
@ -404,16 +433,22 @@ We specialize both the input and output of calls to @racket[query-row],
|
||||||
Our solution, however, is not entirely annotation-free.
|
Our solution, however, is not entirely annotation-free.
|
||||||
We need a schema representing the target database; for this, we ask
|
We need a schema representing the target database; for this, we ask
|
||||||
the programmer to supply an S-expression of symbols and types
|
the programmer to supply an S-expression of symbols and types
|
||||||
that passes a @exact{$\RktMeta{schema?} \in \interp$} predicate.
|
that passes a @racket[schema?] predicate.
|
||||||
|
This approach is similar to phantom types@~cite[lm-dsl-1999].
|
||||||
@; (@racket[schema?]@exact{$\,\circ\,$}@racket[id]) @exact{$\in \interp$}
|
|
||||||
|
|
||||||
|
@exact|{
|
||||||
|
\vspace{1mm}
|
||||||
|
\hfill\fbox{$\RktMeta{schema?} \in \interp$}
|
||||||
|
\vspace{-4mm}
|
||||||
|
}|
|
||||||
@racketblock[
|
@racketblock[
|
||||||
> (define scotus-schema
|
> (define scotus-schema
|
||||||
'([decisions [(id . Natural)
|
'([decisions [(id . Natural)
|
||||||
(plaintiff . String)
|
(plaintiff . String)
|
||||||
(defendant . String)
|
(defendant . String)
|
||||||
(year . Natural)]]))
|
(year . Natural)]]))
|
||||||
|
> (schema? scotus-schema)
|
||||||
|
==> '([decisions ....])
|
||||||
]
|
]
|
||||||
|
|
||||||
The above schema represents a database with at least one table, called @racket[decisions],
|
The above schema represents a database with at least one table, called @racket[decisions],
|
||||||
|
@ -426,33 +461,46 @@ In addition to the @exact{$\RktMeta{schema?}$} predicate, we define one more
|
||||||
The first elaboration is for connecting to a database.
|
The first elaboration is for connecting to a database.
|
||||||
We require a statically-known schema object and elaborate to a normal connection.
|
We require a statically-known schema object and elaborate to a normal connection.
|
||||||
|
|
||||||
@exact{$\RktMeta{sql-connect} \in \elab$}
|
@exact|{
|
||||||
|
\vspace{1mm}
|
||||||
|
\hfill\fbox{$\elabf \in \elab$}
|
||||||
|
\vspace{-4mm}
|
||||||
|
}|
|
||||||
@racketblock[
|
@racketblock[
|
||||||
> (sc '(sql-connect #:user "admin"
|
> ⟦'(sql-connect #:user "admin"
|
||||||
#:database "SCOTUS"))
|
#:database "SCOTUS")⟧
|
||||||
⊥
|
==> ⊥
|
||||||
> (sc '(sql-connect scotus-schema
|
> ⟦'(sql-connect scotus-schema
|
||||||
#:user "admin"
|
#:user "admin"
|
||||||
#:database "SCOTUS"))
|
#:database "SCOTUS")⟧
|
||||||
'(sql-connect #:user "admin"
|
==> '(sql-connect #:user "admin"
|
||||||
#:database "SCOTUS")
|
#:database "SCOTUS")
|
||||||
]
|
]
|
||||||
|
|
||||||
The next interpretation and elaboration are for reading constraints from
|
The next interpretation and elaboration are for reading constraints from
|
||||||
query strings.
|
query strings.
|
||||||
We parse @tt{SELECT} statements and extract
|
We parse @tt{SELECT} statements using @racket[sql->constr] and extract
|
||||||
@itemlist[
|
@itemlist[
|
||||||
@item{the names of selected columns,}
|
@item{the names of selected columns,}
|
||||||
@item{the table name, and}
|
@item{the table name, and}
|
||||||
@item{an association from query parameters to column names.}
|
@item{an association from query parameters to column names.}
|
||||||
]
|
]
|
||||||
@todo{fbox}
|
|
||||||
@racketblock[
|
@exact|{
|
||||||
> "SELECT defendant FROM decisions WHERE plaintiff = '$1'"
|
\vspace{1mm}
|
||||||
'[(defendant) decisions ($1 . plaintiff)]
|
\hfill\fbox{$\RktMeta{sql->constr} \in \interp$}
|
||||||
> "SELECT * FROM loans"
|
\vspace{-4mm}
|
||||||
'[* decisions ()]
|
|
||||||
]
|
\begin{SCodeFlow}\begin{RktBlk}\begin{SingleColumn}
|
||||||
|
\RktSym{{\Stttextmore}}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{"SELECT defendant FROM decisions}\\
|
||||||
|
\mbox{\hphantom{\Scribtexttt{xxxx}}}\RktVal{WHERE plaintiff = {\textquotesingle}\$1{\textquotesingle}"}
|
||||||
|
|
||||||
|
\RktSym{=={\Stttextmore}}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{{\textquotesingle}}\RktVal{[}\RktVal{(}\RktVal{defendant}\RktVal{)}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{decisions}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{(}\RktVal{\$1}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{{\hbox{\texttt{.}}} }\RktVal{plaintiff}\RktVal{)}\RktVal{]}
|
||||||
|
|
||||||
|
\RktSym{{\Stttextmore}}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{"SELECT * FROM loans"}
|
||||||
|
|
||||||
|
\RktSym{=={\Stttextmore}}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{{\textquotesingle}}\RktVal{[}\RktVal{*}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{decisions}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{(}\RktVal{)}\RktVal{]}\end{SingleColumn}\end{RktBlk}\end{SCodeFlow}
|
||||||
|
}|
|
||||||
|
|
||||||
The schema, connection, and query constraints now come together in elaborations
|
The schema, connection, and query constraints now come together in elaborations
|
||||||
such as @exact{$\RktMeta{query-exec} \in \elab$}.
|
such as @exact{$\RktMeta{query-exec} \in \elab$}.
|
||||||
|
@ -460,24 +508,46 @@ There is still a non-trivial amount of work to be done resolving wildcards and
|
||||||
validating row names before the type-annotated result is produced,
|
validating row names before the type-annotated result is produced,
|
||||||
but all the necessary information is available, statically.
|
but all the necessary information is available, statically.
|
||||||
|
|
||||||
@racketblock[
|
@exact|{
|
||||||
> (t '(query-row C
|
\vspace{1mm}
|
||||||
"SELECT plaintiff FROM decisions WHERE year = '$1' LIMIT 1"
|
\hfill\fbox{$\elabf \in \elab$}
|
||||||
2006))
|
\vspace{-4mm}
|
||||||
'((query-row C
|
\begin{SCodeFlow}\begin{RktBlk}\begin{SingleColumn}\RktSym{{\Stttextmore}}\mbox{\hphantom{\Scribtexttt{x}}}\RktSym{$[\![$}\RktVal{{\textquotesingle}}\RktVal{(}\RktVal{query{-}row}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{C}
|
||||||
"SELECT ..."
|
|
||||||
(2006 : Natural))
|
\mbox{\hphantom{\Scribtexttt{xxxxxx}}}\RktVal{"SELECT plaintiff FROM decisions}\\
|
||||||
:: (Vector String))
|
\mbox{\hphantom{\Scribtexttt{xxxxxxx}}}\RktVal{WHERE year = {\textquotesingle}\$1{\textquotesingle} LIMIT 1"}
|
||||||
> (t '(query-row C
|
|
||||||
"SELECT * FROM decisions WHERE plaintiff = '$1' LIMIT 1"
|
\mbox{\hphantom{\Scribtexttt{xxxxx}}}\RktVal{2006}\RktVal{)}\RktSym{$]\!]$}
|
||||||
"United States"))
|
|
||||||
'((query-row C
|
\RktSym{=={\Stttextmore}}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{{\textquotesingle}}\RktVal{(}\RktVal{(}\RktVal{query{-}row}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{C}
|
||||||
"SELECT ..."
|
|
||||||
("United States" : String))
|
\mbox{\hphantom{\Scribtexttt{xxxxxxxx}}}\RktVal{"SELECT {\hbox{\texttt{.}}}{\hbox{\texttt{.}}}{\hbox{\texttt{.}}}{\hbox{\texttt{.}}}"}
|
||||||
:: (Vector Natural String String Natural))
|
|
||||||
> (t '(query-row C "SELECT foo FROM decisions"))
|
\mbox{\hphantom{\Scribtexttt{xxxxxxxx}}}\RktVal{(}\RktVal{2006}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{{\hbox{\texttt{:}}}}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{Natural}\RktVal{)}\RktVal{)}
|
||||||
⊥
|
|
||||||
]
|
\mbox{\hphantom{\Scribtexttt{xxxxxx}}}\RktVal{{\hbox{\texttt{:}}}{\hbox{\texttt{:}}}}\mbox{\hphantom{\Scribtexttt{xxx}}}\RktVal{(}\RktVal{Vector}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{String}\RktVal{)}\RktVal{)}
|
||||||
|
\\
|
||||||
|
\\
|
||||||
|
\RktSym{{\Stttextmore}}\mbox{\hphantom{\Scribtexttt{x}}}\RktSym{$[\![$}\RktVal{{\textquotesingle}}\RktVal{(}\RktVal{query{-}row}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{C}
|
||||||
|
|
||||||
|
\mbox{\hphantom{\Scribtexttt{xxxxxx}}}\RktVal{"SELECT * FROM decisions}\\
|
||||||
|
\mbox{\hphantom{\Scribtexttt{xxxxxxx}}}\RktVal{WHERE plaintiff = {\textquotesingle}\$1{\textquotesingle} LIMIT 1"}
|
||||||
|
|
||||||
|
\mbox{\hphantom{\Scribtexttt{xxxxxxxx}}}\RktVal{"United States"}\RktVal{)}\RktSym{$]\!]$}
|
||||||
|
|
||||||
|
\RktSym{=={\Stttextmore}}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{{\textquotesingle}}\RktVal{(}\RktVal{(}\RktVal{query{-}row}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{C}
|
||||||
|
|
||||||
|
\mbox{\hphantom{\Scribtexttt{xxxxxxxx}}}\RktVal{"SELECT {\hbox{\texttt{.}}}{\hbox{\texttt{.}}}{\hbox{\texttt{.}}}"}
|
||||||
|
|
||||||
|
\mbox{\hphantom{\Scribtexttt{xxxxxxxx}}}\RktVal{(}\RktVal{"United States"}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{{\hbox{\texttt{:}}}}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{String}\RktVal{)}\RktVal{)}
|
||||||
|
|
||||||
|
\mbox{\hphantom{\Scribtexttt{xxxxxx}}}\RktVal{{\hbox{\texttt{:}}}{\hbox{\texttt{:}}}}\mbox{\hphantom{\Scribtexttt{xxx}}}\RktVal{(}\RktVal{Vector}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{Natural}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{String}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{String}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{Natural}\RktVal{)}\RktVal{)}
|
||||||
|
\\
|
||||||
|
\\
|
||||||
|
\RktSym{{\Stttextmore}}\mbox{\hphantom{\Scribtexttt{x}}}\RktSym{$[\![$}\RktVal{{\textquotesingle}}\RktVal{(}\RktVal{query{-}row}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{C}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{"SELECT foo FROM decisions"}\RktVal{)}\RktSym{$]\!]$}
|
||||||
|
|
||||||
|
\RktSym{=={\Stttextmore}}\mbox{\hphantom{\Scribtexttt{x}}}\RktSym{$\perp$}\end{SingleColumn}\end{RktBlk}\end{SCodeFlow}
|
||||||
|
}|
|
||||||
|
|
||||||
Results produced by @racket[query-row] are vectors with a known length;
|
Results produced by @racket[query-row] are vectors with a known length;
|
||||||
as such they cooperate with our library of vector operations described in
|
as such they cooperate with our library of vector operations described in
|
||||||
|
|
Loading…
Reference in New Issue
Block a user