/
fresh.rkt
64 lines (59 loc) · 1.9 KB
/
fresh.rkt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#lang racket/base
(require racket/contract
racket/set)
(define (variable-not-in sexp var)
(define var-str (symbol->string var))
(define var-prefix
(let ([m (regexp-match #rx"^(.*[^0-9])[0-9]+$" var-str)])
(if m
(cadr m)
var-str)))
(define found-exact-var? #f)
(define nums
(let loop ([sexp sexp]
[nums (set)])
(cond
[(pair? sexp) (loop (cdr sexp) (loop (car sexp) nums))]
[(symbol? sexp)
(when (equal? sexp var)
(set! found-exact-var? #t))
(define str (symbol->string sexp))
(define match (regexp-match #rx"([0-9]+)$" str))
(if (and match
(is-prefix? var-prefix str))
(set-add nums (string->number (list-ref match 1)))
nums)]
[else nums])))
(cond
[(not found-exact-var?) var]
[(set-empty? nums) (string->symbol (format "~a1" var))]
[else (string->symbol (format "~a~a" var-prefix (find-best-number nums)))]))
(define (find-best-number nums)
(let loop ([sorted (sort (set->list nums) <)]
[i 1])
(cond
[(null? sorted) i]
[else
(define fst (car sorted))
(cond
[(< i fst) i]
[(> i fst) (loop (cdr sorted) i)]
[(= i fst) (loop (cdr sorted) (+ i 1))])])))
(define (variables-not-in sexp vars)
(let loop ([vars vars]
[sexp sexp])
(cond
[(null? vars) null]
[else
(define new-var (variable-not-in sexp (car vars)))
(cons new-var
(loop (cdr vars)
(cons new-var sexp)))])))
(define (is-prefix? str1 str2)
(and (<= (string-length str1) (string-length str2))
(for/and ([c1 (in-string str1)]
[c2 (in-string str2)])
(equal? c1 c2))))
(provide/contract
[variable-not-in (any/c symbol? . -> . symbol?)]
[variables-not-in (any/c (listof symbol?) . -> . (listof symbol?))])