[make works] Added section “Making with-promises nodes” and improved others in graph2.lp2.rkt
This commit is contained in:
parent
d7860e0eaf
commit
770e75834f
|
@ -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)
|
||||||
|
|
|
@ -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)))]
|
||||||
|
|
||||||
|
|
|
@ -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))
|
||||||
|
|
|
@ -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 (... ...))
|
||||||
|
|
Loading…
Reference in New Issue
Block a user