From fe3eec2b4453c149ded37e6bfca9a4535e3de40a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Georges=20Dup=C3=A9ron?= <georges.duperon@gmail.com> Date: Thu, 1 Jun 2017 16:46:29 +0200 Subject: [PATCH] More literate explanations --- flexible-with2.hl.rkt | 102 +++++++++++++++++++++++++++++------------- 1 file changed, 72 insertions(+), 30 deletions(-) diff --git a/flexible-with2.hl.rkt b/flexible-with2.hl.rkt index e3aa3ac..6df17da 100644 --- a/flexible-with2.hl.rkt +++ b/flexible-with2.hl.rkt @@ -304,7 +304,6 @@ fields. #:node-wrapper λl.r.(list #'cons l r) #:vec vec)] -꩜section{Type of a record, with a multiple holes} @@ -349,10 +348,11 @@ fields. +꩜section{Row typing} -Identifiers which are bound as row type variables are bound as transformers to -instances of the ꩜racket[ρ-wrapper] struct, so that they are easily -recognizable by special forms such as ꩜racket[record]. +Row type variable identifiers are bound as transformers to instances of the +꩜racket[ρ-wrapper] struct, so that they are easily recognisable by special +forms such as ꩜racket[record]. ꩜spler[<ρ-wrapper> (begin-for-syntax @@ -367,9 +367,10 @@ recognizable by special forms such as ꩜racket[record]. stx))))] The row type variable actually expands to several polymorphic type variables. -In order to know which, we remember which fields are used along a given row -type variable, while compiling the current file. The set of field names used -with a given row types variable is stored as an entry of the ꩜racket[ρ-table]. +In order to know which fields are relevant, we remember which fields are used +along a given row type variable, while compiling the current file. The set of +field names used with a given row types variable is stored as an entry of the +꩜racket[ρ-table]. ꩜chunk[<ρ-table> (define-for-syntax ρ-table (make-free-id-table))] @@ -410,10 +411,11 @@ dimmed below. (define sidekicks '()) #`(∀ (arg … #,@sidekicks) tree)]))] -Aside from the kind of result (which is a polymorphic type, not a function), -the main difference with ꩜racket[idx→tree] is how the empty branches are -handled. When a branch only containing ꩜racket[none] elements is encountered, -it is replaced with a single polymorphic type. +The results of ꩜racket[record-type] and ꩜racket[record-builder] differ in two +aspects: the result of ꩜racket[record-type] is a polymorphic type, not a +function, and the empty branches are handled differently. When a branch only +containing ꩜racket[none] elements is encountered, it is replaced with a single +polymorphic type. ꩜hlite[<record-type/wrappers> {-/ (_ = _ _ _ _ _ _ _ _ _ -/ _ vec)} (idx→tree @@ -436,39 +438,65 @@ which will produce the syntax for the desired type when called. ꩜chunk[<current-patch-table> (define-for-syntax current-patch-table (make-parameter #f))] -꩜chunk[<record-type> - <ρ-wrapper> - <current-patch-table> +Type-level forms like ꩜racket[∀ρ], ꩜racket[ρ-inst] and ꩜racket[record] add +placeholders to ꩜racket[current-patch-table]. + +The form ꩜racket[with-ρ] is used to declare row type variables and collect +patches in ꩜racket[current-patch-table]. The explicit declaration of row type +variables is necessary because type variables which are logically ``bound'' +with ꩜racket[∀] are not actually bound as identifiers during macro expansion +(instead, Typed Racket performs its own resolution while typechecking, i.e. +after the program is expanded). If a row type variable is introduced in the +type declaration for a function, we need to be able to detect the binding when +processing type-level forms within the body of the function. + +꩜chunk[<with-ρ> + (define-syntax with-ρ + (syntax-parser + [(_ (ρ …) . body) + #'(splicing-letrec-syntax ([ρ (ρ-wrapper #'ρ)] …) + (with-ρ-chain (ρ …) . body))]))] + +Once the bindings have been introduced via ꩜racket[splicing-letrec-syntax], +the expansion continues within the context of these identifiers, via the +꩜racket[with-ρ-chain] macro. + +꩜chunk[<with-ρ-chain> (define-syntax with-ρ-chain (syntax-parser [(_ (ρ …) . body) (parameterize ([current-patch-table (make-free-id-table)]) (define expanded-form (local-expand #'(begin . body) 'top-level '())) - (patch expanded-form (current-patch-table)))])) - (define-syntax with-ρ - (syntax-parser - [(_ (ρ …) . body) - #'(splicing-letrec-syntax ([ρ (ρ-wrapper #'ρ)] …) - (with-ρ-chain (ρ …) . body))])) - - <ρ-table> + (patch expanded-form (current-patch-table)))]))] + +꩜subsection{Type of a record, with a multiple fields} + +The ꩜racket[∀ρ] type-level form translates to a ꩜racket[∀] form. The +꩜racket[∀] form is expanded, so that uses of the row type variables within can +be detected. The ꩜racket[∀ρ] then expands to a placeholder +꩜racket[delayed-type], which will be patched by the surrounding +꩜racket[with-ρ]. + +꩜;TODO: use a table to track the pre-declared collapsed-branch types? +꩜chunk[<∀ρ> (define-type-expander ∀ρ (syntax-parser [(_ (A:id … #:ρ ρ:id …) τ) (for ([ρ (in-syntax #'(ρ …))]) (free-id-table-set! ρ-table ρ <make-lifo-set>)) - (define expanded (expand-type #'(∀ (A …) - (Let ([ρ (Pairof 'Hello 'ρ)] - …) - τ)))) + (define expanded (expand-type #'(∀ (A …) (Let ([ρ 'NOT-IMPL-YET] …) τ)))) (define/syntax-parse ({~literal tr:∀} (A′ …) . τ′) expanded) (free-id-table-set! (current-patch-table) #'delayed-type - (λ (self) - (delayed-∀ρ #'{(A′ …) (ρ …) τ′}))) - #'delayed-type])) + (λ (self) (delayed-∀ρ #'{(A′ …) (ρ …) τ′}))) + #'delayed-type]))] +When the ꩜racket[delayed-type] is replaced, the type variables associated with +each row type variable are injected as extra arguments to the +previously-expanded polymorphic type. + +꩜chunk[<delayed-∀ρ> (define-for-syntax/case-args (delayed-∀ρ {(A′ …) (ρ …) τ′}) (define/syntax-parse ((ρ′ …) …) (for/list ([ρ (in-syntax #'(ρ …))]) @@ -479,7 +507,21 @@ which will produce the syntax for the desired type when called. ;; the id is added to the list. Also #'here is probably the ;; wrong srcloc (format-id #'here "~a.~a" ρ ρ′)))) - #'(∀ (A′ … ρ′ … …) . τ′)) + #'(∀ (A′ … ρ′ … …) . τ′))] + + + +꩜chunk[<record-type> + <ρ-wrapper> + <current-patch-table> + + <with-ρ-chain> + <with-ρ> + + <ρ-table> + <∀ρ> + + <delayed-∀ρ> (define-type-expander record (syntax-parser