Skip to content

Commit f601f73

Browse files
authored
Add named-let-loop-to-for/first-in-naturals rule (#621)
1 parent bfcb395 commit f601f73

File tree

2 files changed

+66
-17
lines changed

2 files changed

+66
-17
lines changed

default-recommendations/named-let-loopification-test.rkt

Lines changed: 37 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,36 @@ no-change-test: "named let loop over counter not refactorable when loop function
3333
------------------------------------------------------------
3434

3535

36+
test: "named let loop can be refactored to for/first with in-naturals"
37+
------------------------------------------------------------
38+
(define (f c g)
39+
(let loop ([i 0])
40+
(cond
41+
[(c i)
42+
(loop (+ i 1))]
43+
[else
44+
(g i)])))
45+
============================================================
46+
(define (f c g)
47+
(for/first ([i (in-naturals 0)]
48+
#:unless (c i))
49+
(g i)))
50+
------------------------------------------------------------
51+
52+
53+
no-change-test: "named let loop not refactorable to for/first with in-naturals when loop referenced"
54+
------------------------------------------------------------
55+
(define (f c g)
56+
(let loop ([i 0])
57+
(cond
58+
[(c i)
59+
(loop (+ i 1))]
60+
[else
61+
(displayln loop)
62+
(g i)])))
63+
------------------------------------------------------------
64+
65+
3666
test: "named let loop with conditional return over vector can be replaced by for/first"
3767
------------------------------------------------------------
3868
(define vec (vector 0 1 2 3 4 5))
@@ -68,8 +98,7 @@ test: "named let loop over list can be replaced by for/list"
6898
(displayln (car xs))
6999
(cons (* (car xs) 10)
70100
(loop (cdr xs)))]))
71-
------------------------------------------------------------
72-
------------------------------------------------------------
101+
============================================================
73102
(require racket/list)
74103
(let loop ([xs (list 1 2 3)])
75104
(cond
@@ -78,8 +107,7 @@ test: "named let loop over list can be replaced by for/list"
78107
(displayln (first xs))
79108
(cons (* (first xs) 10)
80109
(loop (rest xs)))]))
81-
------------------------------------------------------------
82-
------------------------------------------------------------
110+
============================================================
83111
(require racket/list)
84112
(for/list ([x (in-list (list 1 2 3))])
85113
(displayln x)
@@ -97,8 +125,7 @@ test: "named let loop can be replaced with for/and when equivalent"
97125
[(and (big? (first xs)) (not (red? (car xs))))
98126
(loop (rest xs))]
99127
[else #false])))
100-
------------------------------------------------------------
101-
------------------------------------------------------------
128+
============================================================
102129
(require racket/list)
103130
(define (f xs big? red?)
104131
(for/and ([x (in-list xs)])
@@ -115,8 +142,7 @@ test: "named let loop can be replaced with for/or when equivalent"
115142
[(empty? xs) #false]
116143
[(and (big? (first xs)) (not (red? (car xs)))) #true]
117144
[else (loop (rest xs))])))
118-
------------------------------------------------------------
119-
------------------------------------------------------------
145+
============================================================
120146
(require racket/list)
121147
(define (f xs big? red?)
122148
(for/or ([x (in-list xs)])
@@ -125,14 +151,14 @@ test: "named let loop can be replaced with for/or when equivalent"
125151

126152

127153
test: "read-until-eof loop refactorable to for loop with in-port"
128-
--------------------
154+
------------------------------------------------------------
129155
(define (print-reads)
130156
(let loop ([v (read)])
131157
(unless (eof-object? v)
132158
(displayln v)
133159
(loop (read)))))
134-
====================
160+
============================================================
135161
(define (print-reads)
136162
(for ([v (in-port)])
137163
(displayln v)))
138-
--------------------
164+
------------------------------------------------------------

default-recommendations/named-let-loopification.rkt

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -131,20 +131,42 @@
131131
modified-element-condition))
132132

133133

134+
(define-refactoring-rule named-let-loop-to-for/first-in-naturals
135+
#:description
136+
"This named `let` expression can be replaced by a simpler, equivalent `for/first` loop."
137+
#:literals (let cond else + add1)
138+
139+
(let loop:id ([i:id start:expr])
140+
(cond
141+
[condition:expr
142+
(loop2:id (~or (+ i2:id 1) (add1 i2:id)))]
143+
[else
144+
body:expr ...+]))
145+
#:when (free-identifier=? (attribute loop) (attribute loop2))
146+
#:when (free-identifier=? (attribute i) (attribute i2))
147+
#:when (not (syntax-find-first #'(condition body ...)
148+
id:id #:when (free-identifier=? (attribute id) (attribute loop))))
149+
150+
(for/first ([i (in-naturals start)]
151+
#:unless condition)
152+
body ...))
153+
154+
134155
(define-refactoring-rule named-let-loop-to-for/first-in-vector
135-
#:description "This loop can be replaced by a simpler, equivalent `for/first` loop."
156+
#:description
157+
"This named `let` expression can be replaced by a simpler, equivalent `for/first` loop."
136158
#:literals (let add1 + vector-length vector-ref if and <)
137159
(let loop1:id ([i1:id 0])
138160
(and (< i2:id (vector-length vec1:id))
139161
(let ([x:id (vector-ref vec2:id i3:id)])
140162
(if condition:expr
141163
true-branch:expr
142164
(loop2:id (~or (add1 i4:id) (+ i4:id 1) (+ 1 i4:id)))))))
143-
#:when (and (log-resyntax-rule-condition (free-identifier=? #'loop1 #'loop2))
144-
(log-resyntax-rule-condition (free-identifier=? #'i1 #'i2))
145-
(log-resyntax-rule-condition (free-identifier=? #'i1 #'i3))
146-
(log-resyntax-rule-condition (free-identifier=? #'i1 #'i4))
147-
(log-resyntax-rule-condition (free-identifier=? #'vec1 #'vec2)))
165+
#:when (free-identifier=? #'loop1 #'loop2)
166+
#:when (free-identifier=? #'i1 #'i2)
167+
#:when (free-identifier=? #'i1 #'i3)
168+
#:when (free-identifier=? #'i1 #'i4)
169+
#:when (free-identifier=? #'vec1 #'vec2)
148170
(for/first ([x (in-vector vec1)] #:when condition)
149171
true-branch))
150172

@@ -166,6 +188,7 @@
166188
(define-refactoring-suite named-let-loopification
167189
#:rules (named-let-loop-to-for-in-range
168190
named-let-loop-to-for/and
191+
named-let-loop-to-for/first-in-naturals
169192
named-let-loop-to-for/first-in-vector
170193
named-let-loop-to-for/list
171194
named-let-loop-to-for/or

0 commit comments

Comments
 (0)