diff --git a/graph/graph/fold-queues.lp2.rkt b/graph/graph/fold-queues.lp2.rkt index bddf6ce5..9178ec6c 100644 --- a/graph/graph/fold-queues.lp2.rkt +++ b/graph/graph/fold-queues.lp2.rkt @@ -12,7 +12,7 @@ @chunk[<fold-queues-signature> (fold-queues root-value - [(name [element (~literal :) element-type] Δ-queues get-tag) + [(name [element (~literal :) element-type] Δ-queues enqueue) (~literal :) result-type . body] ...)] @@ -31,7 +31,7 @@ <define-enqueue-type> <define-Δ-queues-type> #'(list (λ ([element : element-type] - [get-tag : get-tag/type] + [enqueue : get-tag/type] [Δ-queues : queues/type]) : result-type . body) diff --git a/graph/graph/graph2.lp2.rkt b/graph/graph/graph2.lp2.rkt index e756a42c..a908ed6a 100644 --- a/graph/graph/graph2.lp2.rkt +++ b/graph/graph/graph2.lp2.rkt @@ -165,7 +165,8 @@ A single node name can refer to several types: @itemlist[ @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 allowed to be either actual instances, or placeholders. For example, @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))]].}] 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} @@ -184,7 +192,7 @@ flexible through wrapper macros. @chunk[<signature> (make-graph-constructor - [node type ...] + ([node field-type ...] ...) (root-expr:expr ...) [(mapping [param (~literal :) param-type] ...) (~literal :) result-type 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. @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> <with-promises-type>] @@ -223,66 +232,108 @@ The return type for each queue will be the corresponding with-promises type. @; type. @; TODO: clarity. -@; The @tc[fold-queues] function allows us to associate each element with a tag, so -@; that, inside the processing function and outside, we can refer to an element -@; using this tag, which can be more lightweight than keeping a copy of the -@; element. +@; The @tc[fold-queues] function allows us to associate each element with a tag, +@; so that, inside the processing function and outside, we can refer to an +@; element using this tag, which can be more lightweight than keeping a copy of +@; the element. @; -@; We will tag our elements with an @tc[Index], which prevents memory leakage: if -@; we kept references to the original data added to the queue, a graph's +@; We will tag our elements with an @tc[Index], which prevents memory leakage: +@; 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 @; 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 -@; able to use an array instead of a hash table. +@; these nodes. Also, it makes lookups in the database much faster, as we will +@; be able to use an array instead of a hash table. @subsection{The queues of placeholders} -@chunk[<root-placeholder> - (make-placeholder root-expr ...)] +The fold-queus macro takes a root element, in our case the root placeholder, +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> (fold-queues <root-placeholder> [(mapping [e : <fold-queue-type-element>] get-tag Δ-queues) : <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 -@; foo/bar, when foo is a syntax parameter. +@chunk[<root-placeholder> + (root/make-placeholder root-expr ...)] -@chunk[<define-ids> - (define-temp-ids mapping "~a/make-placeholder")] +To make the placeholder, we will need a @tc[make-placeholder] function for each +@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> - (define-temp-ids mapping "~a/placeholder-type")] +@; TODO: just use (variant [mapping param-type ...] ...) -@chunk[<define-placeholders> +@chunk[<define-placeholder> (define-type mapping/placeholder-type (List 'mapping param-type ...)) (: mapping/make-placeholder (→ param-type ... mapping/placeholder-type)) (define (mapping/make-placeholder [param : param-type] ...) (list 'mapping param ...))] -@section{Temporary fillers} +The code above needs some identifiers derived from @tc[mapping] names: -@chunk[<placeholder-type> - Any] +@chunk[<define-ids> + (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> Any] -@section{Bits and pieces} +@section{Putting it all together} @chunk[<make-graph-constructor> (define-syntax/parse <signature> <define-ids> - #'(begin - (begin <define-placeholders>) ... - <fold-queue>))] + (template + (let () + (begin <define-placeholder>) ... + (begin <define-with-promises>) ... + <fold-queue>)))] @section{Conclusion} @@ -290,6 +341,8 @@ The return type for each queue will be the corresponding with-promises type. (module main typed/racket (require (for-syntax syntax/parse racket/syntax + syntax/parse/experimental/template + "rewrite-type.lp2.rkt" "../lib/low-untyped.rkt") "fold-queues.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 "..") typed/rackunit) - <make-constructor-example> + <use-example> + + g (require (submod ".." doc)))] diff --git a/graph/graph/rewrite-type.lp2.rkt b/graph/graph/rewrite-type.lp2.rkt index fc81d25f..14a73c11 100644 --- a/graph/graph/rewrite-type.lp2.rkt +++ b/graph/graph/rewrite-type.lp2.rkt @@ -1,4 +1,4 @@ -#lang scribble/lp2 +#lang debug scribble/lp2 @(require "../lib/doc.rkt") @doc-lib-setup @@ -514,8 +514,34 @@ implementation. @section{Conclusion} -TODO: to test the two versions of replace-in-instance, just use the chunk twice, -with a let. +@; TODO: to test the two versions of replace-in-instance, just use the chunk +@; 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[<*> (begin @@ -523,6 +549,7 @@ with a let. (require (for-syntax syntax/parse racket/syntax syntax/stx + syntax/parse/experimental/template "../lib/low-untyped.rkt") "structure.lp2.rkt" "variant.lp2.rkt" @@ -534,12 +561,16 @@ with a let. ;replace-in-instance fold-instance (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-instance> <replace-in-instance2> - <fold-instance>) + <fold-instance> + (begin-for-syntax <template-metafunctions>)) (require 'main) (provide (all-from-out 'main)) diff --git a/graph/lib/low.rkt b/graph/lib/low.rkt index 2b071669..e0323f9f 100644 --- a/graph/lib/low.rkt +++ b/graph/lib/low.rkt @@ -535,7 +535,7 @@ (define-syntax (define-temp-ids stx) (syntax-parse stx - [(_ base:id format) + [(_ format (base:id (~literal ...))) #:when (string? (syntax-e #'format)) (with-syntax ([pat (format-id #'base (syntax-e #'format) #'base)]) #'(define/with-syntax (pat (... ...))