WIP on rich return types. More complex than it seems.
This commit is contained in:
parent
575ea6bd98
commit
713b637fbc
|
@ -49,27 +49,28 @@
|
|||
(for-syntax syntax/parse))
|
||||
|
||||
(define-graph/multi-ctor gm ([a [b1 : b] [b2 : b] [s : String] [v : Number]]
|
||||
[b [a1 : a] [s : String] [v : Number]])
|
||||
[(r [v : Integer] [w : String])
|
||||
: a
|
||||
(printf "r ~a ~a\n" v w)
|
||||
(a (bx (if (> v 0) (sub1 v) (string-length w)))
|
||||
(by (if (> v 0) (sub1 v) (string-length w)) "xyz")
|
||||
w
|
||||
v)]
|
||||
[(bx [v : Integer])
|
||||
: b
|
||||
(printf "bx ~a\n" v)
|
||||
(b (r v "one") "x" v)]
|
||||
[(by [v : Integer] [w : String])
|
||||
: b
|
||||
(printf "by ~a ~a\n" v w)
|
||||
(b (r v "two") "y" (+ v (string-length w)))])
|
||||
[b [a1 : a] [s : String] [v : Number]])
|
||||
[(r [v : Integer] [w : String])
|
||||
: a
|
||||
(printf "r ~a ~a\n" v w)
|
||||
(a (bx (if (> v 0) (sub1 v) (string-length w)))
|
||||
(by (if (> v 0) (sub1 v) (string-length w)) "xyz")
|
||||
w
|
||||
v)]
|
||||
[(bx [v : Integer])
|
||||
: b
|
||||
(printf "bx ~a\n" v)
|
||||
(b (r v "one") "x" v)]
|
||||
[(by [v : Integer] [w : String])
|
||||
: b
|
||||
(printf "by ~a ~a\n" v w)
|
||||
(b (r v "two") "y" (+ v (string-length w)))])
|
||||
|
||||
(define gmi (gm 3 "b"))
|
||||
(check-equal?: (get gmi v) 3)
|
||||
(check-equal?: (get gmi b1 v) 2)
|
||||
(check-equal?: (get gmi b1 s) "x")
|
||||
(check-equal?: (get gmi b1 a1 v) 2)
|
||||
|
||||
;(check-equal?: (get gmi b1 a1 b1 a1 v) 1)
|
||||
;(check-equal?: (get gmi b1 a1 b1 a1 b1 v) 1)
|
||||
|
|
|
@ -101,6 +101,7 @@ plain list.
|
|||
@chunk[<graph-rich-return>
|
||||
(define-syntax/parse <signature>
|
||||
(define-temp-ids "first-step" name)
|
||||
(define-temp-ids "first-step-expander2" name)
|
||||
(define-temp-ids "~a/simple-mapping" (node …))
|
||||
(define-temp-ids "~a/node" (mapping …))
|
||||
(template
|
||||
|
@ -126,15 +127,30 @@ encapsulating the result types of mappings.
|
|||
@chunk[<first-pass-type-expander>
|
||||
(define-type-expander (~> stx)
|
||||
(syntax-parse stx
|
||||
[(_ (~literal mapping))
|
||||
[(_ (~datum mapping)) ;; TODO: should be ~literal
|
||||
(template
|
||||
(U (first-step #:placeholder mapping/node)
|
||||
(tmpl-replace-in-type result-type
|
||||
[node (first-step #:placeholder node)]
|
||||
…)))]
|
||||
…))]
|
||||
…
|
||||
;; TODO: should fall-back to outer definition of ~>, if any.
|
||||
))
|
||||
(define-type-expander (first-step-expander2 stx)
|
||||
(syntax-parse stx
|
||||
[(_ (~datum mapping)) ;; TODO: should be ~literal
|
||||
(template
|
||||
(U (first-step #:placeholder mapping/node)
|
||||
(tmpl-replace-in-type result-type
|
||||
[node (first-step #:placeholder node)]
|
||||
…)))]
|
||||
…
|
||||
;; TODO: should fall-back to outer definition of ~>, if any.
|
||||
)
|
||||
#;(U (first-step #:placeholder m-streets4/node)
|
||||
(Listof (first-step #:placeholder Street))))]
|
||||
|
||||
@; TODO: replace-in-type doesn't work well here, we need to define a
|
||||
@; TODO: replace-in-type doesn't work wfell here, we need to define a
|
||||
@; type-expander.
|
||||
@chunk[<first-pass-field-type>
|
||||
(tmpl-replace-in-type field-type
|
||||
|
@ -237,27 +253,37 @@ encapsulating the result types of mappings.
|
|||
(Street Street2/simple-mapping))
|
||||
(map Street snames)))))))|#
|
||||
|
||||
(begin
|
||||
#;(begin
|
||||
(define-graph
|
||||
first-step
|
||||
#:definitions
|
||||
((define-type-expander
|
||||
(~> stx)
|
||||
(syntax-parse stx
|
||||
((_ (~literal m-cities))
|
||||
((_ (~datum m-cities));(~literal m-cities))
|
||||
(template (U
|
||||
(first-step #:placeholder m-cities3/node)
|
||||
(tmpl-replace-in-type
|
||||
(Listof City)
|
||||
(City (first-step #:placeholder City))
|
||||
(Street (first-step #:placeholder Street))))))
|
||||
((_ (~literal m-streets))
|
||||
((_ (~datum m-streets));(~literal m-streets))
|
||||
(template (U
|
||||
(first-step #:placeholder m-streets4/node)
|
||||
(tmpl-replace-in-type
|
||||
(Listof Street)
|
||||
(City (first-step #:placeholder City))
|
||||
(Street (first-step #:placeholder Street)))))))))
|
||||
(Street (first-step #:placeholder Street))))))))
|
||||
(define-type-expander
|
||||
(~~> stx)
|
||||
(template (U
|
||||
(first-step #:placeholder m-streets4/node)
|
||||
(tmpl-replace-in-type
|
||||
(Listof Street)
|
||||
(City (first-step #:placeholder City))
|
||||
(Street (first-step #:placeholder Street)))))
|
||||
#;#'(U (first-step #:placeholder m-streets4/node)
|
||||
(Listof (first-step #:placeholder Street)))))
|
||||
#|
|
||||
(City [foo : Number] ((m1) (City 1)))
|
||||
(Street [foo : Number] ((m2) (Street 2)))
|
||||
|
@ -269,9 +295,9 @@ encapsulating the result types of mappings.
|
|||
(City
|
||||
(streets : (U m-streets4/node (Listof Street)))
|
||||
((City1/simple-mapping
|
||||
(streets : #|(~> m-streets)|#
|
||||
(U (first-step #:placeholder m-streets4/node)
|
||||
(Listof (first-step #:placeholder Street)))
|
||||
(streets : (~> m-streets);(Let [~> ~~>] (~> m-streets))
|
||||
#|(U (first-step #:placeholder m-streets4/node)
|
||||
(Listof (first-step #:placeholder Street)))|#
|
||||
))
|
||||
(City streets)))
|
||||
(Street
|
||||
|
@ -327,6 +353,140 @@ encapsulating the result types of mappings.
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
(begin
|
||||
(define-graph
|
||||
first-step
|
||||
#:definitions
|
||||
((define-type-expander
|
||||
(~> stx)
|
||||
(syntax-parse
|
||||
stx
|
||||
((_ (~datum m-cities))
|
||||
(template
|
||||
(U
|
||||
(first-step #:placeholder m-cities3/node)
|
||||
(Listof (first-step #:placeholder City)))))
|
||||
((_ (~datum m-streets))
|
||||
(template
|
||||
(U
|
||||
(first-step #:placeholder m-streets4/node)
|
||||
(Listof (first-step #:placeholder Street)))))))
|
||||
#;(define-type-expander
|
||||
(first-step-expander2 stx)
|
||||
(syntax-parse
|
||||
stx
|
||||
((_ (~literal m-cities))
|
||||
(template
|
||||
(U
|
||||
(first-step #:placeholder m-cities3/node)
|
||||
(Listof (first-step #:placeholder City)))))
|
||||
((_ (~literal m-streets))
|
||||
(template
|
||||
(U
|
||||
(first-step #:placeholder m-streets4/node)
|
||||
(Listof (first-step #:placeholder Street)))))))
|
||||
(define-type-expander
|
||||
(~~> stx)
|
||||
#;(template (U
|
||||
(first-step #:placeholder m-streets4/node)
|
||||
(tmpl-replace-in-type
|
||||
(Listof Street)
|
||||
(City (first-step #:placeholder City))
|
||||
(Street (first-step #:placeholder Street)))))
|
||||
#'(U m-streets4/node (Listof Street))))
|
||||
(City
|
||||
(streets : (Let [~> ~~>] (~> m-streets))#;(~> m-streets))
|
||||
((City1/simple-mapping (streets : (~> m-streets))) (City streets)))
|
||||
(Street
|
||||
(sname : String)
|
||||
((Street2/simple-mapping (sname : String)) (Street sname)))
|
||||
(m-cities3/node
|
||||
(returned : (Listof City))
|
||||
((m-cities (cnames : (Listof (Listof String))))
|
||||
(m-cities3/node
|
||||
(let ((City City1/simple-mapping) (Street Street2/simple-mapping))
|
||||
(define (strings→city (s : (Listof String))) (City (m-streets s)))
|
||||
(map strings→city cnames)))))
|
||||
(m-streets4/node
|
||||
(returned : (Listof Street))
|
||||
((m-streets (snames : (Listof String)))
|
||||
(m-streets4/node
|
||||
(let ((City City1/simple-mapping) (Street Street2/simple-mapping))
|
||||
(map Street snames)))))))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
120
graph-lib/graph/graph-aliasing.lp2.rkt
Normal file
120
graph-lib/graph/graph-aliasing.lp2.rkt
Normal file
|
@ -0,0 +1,120 @@
|
|||
#lang scribble/lp2
|
||||
@(require "../lib/doc.rkt")
|
||||
@doc-lib-setup
|
||||
|
||||
@title[#:style manual-doc-style]{Type and constructor
|
||||
aliases in graph declarations}
|
||||
|
||||
@(table-of-contents)
|
||||
|
||||
@section{Introduction}
|
||||
|
||||
When declaring a graph, the names of its nodes and mappings
|
||||
as well as those of the graph it is based on may collide. We
|
||||
try here to provide reasonnable defaults indicating which
|
||||
name should refer to what at each point.
|
||||
|
||||
@chunk[<example>
|
||||
(graph g-old
|
||||
[City [streets : (Listof Street)]]
|
||||
[Street [name : String]]
|
||||
mappings…)
|
||||
(pass g-old → g-new
|
||||
([City [streets : (Listof Street)] [nstreets : Index]]
|
||||
[Street [name : String]])
|
||||
(m-city ([g g-old.City]) : City
|
||||
(City g.streets (length g.streets))))]
|
||||
|
||||
Capitalization aside, the name @tc[city] could refer to seven different things:
|
||||
@itemlist[
|
||||
@item{The @racket[g-old.city] type}
|
||||
@item{The incomplete @racket[g-new.city] type}
|
||||
@item{The placeholder @racket[g-new.city] type}
|
||||
@item{The @racket[g-new.city] type, but most of the time this one should be
|
||||
needed only outside the graph declaration}
|
||||
@item{The @racket[city] constructor, returning an incomplete node}
|
||||
@item{The @racket[city] mapping, returning a placeholder}
|
||||
@item{A @racket[city] field, but this one is not a problem, since it will
|
||||
always be accessed via @racket[some-node-instance.city]}
|
||||
@item{The return type of the @racket[city] mapping, as in @racket[~> city]}]
|
||||
|
||||
Furthermore, the @racket[city] constructor should accept several cases for
|
||||
@tc[street], when giving the list of values for the @tc[streets] field:
|
||||
@itemlist[
|
||||
@item{A placeholder for @racket[street]}
|
||||
@item{An incomplete @racket[street]}
|
||||
@item{A @racket[g-old.street], which it will convert to the new type using the
|
||||
implicit mapping}]
|
||||
|
||||
In the field types, we have one case:
|
||||
@itemlist[
|
||||
@item{The @racket[street] name, for example, should refer
|
||||
to the with-promises type of the new graph @racket[g-new],
|
||||
once the graph is fully constructed. When declaring the incomplete type for
|
||||
@racket[city], @racket[street] will refer to the incomplete @racket[street],
|
||||
but this is happening behind the scenes, and shouldn't cause any ambiguity.}]
|
||||
|
||||
In the mapping declaration, we have four cases:
|
||||
@itemlist[
|
||||
@item{Return type: this should obviously refer to the name
|
||||
of the new node type (incomplete or placeholder).}
|
||||
@item{Parameter type: it would be tempting to make node names there refer to
|
||||
old node types. However, passing around placeholders and incomplete nodes then
|
||||
becomes difficult.}
|
||||
@item{Body, used as a function: inside the body, a node name should refer to
|
||||
the constructor for the new node type, returning a placeholder.}
|
||||
@item{Body, used as a type. A case where this could happen is when declaring an
|
||||
inner function. The case isn't clear here, as the function could return an
|
||||
incomplete node, or a placeholder. The same goes for the parameter type, or
|
||||
the type of variables bound by let.}]
|
||||
|
||||
The type and constructor aspects are independant, as the
|
||||
same identifier can be used both as a type and as a function
|
||||
without ambiguity. It would however be more intuitive if the
|
||||
return type of @tc[city] when used as a function was a
|
||||
subtype of what @tc[city] expands to when used as a type, so
|
||||
that @tc[(ann (city x y) city)] is always valid.
|
||||
|
||||
It is important to note that once constructed, incomplete nodes can be made
|
||||
opaque without loss of functionality. In other words, we are free to use
|
||||
@tc[(U incomplete placeholder)] as the type for all constructed nodes.
|
||||
|
||||
We could therefore use @tc[(U incomplete placeholder)] everywhere, except for
|
||||
the parameters, where we need to access the old graph types, which may conflict
|
||||
with the new ones.
|
||||
|
||||
When there is a single mapping for the node, we have, schematically:
|
||||
|
||||
@chunk[<single-mapping>
|
||||
(g-old.city → g-new.city
|
||||
(begin …
|
||||
(city x y)
|
||||
(bar other-old-city)))]
|
||||
|
||||
Where @tc[bar] is the constructor for another node taking a city for one of its
|
||||
fields (here it will auto-call the mapping).
|
||||
|
||||
@section{Conclusion}
|
||||
|
||||
The solution we propose is to use @tc[(U incomplete placeholder)] everywhere for
|
||||
the types, and disambiguate the old types in the parameters with @tc[old.city].
|
||||
When used as a function, the name should refer to the constructor. We do not
|
||||
have to worry about calling auto-defined mappings, as the constructors should
|
||||
accept the old nodes, and convert them behind the scenes.
|
||||
|
||||
The only problem that remains, is when a user-defined mapping has the same name
|
||||
as a node name, and has more than one argument (or doesn't accept a single old
|
||||
node). This is probably something we can cope with, simply rejecting programs
|
||||
that trigger this case, and request that the programmer uses different names for
|
||||
the mapping and node.
|
||||
|
||||
@subsection{Shadowing}
|
||||
|
||||
We want to shadow the old @tc[city] type everywhere inside the graph
|
||||
declaration. Otherwise this will lead to inconsistencies, inside an inner
|
||||
definition for example. We do not want however the name of the nodes to leak
|
||||
outside as definitions, as this would conflict with other graphs having the same
|
||||
node names.
|
||||
|
||||
@chunk[<*>
|
||||
(begin)]
|
|
@ -325,7 +325,7 @@ arguments, tagged with the @tc[node]'s name):
|
|||
@; TODO: maybe replace node types with placeholder types
|
||||
|
||||
@chunk[<define-placeholder-type>
|
||||
(struct (A) node/placeholder-struct ([f : A]))
|
||||
(struct (A) node/placeholder-struct ([f : A]) #:transparent)
|
||||
(define-type node/placeholder-type
|
||||
(node/placeholder-struct (List param-type …)))]
|
||||
|
||||
|
@ -351,7 +351,7 @@ indicates at which index in the queue's results the successor can be found.
|
|||
@; TODO: use a type-expander here, instead of a template metafunction.
|
||||
|
||||
@CHUNK[<define-with-indices>
|
||||
(struct node/index-type ([i : Index]))
|
||||
(struct node/index-type ([i : Index]) #:transparent)
|
||||
|
||||
(define-type node/with-indices-type
|
||||
(List 'node/with-indices-tag <field/with-indices-type> …))
|
||||
|
|
|
@ -151,7 +151,9 @@ else.
|
|||
#,(expand-type #'T (bind-type-vars #'(TVar ...) env)))]
|
||||
[((~literal Rec) R:id T:expr)
|
||||
#`(Rec R #,(expand-type #'T (bind-type-vars #'(R) env)))]
|
||||
[((~literal Let) [V:id E:id] T:expr)
|
||||
[((~datum Let) [V:id E:id] T:expr);; TODO: ~literal instead of ~datum
|
||||
;; TODO: ~commit when we find Let, so that syntax errors are not
|
||||
;; interpreted as an arbitrary call.
|
||||
;; TODO : for now we only allow aliasing (which means E is an id),
|
||||
;; not on-the-fly declaration of type expanders. This would require
|
||||
;; us to (expand) them.
|
||||
|
|
Loading…
Reference in New Issue
Block a user