From 1743dd0e0463f0edc05ab6b8245be4cdf025e5e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Georges=20Dup=C3=A9ron?= Date: Fri, 26 Feb 2016 21:21:13 +0100 Subject: [PATCH] Notes about the various failures. --- .../graph/__DEBUG_graph6.delta-introducer.rkt | 42 +++ graph-lib/graph/__DEBUG_graph6.txt | 9 +- graph-lib/graph/__DEBUG_graph6G-req.rkt | 2 +- ...ph-6-rich-returns.delta-introducer.lp2.rkt | 249 ++++++++++++++++++ 4 files changed, 300 insertions(+), 2 deletions(-) create mode 100644 graph-lib/graph/__DEBUG_graph6.delta-introducer.rkt create mode 100644 graph-lib/graph/graph-6-rich-returns.delta-introducer.lp2.rkt diff --git a/graph-lib/graph/__DEBUG_graph6.delta-introducer.rkt b/graph-lib/graph/__DEBUG_graph6.delta-introducer.rkt new file mode 100644 index 0000000..6cfbcb7 --- /dev/null +++ b/graph-lib/graph/__DEBUG_graph6.delta-introducer.rkt @@ -0,0 +1,42 @@ +#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)]) + diff --git a/graph-lib/graph/__DEBUG_graph6.txt b/graph-lib/graph/__DEBUG_graph6.txt index 7286dbc..fd5aa42 100644 --- a/graph-lib/graph/__DEBUG_graph6.txt +++ b/graph-lib/graph/__DEBUG_graph6.txt @@ -1,5 +1,12 @@ 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)), see identifiers.ods and __DEBUG_graph6F.rkt: Works on normal identifiers (not sure?) but not for the graph (why?) +* ((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. * 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 \ No newline at end of file diff --git a/graph-lib/graph/__DEBUG_graph6G-req.rkt b/graph-lib/graph/__DEBUG_graph6G-req.rkt index 70d3a90..b7d0e1e 100644 --- a/graph-lib/graph/__DEBUG_graph6G-req.rkt +++ b/graph-lib/graph/__DEBUG_graph6G-req.rkt @@ -1,7 +1,7 @@ #lang typed/racket (require "graph-6-rich-returns.lp2.rkt" - "../lib/low.rkt" + (except-in "../lib/low.rkt" ~>) "graph.lp2.rkt" "get.lp2.rkt" "../type-expander/type-expander.lp2.rkt" diff --git a/graph-lib/graph/graph-6-rich-returns.delta-introducer.lp2.rkt b/graph-lib/graph/graph-6-rich-returns.delta-introducer.lp2.rkt new file mode 100644 index 0000000..84bd6f3 --- /dev/null +++ b/graph-lib/graph/graph-6-rich-returns.delta-introducer.lp2.rkt @@ -0,0 +1,249 @@ +#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[ + (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[ + (define-graph/rich-return name:id + (~or (~seq #:definitions extra-definitions) + (~seq #:wrapping-definitions wrapping-extra-definitions) + (~seq)) + ((~commit [node:id …]) + …) + (~commit ) + …)] + +Where @tc[] hasn't changed: + +@chunk[ + (~describe "[field : type]" + [field:id c:colon field-type:expr])] + +We now allow more complex return types in a @tc[]: + +@chunk[ + (~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[ + (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[ + (define-syntax/parse + (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 ) + ;. #,(syntax-local-introduce + ; #'( + [node [field c (Let [~> first-step-expander2] field-type)] … ;; ~>-id-inner + [(node/simple-mapping [field c 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[ + ;; 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[ + (tmpl-replace-in-type field-type + [(~> mapping) (U mapping/node result-type)] …)] + +@section{Conclusion} + +@chunk[ + (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])) + + )] + +@chunk[ + (module* test typed/racket + (require (submod "..") + typed/rackunit) + + ;; + )] + +@chunk[<*> + (begin + + + (require 'main) + (provide (all-from-out 'main)) + + )] \ No newline at end of file