4

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?

Ben Greenman
  • 1,945
  • 12
  • 22

1 Answers1

5

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!)

Ben Greenman
  • 1,945
  • 12
  • 22
  • 1
    Hey, Ben! Me and at least one more person (also an unexperienced racketer) had hard time to parse `refers-to` clause. In particular, it was not clear, that the term which can refer to the bounded variable is the one closest to `#:refers-to` to the left. In good old lambda this doesn't matter. In the case of `let x = M in M` it becomes relevant. Maybe, for the sake of future generations, it would be useful to note that `(let x = M in M #:refers-to x)` works just as expected. Namely, `x` becomes bound just in the second `M`. – Artem Pelenitsyn Jul 08 '17 at 06:56