[make works] Added section “Making with-promises nodes” and improved others in graph2.lp2.rkt

This commit is contained in:
Georges Dupéron 2015-11-18 19:57:23 +01:00
parent d7860e0eaf
commit 770e75834f
4 changed files with 126 additions and 40 deletions

View File

@ -12,7 +12,7 @@
@chunk[<fold-queues-signature> @chunk[<fold-queues-signature>
(fold-queues root-value (fold-queues root-value
[(name [element (~literal :) element-type] Δ-queues get-tag) [(name [element (~literal :) element-type] Δ-queues enqueue)
(~literal :) result-type (~literal :) result-type
. body] . body]
...)] ...)]
@ -31,7 +31,7 @@
<define-enqueue-type> <define-enqueue-type>
<define-Δ-queues-type> <define-Δ-queues-type>
#'(list (λ ([element : element-type] #'(list (λ ([element : element-type]
[get-tag : get-tag/type] [enqueue : get-tag/type]
[Δ-queues : queues/type]) [Δ-queues : queues/type])
: result-type : result-type
. body) . body)

View File

@ -165,7 +165,8 @@ A single node name can refer to several types:
@itemlist[ @itemlist[
@item{The @emph{ideal} type, expressed by the user, for example @item{The @emph{ideal} type, expressed by the user, for example
@racket[[City (Listof Street) (Listof Person)]]} @racket[[City (Listof Street) (Listof Person)]], it is never used as-is in
practice}
@item{The @emph{incomplete} type, in which references to other node types are @item{The @emph{incomplete} type, in which references to other node types are
allowed to be either actual instances, or placeholders. For example, allowed to be either actual instances, or placeholders. For example,
@racket[[City (Listof (U Street Street-Placeholder)) @racket[[City (Listof (U Street Street-Placeholder))
@ -175,7 +176,14 @@ A single node name can refer to several types:
@racket[[City (Listof (Promise Street)) (Listof (Promise Person))]].}] @racket[[City (Listof (Promise Street)) (Listof (Promise Person))]].}]
When the user code calls a mapping, a placeholder is instead returned. We When the user code calls a mapping, a placeholder is instead returned. We
therefore will have one placeholder type per mapping. therefore will have one placeholder type per mapping. Mappings come in various
flavours too:
@itemlist[
@item{The \emph{placeholder} type and constructor, which just store the
arguments for the mapping along with its name}
@item{The mapping function's \emph{body}, which takes some parameters and
returns a node (this is the code directly provided by the user)}]
@subsection{The macro's syntax} @subsection{The macro's syntax}
@ -184,7 +192,7 @@ flexible through wrapper macros.
@chunk[<signature> @chunk[<signature>
(make-graph-constructor (make-graph-constructor
[node type ...] ([node field-type ...] ...)
(root-expr:expr ...) (root-expr:expr ...)
[(mapping [param (~literal :) param-type] ...) (~literal :) result-type [(mapping [param (~literal :) param-type] ...) (~literal :) result-type
body] body]
@ -208,9 +216,10 @@ We will have one queue for each placeholder type.@note{It we had only one queue,
queues' element types will therefore be these placeholder types. queues' element types will therefore be these placeholder types.
@chunk[<fold-queue-type-element> @chunk[<fold-queue-type-element>
<placeholder-type>] mapping/placeholder-type]
The return type for each queue will be the corresponding with-promises type. The return type for each queue will be the corresponding with-promises type. The
fold-queues function will therefore return a vector of with-promises nodes.
@chunk[<fold-queue-type-result> @chunk[<fold-queue-type-result>
<with-promises-type>] <with-promises-type>]
@ -223,66 +232,108 @@ The return type for each queue will be the corresponding with-promises type.
@; type. @; type.
@; TODO: clarity. @; TODO: clarity.
@; The @tc[fold-queues] function allows us to associate each element with a tag, so @; The @tc[fold-queues] function allows us to associate each element with a tag,
@; that, inside the processing function and outside, we can refer to an element @; so that, inside the processing function and outside, we can refer to an
@; using this tag, which can be more lightweight than keeping a copy of the @; element using this tag, which can be more lightweight than keeping a copy of
@; element. @; the element.
@; @;
@; We will tag our elements with an @tc[Index], which prevents memory leakage: if @; We will tag our elements with an @tc[Index], which prevents memory leakage:
@; we kept references to the original data added to the queue, a graph's @; if we kept references to the original data added to the queue, a graph's
@; representation would hold references to its input, which is not the case when @; representation would hold references to its input, which is not the case when
@; using simple integers to refer to other nodes, instead of using the input for @; using simple integers to refer to other nodes, instead of using the input for
@; these nodes. Also, it makes lookups in the database much faster, as we will be @; these nodes. Also, it makes lookups in the database much faster, as we will
@; able to use an array instead of a hash table. @; be able to use an array instead of a hash table.
@subsection{The queues of placeholders} @subsection{The queues of placeholders}
@chunk[<root-placeholder> The fold-queus macro takes a root element, in our case the root placeholder,
(make-placeholder root-expr ...)] which it will insert into the first queue. The next clauses are the queue
handlers, which look like function definitions of the form
@tc[(queue-name [element : element-type] Δ-queues enqueue)]. The @tc[enqueue]
argument is a function used to enqueue elements and get a tag in return, which
can later be used to retrieve the processed element.
Since the @tc[enqueue] function is pure, it takes a parameter of the same type
as @tc[Δ-queues] representing the already-enqueued elements, and returns a
modified copy, in addition to the tag. The queue's processing body should return
the latest @tc[Δ-queues] in order to have these elements added to the queue.
@chunk[<fold-queue> @chunk[<fold-queue>
(fold-queues <root-placeholder> (fold-queues <root-placeholder>
[(mapping [e : <fold-queue-type-element>] get-tag Δ-queues) [(mapping [e : <fold-queue-type-element>] get-tag Δ-queues)
: <fold-queue-type-result> : <fold-queue-type-result>
'todo!] <fold-queue-body>]
...)] ...)]
@subsection{Making placeholders for mappings}
@section{Making placeholders} We start creating the root placeholder which we provide to @tc[fold-queues].
@; TODO: make a template library that implicitly creates temporaries for @chunk[<root-placeholder>
@; foo/bar, when foo is a syntax parameter. (root/make-placeholder root-expr ...)]
@chunk[<define-ids> To make the placeholder, we will need a @tc[make-placeholder] function for each
(define-temp-ids mapping "~a/make-placeholder")] @tc[mapping]. We define the type of each placeholder (a list of arguments,
tagged with the @tc[mapping]'s name), and a constructor:
@chunk[<define-ids> @; TODO: just use (variant [mapping param-type ...] ...)
(define-temp-ids mapping "~a/placeholder-type")]
@chunk[<define-placeholders> @chunk[<define-placeholder>
(define-type mapping/placeholder-type (List 'mapping param-type ...)) (define-type mapping/placeholder-type (List 'mapping param-type ...))
(: mapping/make-placeholder ( param-type ... mapping/placeholder-type)) (: mapping/make-placeholder ( param-type ... mapping/placeholder-type))
(define (mapping/make-placeholder [param : param-type] ...) (define (mapping/make-placeholder [param : param-type] ...)
(list 'mapping param ...))] (list 'mapping param ...))]
@section{Temporary fillers} The code above needs some identifiers derived from @tc[mapping] names:
@chunk[<placeholder-type> @chunk[<define-ids>
Any] (define-temp-ids "~a/make-placeholder" (mapping ...))
(define-temp-ids "~a/placeholder-type" (mapping ...))
(define/with-syntax (root/make-placeholder . _)
#'(mapping/make-placeholder ...))]
@subsection{Making with-promises nodes}
We derive the @tc[with-promises] type from each @emph{ideal} node type, using
the @tc[tmpl-replace-in-type] template metafunction from the rewrite-type
library. We replace all occurrences of a @tc[node] name with a @tc[Promise] for
that node's @tc[with-promises] type.
@; TODO: use a type-expander here, instead of a template metafunction.
@CHUNK[<define-with-promises>
(define-type node/with-promises-type
(tmpl-replace-in-type (List 'node field-type ...)
([node (Promise node/with-promises-type)] ...)))]
@chunk[<define-ids>
(define-temp-ids "~a/make-with-promises" (node ...))
(define-temp-ids "~a/with-promises-type" (node ...))]
@subsection{Processing the placeholders}
@chunk[<fold-queue-body>
'todo!]
@section{Temporary fillers}
@chunk[<with-promises-type> @chunk[<with-promises-type>
Any] Any]
@section{Bits and pieces} @section{Putting it all together}
@chunk[<make-graph-constructor> @chunk[<make-graph-constructor>
(define-syntax/parse <signature> (define-syntax/parse <signature>
<define-ids> <define-ids>
#'(begin (template
(begin <define-placeholders>) ... (let ()
<fold-queue>))] (begin <define-placeholder>) ...
(begin <define-with-promises>) ...
<fold-queue>)))]
@section{Conclusion} @section{Conclusion}
@ -290,6 +341,8 @@ The return type for each queue will be the corresponding with-promises type.
(module main typed/racket (module main typed/racket
(require (for-syntax syntax/parse (require (for-syntax syntax/parse
racket/syntax racket/syntax
syntax/parse/experimental/template
"rewrite-type.lp2.rkt"
"../lib/low-untyped.rkt") "../lib/low-untyped.rkt")
"fold-queues.lp2.rkt" "fold-queues.lp2.rkt"
"rewrite-type.lp2.rkt" "rewrite-type.lp2.rkt"
@ -305,7 +358,9 @@ The return type for each queue will be the corresponding with-promises type.
(require (submod "..") (require (submod "..")
typed/rackunit) typed/rackunit)
<make-constructor-example> <use-example>
g
(require (submod ".." doc)))] (require (submod ".." doc)))]

View File

@ -1,4 +1,4 @@
#lang scribble/lp2 #lang debug scribble/lp2
@(require "../lib/doc.rkt") @(require "../lib/doc.rkt")
@doc-lib-setup @doc-lib-setup
@ -514,8 +514,34 @@ implementation.
@section{Conclusion} @section{Conclusion}
TODO: to test the two versions of replace-in-instance, just use the chunk twice, @; TODO: to test the two versions of replace-in-instance, just use the chunk
with a let. @; twice, with a let.
For easier use of these functions, we also provide a few template metafunctions,
one for @tc[replace-in-type]:
@CHUNK[<template-metafunctions>
(define-template-metafunction (tmpl-replace-in-type stx)
(syntax-parse stx
[(_ type:expr ([from to] ...))
#`#,(replace-in-type #'type
#'([from to] ...))]))]
And one each for @tc[fold-instance] and @tc[replace-in-instance2]:
@CHUNK[<template-metafunctions>
(define-template-metafunction (tmpl-fold-instance stx)
(syntax-parse stx
[(_ type:expr acc-type:expr (~and rules ([from to fun] ...)))
#`#,(fold-instance #'type #'acc-type #'rules)]))
(define-template-metafunction (tmpl-replace-in-instance stx)
(syntax-parse stx
[(_ type:expr (~and rules ([from to fun] ...)))
#`#,(replace-in-instance2 #'type #'rules)]))]
These metafunctions just extract the arguments for @tc[replace-in-type] and
@tc[replace-in-instance2], and pass them to these functions.
@chunk[<*> @chunk[<*>
(begin (begin
@ -523,6 +549,7 @@ with a let.
(require (for-syntax syntax/parse (require (for-syntax syntax/parse
racket/syntax racket/syntax
syntax/stx syntax/stx
syntax/parse/experimental/template
"../lib/low-untyped.rkt") "../lib/low-untyped.rkt")
"structure.lp2.rkt" "structure.lp2.rkt"
"variant.lp2.rkt" "variant.lp2.rkt"
@ -534,12 +561,16 @@ with a let.
;replace-in-instance ;replace-in-instance
fold-instance fold-instance
(rename-out [replace-in-instance2 (rename-out [replace-in-instance2
replace-in-instance]))) replace-in-instance])
tmpl-replace-in-type
tmpl-fold-instance
tmpl-replace-in-instance))
<replace-in-type> <replace-in-type>
<replace-in-instance> <replace-in-instance>
<replace-in-instance2> <replace-in-instance2>
<fold-instance>) <fold-instance>
(begin-for-syntax <template-metafunctions>))
(require 'main) (require 'main)
(provide (all-from-out 'main)) (provide (all-from-out 'main))

View File

@ -535,7 +535,7 @@
(define-syntax (define-temp-ids stx) (define-syntax (define-temp-ids stx)
(syntax-parse stx (syntax-parse stx
[(_ base:id format) [(_ format (base:id (~literal ...)))
#:when (string? (syntax-e #'format)) #:when (string? (syntax-e #'format))
(with-syntax ([pat (format-id #'base (syntax-e #'format) #'base)]) (with-syntax ([pat (format-id #'base (syntax-e #'format) #'base)])
#'(define/with-syntax (pat (... ...)) #'(define/with-syntax (pat (... ...))