Revert "Notes about the various failures."
This reverts commit 1743dd0e04
.
This commit is contained in:
parent
094fb14b00
commit
e7b9e41c98
|
@ -1,42 +0,0 @@
|
|||
#lang typed/racket
|
||||
|
||||
(require "graph-6-rich-returns.delta-introducer.lp2.rkt"
|
||||
(except-in "../lib/low.rkt" ~>)
|
||||
"graph.lp2.rkt"
|
||||
"get.lp2.rkt"
|
||||
"../type-expander/type-expander.lp2.rkt"
|
||||
"../type-expander/multi-id.lp2.rkt"
|
||||
"structure.lp2.rkt" ; debug
|
||||
"variant.lp2.rkt" ; debug
|
||||
"fold-queues.lp2.rkt"; debug
|
||||
"rewrite-type.lp2.rkt"; debug
|
||||
"meta-struct.rkt"; debug
|
||||
racket/splicing; debug
|
||||
racket/stxparam; debug
|
||||
(for-syntax syntax/parse)
|
||||
(for-syntax syntax/parse/experimental/template))
|
||||
|
||||
(define-graph/rich-return grr
|
||||
([City [streets : (~> m-streets)]]
|
||||
[Street [sname : String]])
|
||||
[(m-cities [cnames : (Listof (Listof String))])
|
||||
: (Listof City)
|
||||
(define (strings→city [s : (Listof String)])
|
||||
(City (m-streets s)))
|
||||
(map strings→city cnames)]
|
||||
[(m-streets [snames : (Listof String)])
|
||||
: (Listof Street)
|
||||
(map Street snames)])
|
||||
|
||||
#;(define-graph/rich-return grra
|
||||
([City [streets : (~> m-streets)]]
|
||||
[Street [sname : String]])
|
||||
[(m-cities [cnames : (Listof (Listof String))])
|
||||
: (Listof City)
|
||||
(define (strings→city [s : (Listof String)])
|
||||
(City (m-streets s)))
|
||||
(map strings→city cnames)]
|
||||
[(m-streets [snames : (Listof String)])
|
||||
: (Listof Street)
|
||||
(map Street snames)])
|
||||
|
|
@ -1,12 +1,5 @@
|
|||
Attempts:
|
||||
* Splitting the define-graph macro in two: it's not enough.
|
||||
* (datum->syntax) Commit 876c4d2: works, but introduces ~> into the global scope
|
||||
* (syntax-local-introduce) Does not work at all
|
||||
* ((make-delta-introducer) (syntax-local-introduce) 'add), see identifiers.ods and __DEBUG_graph6F.rkt and __DEBUG_graph6.delta-introducer.rkt: Works on normal identifiers but not for the graph, because the `:` identifier is not the same anymore, and graph doesn't recognize it: define-graph: expected the identifier `:' or expected the identifier `new-:' parsing context: while parsing colon in: :
|
||||
* (make-syntax-introducer) does not work, but I'm not sure I got it right.
|
||||
* ((make-delta-introducer) (syntax-local-introduce)), see identifiers.ods and __DEBUG_graph6F.rkt: Works on normal identifiers (not sure?) but not for the graph (why?)
|
||||
* splicing-syntax-parameterize Commit 56fdfae: splicing-syntax-parameterize messes up the scopes of its body
|
||||
|
||||
Not tried yet:
|
||||
* datum->syntax (or replace-context or …) in define-graph, so that it "gobbles" its parameters?
|
||||
* #:defined-please-bind-dammit (~>), so that a rename-transformer is introduced by define-graph
|
||||
* defining ~> directly inside define-graph
|
|
@ -1,7 +1,7 @@
|
|||
#lang typed/racket
|
||||
|
||||
(require "graph-6-rich-returns.lp2.rkt"
|
||||
(except-in "../lib/low.rkt" ~>)
|
||||
"../lib/low.rkt"
|
||||
"graph.lp2.rkt"
|
||||
"get.lp2.rkt"
|
||||
"../type-expander/type-expander.lp2.rkt"
|
||||
|
|
|
@ -1,249 +0,0 @@
|
|||
#lang scribble/lp2
|
||||
@(require "../lib/doc.rkt")
|
||||
@doc-lib-setup
|
||||
|
||||
@title[#:style manual-doc-style]{Syntactic sugar for
|
||||
@racket[graph]: rich return types}
|
||||
|
||||
@(table-of-contents)
|
||||
|
||||
@section{Introduction}
|
||||
|
||||
We define a wrapper around the @tc[graph] macro, which
|
||||
allows defining mappings with rich return types, instead of
|
||||
being forced to return a single node. For example, a mapping
|
||||
can return a list of nodes.
|
||||
|
||||
During the graph construction, however, the user cannot
|
||||
access the contents of these rich values. If this was
|
||||
allowed, constructing a node might cause infinite recursion,
|
||||
which is precisely one of the pitfalls our library strives
|
||||
to avoid. For example, the following two constructors each
|
||||
depend on parts of the other's output.
|
||||
|
||||
@chunk[<example-infinite-loop>
|
||||
(define-graph (g [a [len : Integer] [bs : (Listof b)]]
|
||||
[b [len : Integer] [as : (Listof a)]])
|
||||
[(ma) : (Listof a)
|
||||
(let ([bs (mb)])
|
||||
(list (a (length bs) bs)
|
||||
(a 42 bs)))]
|
||||
[(mb) : (Listof b)
|
||||
(let ([as (ma)])
|
||||
(list (b (length bs) as)
|
||||
(b 123 as)))])]
|
||||
|
||||
In the above example, running @tc[(ma)] will require
|
||||
running @tc[(mb)] too, to compute the length of the list
|
||||
returned by @tc[(mb)], and vice-versa. It is clear this code
|
||||
will run into an infinite loop in an eager language like
|
||||
@tc[typed/racket].
|
||||
|
||||
To avoid this kind of issue, we will make the mapping
|
||||
functions return opaque values whose contents cannot be
|
||||
inspected during the creation of the graph. This also makes
|
||||
the implementation easier, as we will generate the graph in
|
||||
two phases: first, we will associate a single-field node
|
||||
with each mapping, and use it as their return type. Then, a
|
||||
second pass will break these nodes, and extract their
|
||||
constituents until an actual user-specified node is
|
||||
reached.
|
||||
|
||||
Since this implementation also allows serveral mappings to
|
||||
return the same node, the new signature separates the
|
||||
mapping declarations from the node definitions:
|
||||
|
||||
@chunk[<signature>
|
||||
(define-graph/rich-return name:id
|
||||
(~or (~seq #:definitions extra-definitions)
|
||||
(~seq #:wrapping-definitions wrapping-extra-definitions)
|
||||
(~seq))
|
||||
((~commit [node:id <field-signature> …])
|
||||
…)
|
||||
(~commit <mapping-declaration>)
|
||||
…)]
|
||||
|
||||
Where @tc[<field-signature>] hasn't changed:
|
||||
|
||||
@chunk[<field-signature>
|
||||
(~describe "[field : type]"
|
||||
[field:id c:colon field-type:expr])]
|
||||
|
||||
We now allow more complex return types in a @tc[<mapping-declaration>]:
|
||||
|
||||
@chunk[<mapping-declaration>
|
||||
(~describe "[(mapping [param : type] …) : result . body]"
|
||||
[(mapping:id [param:id cp:colon param-type:expr] …)
|
||||
cm:colon result-type:expr
|
||||
. body])]
|
||||
|
||||
Here is an example usage of this syntax:
|
||||
|
||||
@chunk[<test-graph-rich-return>
|
||||
(define-graph/rich-return grr
|
||||
([City [streets : (~> m-streets)]]
|
||||
[Street [sname : String]])
|
||||
[(m-cities [cnames : (Listof (Listof String))]) : (Listof City)
|
||||
(define (strings→city [s : (Listof String)])
|
||||
(City (m-streets s)))
|
||||
(map strings→city cnames)]
|
||||
[(m-streets [snames : (Listof String)]) : (Listof Street)
|
||||
(map Street snames)])]
|
||||
|
||||
The @tc[(~> m-streets)] type is a special marker which will
|
||||
be expanded to the return type of @tc[m-streets] (namely
|
||||
@tc[(Listof Street)]) in the final graph type. For the first
|
||||
step, however, it will be expanded to
|
||||
@tc[(U (grr #:placeholder m-streets/node) (Listof Street))].
|
||||
Without this, passing the result of @tc[(m-streets s)] to
|
||||
@tc[City] would be impossible: the former is a placeholder
|
||||
for the temporary node type which encapsulates the result
|
||||
of @tc[m-streets], while the latter would normally expect a
|
||||
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 …))
|
||||
;(define/with-syntax ~>-id #'~>);(datum->syntax #'name '~>))
|
||||
;(define/with-syntax ~>-id-inner (syntax-local-introduce #'~>))
|
||||
(quasitemplate
|
||||
(debug
|
||||
(begin
|
||||
(define-graph first-step
|
||||
. #,((make-syntax-delta-introducer #'~> #'name)
|
||||
(syntax-local-introduce
|
||||
#'(
|
||||
#:definitions (begin <first-pass-type-expander>)
|
||||
;. #,(syntax-local-introduce
|
||||
; #'(
|
||||
[node [field c (Let [~> first-step-expander2] field-type)] … ;; ~>-id-inner
|
||||
[(node/simple-mapping [field c field-type] …)
|
||||
;<first-pass-field-type>] …)
|
||||
(node field …)]]
|
||||
…
|
||||
[mapping/node [returned cm result-type]
|
||||
[(mapping [param cp param-type] …)
|
||||
(mapping/node
|
||||
(let ([node node/simple-mapping] …)
|
||||
. body))]]
|
||||
…
|
||||
)) 'add)
|
||||
)))))]
|
||||
|
||||
As explained above, during the first pass, the field types
|
||||
of nodes will allow placeholders for the temporary nodes
|
||||
encapsulating the result types of mappings.
|
||||
|
||||
@chunk[<first-pass-type-expander>
|
||||
;; TODO: to avoid conflicting definitions of ~>, we should either use
|
||||
;; syntax-parameterize, or make a #:local-definitions
|
||||
#;(define-type-expander (~>-id 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.
|
||||
))
|
||||
#;(define-type-expander (first-step-expander2 stx)
|
||||
(syntax-parse stx
|
||||
[(_ (~datum mapping)) ;; TODO: should be ~literal
|
||||
#'(U mapping/node result-type)]
|
||||
…
|
||||
;; TODO: should fall-back to outer definition of ~>, if any.
|
||||
)
|
||||
#;(U (first-step #:placeholder m-streets4/node)
|
||||
(Listof (first-step #:placeholder Street))))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
(define-type-expander (~> 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.
|
||||
))
|
||||
|
||||
(define-type-expander (first-step-expander2 stx)
|
||||
(syntax-parse stx
|
||||
[(_ (~datum mapping)) ;; TODO: should be ~literal
|
||||
#'(U mapping/node result-type)]
|
||||
…
|
||||
;; 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 wfell here, we need to define a
|
||||
@; type-expander.
|
||||
@chunk[<first-pass-field-type>
|
||||
(tmpl-replace-in-type field-type
|
||||
[(~> mapping) (U mapping/node result-type)] …)]
|
||||
|
||||
@section{Conclusion}
|
||||
|
||||
@chunk[<module-main>
|
||||
(module main typed/racket
|
||||
(require (for-syntax syntax/parse
|
||||
syntax/parse/experimental/template
|
||||
racket/syntax
|
||||
syntax/stx
|
||||
"../lib/low-untyped.rkt"
|
||||
"../lib/low/multiassoc-syntax.rkt"
|
||||
"rewrite-type.lp2.rkt"; debug
|
||||
)
|
||||
(rename-in "../lib/low.rkt" [~> threading:~>])
|
||||
"graph.lp2.rkt"
|
||||
"get.lp2.rkt"
|
||||
"../type-expander/type-expander.lp2.rkt"
|
||||
"../type-expander/multi-id.lp2.rkt"
|
||||
"structure.lp2.rkt" ; debug
|
||||
"variant.lp2.rkt" ; debug
|
||||
"fold-queues.lp2.rkt"; debug
|
||||
"rewrite-type.lp2.rkt"; debug
|
||||
"meta-struct.rkt"; debug
|
||||
racket/stxparam
|
||||
racket/splicing)
|
||||
(provide define-graph/rich-return)
|
||||
|
||||
(require (for-syntax racket/pretty))
|
||||
(define-syntax (debug stx)
|
||||
(syntax-case stx ()
|
||||
[(_ body)
|
||||
;; syntax->string
|
||||
(pretty-print (syntax->datum #'body))
|
||||
#'body]))
|
||||
|
||||
<graph-rich-return>)]
|
||||
|
||||
@chunk[<module-test>
|
||||
(module* test typed/racket
|
||||
(require (submod "..")
|
||||
typed/rackunit)
|
||||
|
||||
;;<test-graph-rich-return>
|
||||
)]
|
||||
|
||||
@chunk[<*>
|
||||
(begin
|
||||
<module-main>
|
||||
|
||||
(require 'main)
|
||||
(provide (all-from-out 'main))
|
||||
|
||||
<module-test>)]
|
Loading…
Reference in New Issue
Block a user