WIP on rich return types. More complex than it seems.
This commit is contained in:
parent
575ea6bd98
commit
713b637fbc
|
@ -71,5 +71,6 @@
|
||||||
(check-equal?: (get gmi b1 v) 2)
|
(check-equal?: (get gmi b1 v) 2)
|
||||||
(check-equal?: (get gmi b1 s) "x")
|
(check-equal?: (get gmi b1 s) "x")
|
||||||
(check-equal?: (get gmi b1 a1 v) 2)
|
(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 v) 1)
|
||||||
;(check-equal?: (get gmi b1 a1 b1 a1 b1 v) 1)
|
;(check-equal?: (get gmi b1 a1 b1 a1 b1 v) 1)
|
||||||
|
|
|
@ -101,6 +101,7 @@ plain list.
|
||||||
@chunk[<graph-rich-return>
|
@chunk[<graph-rich-return>
|
||||||
(define-syntax/parse <signature>
|
(define-syntax/parse <signature>
|
||||||
(define-temp-ids "first-step" name)
|
(define-temp-ids "first-step" name)
|
||||||
|
(define-temp-ids "first-step-expander2" name)
|
||||||
(define-temp-ids "~a/simple-mapping" (node …))
|
(define-temp-ids "~a/simple-mapping" (node …))
|
||||||
(define-temp-ids "~a/node" (mapping …))
|
(define-temp-ids "~a/node" (mapping …))
|
||||||
(template
|
(template
|
||||||
|
@ -126,15 +127,30 @@ encapsulating the result types of mappings.
|
||||||
@chunk[<first-pass-type-expander>
|
@chunk[<first-pass-type-expander>
|
||||||
(define-type-expander (~> stx)
|
(define-type-expander (~> stx)
|
||||||
(syntax-parse stx
|
(syntax-parse stx
|
||||||
[(_ (~literal mapping))
|
[(_ (~datum mapping)) ;; TODO: should be ~literal
|
||||||
(template
|
(template
|
||||||
(U (first-step #:placeholder mapping/node)
|
(U (first-step #:placeholder mapping/node)
|
||||||
(tmpl-replace-in-type result-type
|
(tmpl-replace-in-type result-type
|
||||||
[node (first-step #:placeholder node)]
|
[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.
|
@; type-expander.
|
||||||
@chunk[<first-pass-field-type>
|
@chunk[<first-pass-field-type>
|
||||||
(tmpl-replace-in-type field-type
|
(tmpl-replace-in-type field-type
|
||||||
|
@ -237,27 +253,37 @@ encapsulating the result types of mappings.
|
||||||
(Street Street2/simple-mapping))
|
(Street Street2/simple-mapping))
|
||||||
(map Street snames)))))))|#
|
(map Street snames)))))))|#
|
||||||
|
|
||||||
(begin
|
#;(begin
|
||||||
(define-graph
|
(define-graph
|
||||||
first-step
|
first-step
|
||||||
#:definitions
|
#:definitions
|
||||||
((define-type-expander
|
((define-type-expander
|
||||||
(~> stx)
|
(~> stx)
|
||||||
(syntax-parse stx
|
(syntax-parse stx
|
||||||
((_ (~literal m-cities))
|
((_ (~datum m-cities));(~literal m-cities))
|
||||||
(template (U
|
(template (U
|
||||||
(first-step #:placeholder m-cities3/node)
|
(first-step #:placeholder m-cities3/node)
|
||||||
(tmpl-replace-in-type
|
(tmpl-replace-in-type
|
||||||
(Listof City)
|
(Listof City)
|
||||||
(City (first-step #:placeholder City))
|
(City (first-step #:placeholder City))
|
||||||
(Street (first-step #:placeholder Street))))))
|
(Street (first-step #:placeholder Street))))))
|
||||||
((_ (~literal m-streets))
|
((_ (~datum m-streets));(~literal m-streets))
|
||||||
(template (U
|
(template (U
|
||||||
(first-step #:placeholder m-streets4/node)
|
(first-step #:placeholder m-streets4/node)
|
||||||
(tmpl-replace-in-type
|
(tmpl-replace-in-type
|
||||||
(Listof Street)
|
(Listof Street)
|
||||||
(City (first-step #:placeholder City))
|
(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)))
|
(City [foo : Number] ((m1) (City 1)))
|
||||||
(Street [foo : Number] ((m2) (Street 2)))
|
(Street [foo : Number] ((m2) (Street 2)))
|
||||||
|
@ -269,9 +295,9 @@ encapsulating the result types of mappings.
|
||||||
(City
|
(City
|
||||||
(streets : (U m-streets4/node (Listof Street)))
|
(streets : (U m-streets4/node (Listof Street)))
|
||||||
((City1/simple-mapping
|
((City1/simple-mapping
|
||||||
(streets : #|(~> m-streets)|#
|
(streets : (~> m-streets);(Let [~> ~~>] (~> m-streets))
|
||||||
(U (first-step #:placeholder m-streets4/node)
|
#|(U (first-step #:placeholder m-streets4/node)
|
||||||
(Listof (first-step #:placeholder Street)))
|
(Listof (first-step #:placeholder Street)))|#
|
||||||
))
|
))
|
||||||
(City streets)))
|
(City streets)))
|
||||||
(Street
|
(Street
|
||||||
|
@ -331,6 +357,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)))))))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<graph-rich-return>)]
|
<graph-rich-return>)]
|
||||||
|
|
||||||
@chunk[<module-test>
|
@chunk[<module-test>
|
||||||
|
|
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
|
@; TODO: maybe replace node types with placeholder types
|
||||||
|
|
||||||
@chunk[<define-placeholder-type>
|
@chunk[<define-placeholder-type>
|
||||||
(struct (A) node/placeholder-struct ([f : A]))
|
(struct (A) node/placeholder-struct ([f : A]) #:transparent)
|
||||||
(define-type node/placeholder-type
|
(define-type node/placeholder-type
|
||||||
(node/placeholder-struct (List param-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.
|
@; TODO: use a type-expander here, instead of a template metafunction.
|
||||||
|
|
||||||
@CHUNK[<define-with-indices>
|
@CHUNK[<define-with-indices>
|
||||||
(struct node/index-type ([i : Index]))
|
(struct node/index-type ([i : Index]) #:transparent)
|
||||||
|
|
||||||
(define-type node/with-indices-type
|
(define-type node/with-indices-type
|
||||||
(List 'node/with-indices-tag <field/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)))]
|
#,(expand-type #'T (bind-type-vars #'(TVar ...) env)))]
|
||||||
[((~literal Rec) R:id T:expr)
|
[((~literal Rec) R:id T:expr)
|
||||||
#`(Rec R #,(expand-type #'T (bind-type-vars #'(R) env)))]
|
#`(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),
|
;; TODO : for now we only allow aliasing (which means E is an id),
|
||||||
;; not on-the-fly declaration of type expanders. This would require
|
;; not on-the-fly declaration of type expanders. This would require
|
||||||
;; us to (expand) them.
|
;; us to (expand) them.
|
||||||
|
|
Loading…
Reference in New Issue
Block a user