racket/collects/tests/eopl/chapter7/inferred/substitutions.rkt
David Van Horn 7491e172ea EOPL test suite re-written in Racket-based #lang eopl and rackunit
The eopl language is now racket-based rather than mzscheme-based.  This
test-suite, which was originally distributed on the book's web-site has
been re-written in the new language.  Changes include dropping all
drscheme-init.scm and top.scm files.  Remaining files were renamed to
use the .rkt extension and edited to use the #lang syntax (instead of
modulue).  Require and provide forms were changed to reflect racket's
syntax instead of mzscheme's (eg, only-in vs. only).  Several
occurrences of one-armed ifs were changed to use when and unless.  All
tests have been run successfully.
2012-02-24 14:46:18 -05:00

106 lines
2.8 KiB
Racket
Executable File

#lang eopl
(require "lang.rkt")
(require "data-structures.rkt")
(provide substitution? empty-subst extend-subst apply-subst-to-type)
;;;;;;;;;;;;;;;; Unit substitution ;;;;;;;;;;;;;;;;
;; apply-one-subst: type * tvar * type -> type
;; (apply-one-subst ty0 var ty1) returns the type obtained by
;; substituting ty1 for every occurrence of tvar in ty0. This is
;; sometimes written ty0[tvar=ty1]
;; apply-one-subst : Type * Tvar * Type -> Type
;; Page: 260
(define apply-one-subst
(lambda (ty0 tvar ty1)
(cases type ty0
(int-type () (int-type))
(bool-type () (bool-type))
(proc-type (arg-type result-type)
(proc-type
(apply-one-subst arg-type tvar ty1)
(apply-one-subst result-type tvar ty1)))
(tvar-type (sn)
(if (equal? ty0 tvar) ty1 ty0)))))
;;;;;;;;;;;;;;;; Substitutions ;;;;;;;;;;;;;;;;
;; a substitution is a map from unknown types to types.
;; we'll represent this as an association list.
(define pair-of
(lambda (pred1 pred2)
(lambda (val)
(and (pair? val) (pred1 (car val)) (pred2 (cdr val))))))
(define substitution?
(list-of (pair-of tvar-type? type?)))
;; basic observer: apply-subst-to-type
;; this is sometimes written ty1.subst
;; apply-subst-to-type : Type * Subst -> Type
;; Page: 261
(define apply-subst-to-type
(lambda (ty subst)
(cases type ty
(int-type () (int-type))
(bool-type () (bool-type))
(proc-type (t1 t2)
(proc-type
(apply-subst-to-type t1 subst)
(apply-subst-to-type t2 subst)))
(tvar-type (sn)
(let ((tmp (assoc ty subst)))
(if tmp
(cdr tmp)
ty))))))
;; empty-subst : () -> Subst
;; produces a representation of the empty substitution.
;; extend-subst : Subst * Tvar * Type -> Subst
;; (extend-subst s tv t) produces a substitution with the property
;; that for all t0,
;; (apply-subst t0 (extend-subst s tv t))
;; = (apply-one-subst (apply-subst t0 s) tv t)
;; i.e., t0.(s[tv=t]) = (t0.s)[tv=t]
;; this means that for any type variable tv0 in the domain of s,
;; (apply-subst tv0 (extend-subst s tv t))
;; = (apply-one-subst (apply-subst tv0 s) tv t)
;; so we extend the substitution with a new element, and apply [t/v] to every
;; element already in the substitution.
;; empty-subst : () -> Subst
;; Page 262
(define empty-subst (lambda () '()))
;; extend-subst : Subst * Tvar * Type -> Subst
;; usage: tvar not already bound in subst.
;; Page: 262
(define extend-subst
(lambda (subst tvar ty)
(cons
(cons tvar ty)
(map
(lambda (p)
(let ((oldlhs (car p))
(oldrhs (cdr p)))
(cons
oldlhs
(apply-one-subst oldrhs tvar ty))))
subst))))