Search code examples
racketplt-redex

plt-redex: capture-avoiding substitution for free?


Every time I define a language in PLT redex, I need to manually define a (capture-avoiding) substitution function. For example, this model isn't finished because subst isn't defined:

#lang racket/base
(require redex/reduction-semantics)

(define-language Λ
  [V ::= x (λ x M)]
  [M ::= (M M) V]
  [C ::= hole (V C) (C M)]
  [x ::= variable-not-otherwise-mentioned])

(define -->β
  (reduction-relation Λ
    [--> (in-hole C ((λ x M) V))
         (in-hole C (subst M x V))]))

But the definition of subst is obvious. Can PLT redex handle substitution automatically?


Solution

  • Yes! Just describe your language's binding structure with a #:binding-forms declaration.

    Here's a similar model with capture-avoiding substitution via the substitute function:

    #lang racket/base
    (require redex/reduction-semantics)
    
    (define-language Λ
      [V ::= x (λ x M)]
      [M ::= (M M) V]
      [C ::= hole (V C) (C M)]
      [x ::= variable-not-otherwise-mentioned]
      #:binding-forms
      (λ x M #:refers-to x)) ;; "term M refers to the variable x"
    
    (define -->β
      (reduction-relation Λ
        [--> (in-hole C ((λ x M) V))
             (in-hole C (substitute M x V))]))
    
    (apply-reduction-relation -->β
      (term ((λ x (λ y x)) y)))
    ;; '((λ y«2» y))
    

    Alphabetic equivalence comes for free too, see alpha-equivalent?

    (Thank you Paul Stansifer!)