Hi,
Papers often define parameterized metafunctions, reduction relations and
judgment forms, and when I model them in PLT Redex, I reach for Racket
parameters; but the resulting definitions are impure, and they invalidate
Redex’s cache. I first present three workarounds, none of which are
satisfactory, and then I propose two new Redex features that address this
issue.
PROBLEM
To ground our conversation, let us consider an example: in Abstracting
Abstract Machines (AAM),¹ page 726, we find the metafunction ‘tick’, which
takes the ‘k’ first elements of the list ‘(e : t)’.² The ‘k’ in question is
not an explicit argument of ‘tick’, but an analysis-wide parameter that is
in scope and remains the same for definitions across several pages. To
capture this intent, the following is a Redex model in which ‘k’ is a
Racket parameter:
#lang racket/base
(require redex/reduction-semantics racket/list)
(define k (make-parameter 0))
(define-language L
[e ::= any]
[t ::= [e ...]])
(define-metafunction L
tick : e _ _ _ t -> t
[(tick e _ _ _ t) ,(take (cons (term e) (term t)) (k))])
There is a problem with this definition, though, because ‘tick’ is
impure—it relies on the mutable external state of ‘k’—and Redex caches
metafunction applications:
(term (tick a _ _ _ []))
'()
(parameterize ([k 1])
(term (tick b _ _ _ [])))
'(b)
(parameterize ([k 1])
(term (tick a _ _ _ [])))
'()
The first two interactions illustrate the desired behavior: on the first,
the ‘a’ is discarded because it overflows the default maximum list size ‘k
= 0’; on the second, we bump ‘k = 1’ and ‘tick’ returns the list containing
‘b’. But things go wrong in the third interaction, when we try again to add
‘a’ to the empty list, this time with ‘k = 1’: Redex has cached the
previous answer, so ‘tick’ wrongly discards ‘a’.
WORKAROUNDS
Workaround 1: Disable the Cache
We set ‘caching-enabled? = #f’ whenever we parameterize ‘k’. This
deteriorates performance.
Workaround 2: Thread the Parameter
Don’t have ‘k’ as a Racket parameter, and modify every definition to
propagate ‘k’ as an argument. This clutters the model and sets it apart
from the version on the paper.
Workaround 3: Use a macro
#lang racket/base
(require (for-syntax racket/base racket/syntax) syntax/parse/define
redex/reduction-semantics racket/list syntax/parse/define)
(define-syntax-parser analysis
[(_ k:integer)
(with-syntax ([L (format-id #'k "L~a" (syntax-e #'k))]
[tick (format-id #'k "tick~a" (syntax-e #'k))])
#'(begin
(define-language L
[e ::= any]
[t ::= [e (... ...)]])
(define-metafunction L
tick : e _ _ _ t -> t
[(tick e _ _ _ t) ,(take (cons (term e) (term t)) k)])))])
We can instantiate different analyses for our choice of ‘k’:
(analysis 0)
(analysis 1)
(term (tick0 a _ _ _ []))
'()
(term (tick1 b _ _ _ []))
'(b)
(term (tick1 a _ _ _ []))
'(a)
This has many issues: it is harder to read and write; it requires escaping
ellipses (see ‘(... ...)’ above); it binds the name ‘k’ in all contexts,
including undesirable ones, for example, ‘(term k)’; it may break
typesetting; it insists that ‘k’ is a literal number, not an expression
that evaluates to a number; and it may be bad for compilation performance.
Some of these issues are solved by writing even more incantations, but not
all.
SOLUTIONS
Currently, I’m using Workaround 1, disabling the cache, but I wish for a
lighter hammer. The simplest thing that comes to mind is a way for me to
flush Redex’s cache when I parameterize ‘k’. This would be a good
compromise: I’d still write a simple and correct model, and I’d leverage at
least some of the performance benefits of caching. Unfortunately, cache
invalidation continues to be one of the *hard problems* in computer
science. I tried to disable and reenable the cache. I tried to
‘set-cache-size!’ to a low number and then back again. Nothing worked.
Going further, we could introduce a ‘define-metaparameter’ form to Redex. A
metaparameter is parameterizeable like a Racket parameter, but we can use
it like a regular term in Redex definitions and the cache is aware of it.
* * *
Thoughts are appreciated. Is there a better way to accomplish my goal? Is
it a valid thing to want in the first place?
Parametrically confused,
Leandro.
* * *
¹ Van horn, David, and Matthew Might. 2012. “Systematic Abstraction of
Abstract Machines.” J. Funct. Program. 22 (4–5): 705–746.
https://doi.org/10.1017/S0956796812000238.
² Similar to ‘take’ from ‘racket/list’.
--
You received this message because you are subscribed to the Google Groups
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.