56: Write more text in rewrite-type.lp2.rkt
This commit is contained in:
parent
e8ab36d022
commit
116d16f74e
34
graph/graph/graph2.lp2.rkt
Normal file
34
graph/graph/graph2.lp2.rkt
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
#lang scribble/lp2
|
||||||
|
@(require "../lib/doc.rkt")
|
||||||
|
@doc-lib-setup
|
||||||
|
|
||||||
|
@title[#:style manual-doc-style]{Graph library}
|
||||||
|
|
||||||
|
@(table-of-contents)
|
||||||
|
|
||||||
|
@section{Introduction}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@section{Conclusion}
|
||||||
|
|
||||||
|
@chunk[<*>
|
||||||
|
(begin
|
||||||
|
(module main typed/racket
|
||||||
|
(require (for-syntax syntax/parse
|
||||||
|
racket/syntax
|
||||||
|
"../lib/low-untyped.rkt")
|
||||||
|
"../lib/low.rkt")
|
||||||
|
|
||||||
|
)
|
||||||
|
|
||||||
|
(require 'main)
|
||||||
|
(provide (all-from-out 'main))
|
||||||
|
|
||||||
|
(module* test typed/racket
|
||||||
|
(require (submod "..")
|
||||||
|
typed/rackunit)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
(require (submod ".." doc))))]
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
@title[#:style manual-doc-style]{Rewriting data structures and their types}
|
@title[#:style manual-doc-style]{Rewriting data structures and their types}
|
||||||
|
|
||||||
|
@section[#:tag "sec:intro-example"]{Introductory example}
|
||||||
This module allows purely functional substitution inside a data structure of
|
This module allows purely functional substitution inside a data structure of
|
||||||
arbitrarily deep elements of a given type, while also computing the type of the
|
arbitrarily deep elements of a given type, while also computing the type of the
|
||||||
result.
|
result.
|
||||||
|
@ -11,15 +12,42 @@ result.
|
||||||
For example, one could replace all strings in a data structure by their length:
|
For example, one could replace all strings in a data structure by their length:
|
||||||
|
|
||||||
@CHUNK[<test-example>
|
@CHUNK[<test-example>
|
||||||
|
(make-replace test-example
|
||||||
|
(Vectorof (U (List 'tag1 String) (List 'tag2 Number)))
|
||||||
|
[String Number string-length])]
|
||||||
|
|
||||||
|
The result's type would be derived from the original one, but all occurrences of
|
||||||
|
@tc[String] have been replaced by @tc[Number]. The result itself would have the
|
||||||
|
value returned by string-length instead of each string, everything else being
|
||||||
|
identical.
|
||||||
|
|
||||||
|
@CHUNK[<test-example>
|
||||||
|
(check-equal?
|
||||||
|
(ann (test-example '#((tag1 "a") (tag2 7) (tag1 "bcd")))
|
||||||
|
(Vectorof (U (List 'tag1 Number) (List 'tag2 Number))))
|
||||||
|
'#((tag1 1) (tag2 7) (tag1 3)))]
|
||||||
|
|
||||||
|
In this example, we used @tc[make-replace], a test macro defined below which
|
||||||
|
relies on the lower-level utilities provided by this module, namely
|
||||||
|
@tc[replace-in-type] and @tc[replace-in-instance].
|
||||||
|
|
||||||
|
@CHUNK[<test-make-replace>
|
||||||
(define-syntax (make-replace stx)
|
(define-syntax (make-replace stx)
|
||||||
(syntax-case stx ()
|
(syntax-case stx ()
|
||||||
[(_ name type . replace)
|
[(_ name type . replace)
|
||||||
#`(begin
|
#`(begin
|
||||||
(: name (→ type #,(replace-in-data-structure #'type #'replace)))
|
(: name (→ type #,(replace-in-type #'type #'replace)))
|
||||||
(define (name v)
|
(define (name v)
|
||||||
#,(replace-in-instance #'v #'type #'replace)))]))
|
#,(replace-in-instance #'v #'type #'replace)))]))]
|
||||||
|
|
||||||
(make-replace test1
|
@subsection{A bigger example}
|
||||||
|
|
||||||
|
We would expect this to work on bigger types without any extra efforts. In the
|
||||||
|
following example, we replace all strings with their length, on a bigger
|
||||||
|
example:
|
||||||
|
|
||||||
|
@CHUNK[<test-big>
|
||||||
|
(make-replace test-big
|
||||||
(List (Pairof (U (List 'tag1 (List (Vector Symbol)
|
(List (Pairof (U (List 'tag1 (List (Vector Symbol)
|
||||||
Number
|
Number
|
||||||
(Listof String)))
|
(Listof String)))
|
||||||
|
@ -27,10 +55,14 @@ For example, one could replace all strings in a data structure by their length:
|
||||||
Number
|
Number
|
||||||
(Listof String))))
|
(Listof String))))
|
||||||
String))
|
String))
|
||||||
[String Number string-length])
|
[String Number string-length])]
|
||||||
|
|
||||||
|
The replacement function @tc[test-big] defined above will, as expected, have a
|
||||||
|
return type containing no more strings, and the correct return value.
|
||||||
|
|
||||||
|
@CHUNK[<test-big>
|
||||||
(check-equal?
|
(check-equal?
|
||||||
(ann (test1 '(((tag2 (#(sym) 7 ("ab" "abc" "abcd"))) . "a")))
|
(ann (test-big '(((tag2 (#(sym) 7 ("ab" "abc" "abcd"))) . "a")))
|
||||||
(List (Pairof (U (List 'tag1 (List (Vector Symbol)
|
(List (Pairof (U (List 'tag1 (List (Vector Symbol)
|
||||||
Number
|
Number
|
||||||
(Listof Number)))
|
(Listof Number)))
|
||||||
|
@ -40,84 +72,142 @@ For example, one could replace all strings in a data structure by their length:
|
||||||
Number)))
|
Number)))
|
||||||
'(((tag2 (#(sym) 7 (2 3 4))) . 1)))]
|
'(((tag2 (#(sym) 7 (2 3 4))) . 1)))]
|
||||||
|
|
||||||
@CHUNK[<replace-in-data-structure>
|
@section{Replacing parts of a type}
|
||||||
(define-for-syntax (replace-in-data-structure t r)
|
|
||||||
(define (recursive-replace new-t) (replace-in-data-structure new-t r))
|
The @tc[replace-in-type] @tc[for-syntax] function is pretty straightforward: it
|
||||||
|
checks whether the given type matches one of the substitution rules given in
|
||||||
|
@tc[r]. If no substitution rule was found, it matches the type against a small
|
||||||
|
set of known type constructors like @tc[List] or @tc[Pairof], and recursively
|
||||||
|
calls itself on the components of the type.
|
||||||
|
|
||||||
|
@CHUNK[<replace-in-type>
|
||||||
|
(define-for-syntax (replace-in-type t r)
|
||||||
|
(define (recursive-replace new-t) (replace-in-type new-t r))
|
||||||
(define/with-syntax ([from to fun] ...) r)
|
(define/with-syntax ([from to fun] ...) r)
|
||||||
(syntax-parse t
|
(syntax-parse t
|
||||||
[x:id
|
<replace-in-type-substitute>
|
||||||
#:attr assoc-from-to (cdr-stx-assoc #'x #'((from . to) ...))
|
<replace-in-type-other-cases>))]
|
||||||
#:when (attribute assoc-from-to)
|
|
||||||
#'assoc-from-to]
|
The clause that matches the type against the substitution rules uses the
|
||||||
[((~literal List) a ...)
|
@tc[stx-assoc] function defined in our library, which uses
|
||||||
#`(List #,@(stx-map recursive-replace #'(a ...)))]
|
@tc[free-identifier=?] to find the first pair which @tc[car] or @tc[stx-car]
|
||||||
[((~literal Pairof) a b)
|
matches the given type @tc[#'x].
|
||||||
#`(Pairof #,(recursive-replace #'a) #,(recursive-replace #'b))]
|
|
||||||
[((~literal Listof) a)
|
@CHUNK[<replace-in-type-substitute>
|
||||||
#`(Listof #,(recursive-replace #'a))]
|
[x:id
|
||||||
[((~literal Vector) a ...)
|
#:attr assoc-from-to (cdr-stx-assoc #'x #'((from . to) ...))
|
||||||
#`(Vector #,@(stx-map recursive-replace #'(a ...)))]
|
#:when (attribute assoc-from-to)
|
||||||
[((~literal Vectorof) a)
|
#'assoc-from-to]]
|
||||||
#`(Vectorof #,(recursive-replace #'a))]
|
|
||||||
[((~literal U) a ...)
|
The other cases use @tc[~literal] and a syntax pattern to find uses of
|
||||||
#`(U #,@(stx-map recursive-replace #'(a ...)))]
|
@tc[List], @tc[Pairof], @tc[Vectorof] etc.
|
||||||
[((~literal quote) a)
|
|
||||||
;; TODO: if the quoted type is a primitive, we should replace it too
|
@CHUNK[<replace-in-type-other-cases>
|
||||||
#`(quote a)]
|
[((~literal List) a ...)
|
||||||
[x:id #'x]))]
|
#`(List #,@(stx-map recursive-replace #'(a ...)))]
|
||||||
|
[((~literal Pairof) a b)
|
||||||
|
#`(Pairof #,(recursive-replace #'a) #,(recursive-replace #'b))]
|
||||||
|
[((~literal Listof) a)
|
||||||
|
#`(Listof #,(recursive-replace #'a))]
|
||||||
|
[((~literal Vector) a ...)
|
||||||
|
#`(Vector #,@(stx-map recursive-replace #'(a ...)))]
|
||||||
|
[((~literal Vectorof) a)
|
||||||
|
#`(Vectorof #,(recursive-replace #'a))]
|
||||||
|
[((~literal U) a ...)
|
||||||
|
#`(U #,@(stx-map recursive-replace #'(a ...)))]
|
||||||
|
<replace-in-type-case-quote>
|
||||||
|
[x:id
|
||||||
|
#'x]]
|
||||||
|
|
||||||
|
TODO: If the type is a quoted primitive, we should replace it too, for example
|
||||||
|
@tc['("abc" symbol)] should be transformed into @tc['(3 symbol)] if we apply the
|
||||||
|
@tc[[String Number string-length]] substitution from the example in section
|
||||||
|
@secref{sec:intro-example}.
|
||||||
|
|
||||||
|
@CHUNK[<replace-in-type-case-quote>
|
||||||
|
[((~literal quote) a)
|
||||||
|
#`(quote a)]]
|
||||||
|
|
||||||
|
@section{Replacing parts of an instance}
|
||||||
|
|
||||||
|
The @tc[replace-in-instance] for-syntax function is defined in a similar way,
|
||||||
|
with an internal definition for @tc[recursive-replace]. The case of unions is
|
||||||
|
offloaded to a separate subroutine.
|
||||||
|
|
||||||
@CHUNK[<replace-in-instance>
|
@CHUNK[<replace-in-instance>
|
||||||
(define-for-syntax (replace-in-instance val t r)
|
(define-for-syntax (replace-in-instance val t r)
|
||||||
(define/with-syntax ([from to fun] ...) r)
|
(define/with-syntax ([from to fun] ...) r)
|
||||||
|
<recursive-replace-in-instance>
|
||||||
<replace-in-union>
|
<replace-in-union>
|
||||||
(define (recursive-replace stx-val type)
|
|
||||||
(define/with-syntax val stx-val)
|
|
||||||
(define/with-syntax (v-cache) (generate-temporaries #'(val-cache)))
|
|
||||||
(syntax-parse type
|
|
||||||
[x:id
|
|
||||||
#:attr assoc-from-to (cdr-stx-assoc #'x
|
|
||||||
#'((from . (to . fun)) ...))
|
|
||||||
#:when (attribute assoc-from-to)
|
|
||||||
#:with (to-type . to-fun) #'assoc-from-to
|
|
||||||
(define/with-syntax (tmp) (generate-temporaries #'(x)))
|
|
||||||
;; TODO: Add predicate for to-type in the pattern.
|
|
||||||
#`(to-fun val)]
|
|
||||||
[((~literal List) a ...)
|
|
||||||
(define/with-syntax (tmp ...) (generate-temporaries #'(a ...)))
|
|
||||||
#`(let-values ([(tmp ...) (apply values val)])
|
|
||||||
(list #,@(stx-map recursive-replace #'(tmp ...) #'(a ...))))]
|
|
||||||
[((~literal Pairof) a b)
|
|
||||||
#`(let ([v-cache val])
|
|
||||||
(cons #,(recursive-replace #'(car v-cache) #'a)
|
|
||||||
#,(recursive-replace #'(cdr v-cache) #'b)))]
|
|
||||||
[((~literal Listof) a)
|
|
||||||
(define/with-syntax (tmp) (generate-temporaries #'(a)))
|
|
||||||
#`(map (λ ([tmp : a]) #,(recursive-replace #'tmp #'a))
|
|
||||||
val)]
|
|
||||||
[((~literal Vector) a ...)
|
|
||||||
(define/with-syntax (tmp ...) (generate-temporaries #'(a ...)))
|
|
||||||
(define/with-syntax (idx ...) (generate-indices #'(a ...)))
|
|
||||||
#`(let ([v-cache val])
|
|
||||||
(let ([tmp (vector-ref v-cache idx)]
|
|
||||||
...)
|
|
||||||
(vector #,@(stx-map recursive-replace
|
|
||||||
#'(tmp ...)
|
|
||||||
#'(a ...)))))]
|
|
||||||
[((~literal Vectorof) a)
|
|
||||||
(define/with-syntax (tmp) (generate-temporaries #'(a)))
|
|
||||||
#`(vector-map (λ ([tmp : a]) #,(recursive-replace #'tmp #'a))
|
|
||||||
val)]
|
|
||||||
[((~literal U) a ...)
|
|
||||||
#`(let ([v-cache val])
|
|
||||||
(cond
|
|
||||||
#,@(stx-map (λ (ta) (replace-in-union #'v-cache ta r))
|
|
||||||
#'(a ...))))]
|
|
||||||
[((~literal quote) a)
|
|
||||||
#'val]
|
|
||||||
[x:id
|
|
||||||
#'val]))
|
|
||||||
(recursive-replace val t))]
|
(recursive-replace val t))]
|
||||||
|
|
||||||
|
The @tc[recursive-replace] internal function defined below takes a type
|
||||||
|
@tc[type] and produces an expression that transforms instances of that type
|
||||||
|
using the substitution rules given in the parameter @tc[r] of the enclosing
|
||||||
|
function.
|
||||||
|
|
||||||
|
The expression assumes that the instance to be transformed is located in the
|
||||||
|
variable or expression @tc[stx-val], and caching is used where needed to avoid
|
||||||
|
evaluating @tc[stx-val] twice. Here is the case that handles @tc[Pairof], which
|
||||||
|
caches @tc[val] and calls @tc[recursive-replace] with the @tc[car] and @tc[cdr]
|
||||||
|
as expressions:
|
||||||
|
|
||||||
|
@CHUNK[<replace-in-instance-case-pairof>
|
||||||
|
[((~literal Pairof) a b)
|
||||||
|
#`(let ([v-cache val])
|
||||||
|
(cons #,(recursive-replace #'(car v-cache) #'a)
|
||||||
|
#,(recursive-replace #'(cdr v-cache) #'b)))]]
|
||||||
|
|
||||||
|
The other cases are similarly defined:
|
||||||
|
|
||||||
|
@CHUNK[<recursive-replace-in-instance>
|
||||||
|
(define (recursive-replace stx-val type)
|
||||||
|
(define/with-syntax val stx-val)
|
||||||
|
(define/with-syntax (v-cache) (generate-temporaries #'(val-cache)))
|
||||||
|
(syntax-parse type
|
||||||
|
[x:id
|
||||||
|
#:attr assoc-from-to (cdr-stx-assoc #'x #'((from . (to . fun)) ...))
|
||||||
|
#:when (attribute assoc-from-to)
|
||||||
|
#:with (to-type . to-fun) #'assoc-from-to
|
||||||
|
(define/with-syntax (tmp) (generate-temporaries #'(x)))
|
||||||
|
;; TODO: Add predicate for to-type in the pattern.
|
||||||
|
#`(to-fun val)]
|
||||||
|
[((~literal List) a ...)
|
||||||
|
(define/with-syntax (tmp ...) (generate-temporaries #'(a ...)))
|
||||||
|
#`(let-values ([(tmp ...) (apply values val)])
|
||||||
|
(list #,@(stx-map recursive-replace #'(tmp ...) #'(a ...))))]
|
||||||
|
<replace-in-instance-case-pairof>
|
||||||
|
[((~literal Listof) a)
|
||||||
|
(define/with-syntax (tmp) (generate-temporaries #'(a)))
|
||||||
|
#`(map (λ ([tmp : a]) #,(recursive-replace #'tmp #'a))
|
||||||
|
val)]
|
||||||
|
[((~literal Vector) a ...)
|
||||||
|
(define/with-syntax (tmp ...) (generate-temporaries #'(a ...)))
|
||||||
|
(define/with-syntax (idx ...) (generate-indices #'(a ...)))
|
||||||
|
#`(let ([v-cache val])
|
||||||
|
(let ([tmp (vector-ref v-cache idx)]
|
||||||
|
...)
|
||||||
|
(vector #,@(stx-map recursive-replace
|
||||||
|
#'(tmp ...)
|
||||||
|
#'(a ...)))))]
|
||||||
|
[((~literal Vectorof) a)
|
||||||
|
(define/with-syntax (tmp) (generate-temporaries #'(a)))
|
||||||
|
#`(vector-map (λ ([tmp : a]) #,(recursive-replace #'tmp #'a))
|
||||||
|
val)]
|
||||||
|
[((~literal U) a ...)
|
||||||
|
#`(let ([v-cache val])
|
||||||
|
(cond
|
||||||
|
#,@(stx-map (λ (ta) (replace-in-union #'v-cache ta r))
|
||||||
|
#'(a ...))))]
|
||||||
|
[((~literal quote) a)
|
||||||
|
#'val]
|
||||||
|
[x:id
|
||||||
|
#'val]))]
|
||||||
|
|
||||||
|
For unions, we currently support only tagged unions, that is unions where each
|
||||||
|
possible type is a @tc[List] with a distinct @tc[tag] in its first element.
|
||||||
|
TODO: we currently don't check that each @tc[tag] is distinct.
|
||||||
|
|
||||||
@CHUNK[<replace-in-union>
|
@CHUNK[<replace-in-union>
|
||||||
(define (replace-in-union stx-v-cache t r)
|
(define (replace-in-union stx-v-cache t r)
|
||||||
(define/with-syntax v-cache stx-v-cache)
|
(define/with-syntax v-cache stx-v-cache)
|
||||||
|
@ -126,76 +216,34 @@ For example, one could replace all strings in a data structure by their length:
|
||||||
<replace-in-tagged-union-instance>]
|
<replace-in-tagged-union-instance>]
|
||||||
[_ (error "Type-replace on untagged Unions isn't supported yet!")]))]
|
[_ (error "Type-replace on untagged Unions isn't supported yet!")]))]
|
||||||
|
|
||||||
|
For cases of the union which are a tagged list, we use a simple guard, and call
|
||||||
|
@tc[recursive-replace] on the whole @tc[(List 'tag b ...)] type.
|
||||||
|
|
||||||
@CHUNK[<replace-in-tagged-union-instance>
|
@CHUNK[<replace-in-tagged-union-instance>
|
||||||
#`[(and (list? v-cache) (eq? 'tag (car v-cache)))
|
#`[(and (list? v-cache)
|
||||||
|
(not (null? v-cache))
|
||||||
|
(eq? 'tag (car v-cache)))
|
||||||
#,(recursive-replace #'v-cache t)]]
|
#,(recursive-replace #'v-cache t)]]
|
||||||
|
|
||||||
|
Handling freer forms of unions causes some problems:
|
||||||
|
|
||||||
@CHUNK[<replace-in-instance_old>
|
@itemlist[
|
||||||
(define-for-syntax (replace-in-instance val t r)
|
@item{There are some types without make-predicate, so we can't use
|
||||||
(define/with-syntax ([from to fun] ...) r)
|
@racket[(make-predicate T)] to know what case of the union we are in}
|
||||||
(define (recursive-replace stx-val type)
|
@item{There are some types for which there is no predicate, like function types
|
||||||
(define/with-syntax val stx-val)
|
with the same arity}
|
||||||
(syntax-parse type
|
@item{There are some types for which the type system doesn't acknowledge the
|
||||||
[x:id
|
predicates, e.g. @racket[(U (Vector Number) (Vector String String))]: we can't
|
||||||
#:attr assoc-from-to (cdr-stx-assoc #'x
|
even bound the type of @racket[(vector-ref x 0)] in that case, it defaults to
|
||||||
#'((from . (to . fun)) ...))
|
@racket[Any].}]
|
||||||
#:when (attribute assoc-from-to)
|
|
||||||
#:with (to-type . to-fun) #'assoc-from-to
|
These issues and possible solutions are addressed in more
|
||||||
(define/with-syntax (tmp) (generate-temporaries #'(x)))
|
detail in the
|
||||||
;; TODO: Add predicate for to-type in the pattern.
|
@hyperlink[(string-append "https://phc.fogbugz.com/f/cases/54/"
|
||||||
#`(match-abort val [(and tmp) (protected (to-fun tmp))])]
|
"Rethink-how-to-do-the-multi-step-types-more-inside")]
|
||||||
[((~literal List) a ...)
|
{FogBugz case 54}.
|
||||||
(define/with-syntax (tmp1 ...) (generate-temporaries #'(a ...)))
|
|
||||||
(define/with-syntax (tmp2 ...) (generate-temporaries #'(a ...)))
|
@section{Conclusion}
|
||||||
(define/with-syntax (rec ...)
|
|
||||||
(stx-map recursive-replace #'(tmp1 ...) #'(a ...)))
|
|
||||||
#`(match-abort val
|
|
||||||
[(list tmp1 ...)
|
|
||||||
(let-abort ([tmp2 rec] ...)
|
|
||||||
(protected (list (unprotect tmp2) ...)))])]
|
|
||||||
[((~literal Pairof) a b)
|
|
||||||
(define/with-syntax (tmpa1 tmpb1) (generate-temporaries #'(a b)))
|
|
||||||
(define/with-syntax (tmpa2 tmpb2) (generate-temporaries #'(a b)))
|
|
||||||
(define/with-syntax reca (recursive-replace #'tmpa1 #'a))
|
|
||||||
(define/with-syntax recb (recursive-replace #'tmpb1 #'b))
|
|
||||||
#'(match-abort val
|
|
||||||
[(cons tmpa1 tmpb1)
|
|
||||||
(let-abort ([tmpa2 reca] [tmpb2 recb])
|
|
||||||
(protected (cons (unprotect tmpa2)
|
|
||||||
(unprotect tmpb2))))])]
|
|
||||||
#| TODO: |#
|
|
||||||
[((~literal Listof) a)
|
|
||||||
(define/with-syntax (tmp1) (generate-temporaries #'(a)))
|
|
||||||
(define/with-syntax (tmp1x) (generate-temporaries #'(a)))
|
|
||||||
(define/with-syntax rec (recursive-replace #'tmp1x #'a))
|
|
||||||
#'(match-abort val
|
|
||||||
[(list tmp1 (... ...))
|
|
||||||
(map-abort tmp1 tmp1x rec)])]
|
|
||||||
[((~literal Vector) a ...)
|
|
||||||
(define/with-syntax (tmp1 ...) (generate-temporaries #'(a ...)))
|
|
||||||
(define/with-syntax (tmp2 ...) (generate-temporaries #'(a ...)))
|
|
||||||
(define/with-syntax (rec ...)
|
|
||||||
(stx-map recursive-replace #'(tmp1 ...) #'(a ...)))
|
|
||||||
#`(match-abort val
|
|
||||||
[(vector tmp1 ...)
|
|
||||||
(let-abort ([tmp2 rec] ...)
|
|
||||||
(protected (list (unprotect tmp2) ...)))])]
|
|
||||||
#| TODO:
|
|
||||||
[((~literal Vectorof) a)
|
|
||||||
#`(Vectorof #,(recursive-replace #'a))]
|
|
||||||
;|#
|
|
||||||
[((~literal U) a ...)
|
|
||||||
(define/with-syntax (tmp1 ...) (generate-temporaries #'(a ...)))
|
|
||||||
(define/with-syntax (rec ...)
|
|
||||||
(stx-map recursive-replace #'(tmp1 ...) #'(a ...)))
|
|
||||||
#`(match-abort val
|
|
||||||
[tmp1 rec]
|
|
||||||
...)]
|
|
||||||
[x:id
|
|
||||||
#'(protected val)]))
|
|
||||||
;; TODO: if we recieve a 'continue or 'break, give a type error.
|
|
||||||
#`(unprotect #,(recursive-replace val t)))]
|
|
||||||
|
|
||||||
@chunk[<*>
|
@chunk[<*>
|
||||||
(begin
|
(begin
|
||||||
|
@ -209,10 +257,10 @@ For example, one could replace all strings in a data structure by their length:
|
||||||
"../type-expander/multi-id.lp2.rkt"
|
"../type-expander/multi-id.lp2.rkt"
|
||||||
"../type-expander/type-expander.lp2.rkt"
|
"../type-expander/type-expander.lp2.rkt"
|
||||||
"cond-abort.rkt")
|
"cond-abort.rkt")
|
||||||
(begin-for-syntax (provide replace-in-data-structure
|
(begin-for-syntax (provide replace-in-type
|
||||||
replace-in-instance))
|
replace-in-instance))
|
||||||
|
|
||||||
<replace-in-data-structure>
|
<replace-in-type>
|
||||||
<replace-in-instance>)
|
<replace-in-instance>)
|
||||||
|
|
||||||
(require 'main)
|
(require 'main)
|
||||||
|
@ -227,6 +275,8 @@ For example, one could replace all strings in a data structure by their length:
|
||||||
"../type-expander/type-expander.lp2.rkt"
|
"../type-expander/type-expander.lp2.rkt"
|
||||||
"cond-abort.rkt")
|
"cond-abort.rkt")
|
||||||
|
|
||||||
|
<test-make-replace>
|
||||||
<test-example>
|
<test-example>
|
||||||
|
<test-big>
|
||||||
|
|
||||||
(require (submod ".." doc))))]
|
(require (submod ".." doc))))]
|
|
@ -30,6 +30,10 @@ Blah @math{n}, as described by M@._ Foo@.__
|
||||||
(define (foo)
|
(define (foo)
|
||||||
(syntax-e #`#,"foo"))]
|
(syntax-e #`#,"foo"))]
|
||||||
|
|
||||||
|
@itemlist[
|
||||||
|
@item{Item 1}
|
||||||
|
@item{Item 2}]
|
||||||
|
|
||||||
@(define to-insert 42)
|
@(define to-insert 42)
|
||||||
@chunk[<*>
|
@chunk[<*>
|
||||||
;(displayln #,to-insert) ;; Should work.
|
;(displayln #,to-insert) ;; Should work.
|
||||||
|
@ -56,4 +60,4 @@ But we would actually want:
|
||||||
(define-syntax-rule (double x) -- should be greyed out
|
(define-syntax-rule (double x) -- should be greyed out
|
||||||
(let ((x-cache x))
|
(let ((x-cache x))
|
||||||
(+ x-cache x-cache))) -- everything except the changed bits should
|
(+ x-cache x-cache))) -- everything except the changed bits should
|
||||||
-- be greyed out]
|
-- be greyed out]
|
Loading…
Reference in New Issue
Block a user