From 02bce8b7d8d34709abc1dacd96de01c9be95a2ce Mon Sep 17 00:00:00 2001 From: Jack Firth Date: Fri, 30 Aug 2024 20:11:22 -0700 Subject: [PATCH] Add `map-to-for` refactoring (#254) This is similar to `for-each-to-for` but for refactoring `map` into `for/list`. --- .../for-loop-shortcuts-test.rkt | 99 +++++++++++++++++++ .../for-loop-shortcuts.rkt | 10 ++ 2 files changed, 109 insertions(+) diff --git a/default-recommendations/for-loop-shortcuts-test.rkt b/default-recommendations/for-loop-shortcuts-test.rkt index a677f06..c2eba49 100644 --- a/default-recommendations/for-loop-shortcuts-test.rkt +++ b/default-recommendations/for-loop-shortcuts-test.rkt @@ -8,6 +8,105 @@ header: - #lang racket/base +test: "map with short single-form body not refactorable" +------------------------------ +(define some-list (list 1 2 3)) +(map (λ (x) (* x 2)) some-list) +------------------------------ + + +test: "map with long single-form body to for/list" +------------------------------ +(define some-list (list 1 2 3)) +(map + (λ (a-very-very-very-long-variable-name-thats-so-very-long) + (* a-very-very-very-long-variable-name-thats-so-very-long 2)) + some-list) +------------------------------ +------------------------------ +(define some-list (list 1 2 3)) +(for/list ([a-very-very-very-long-variable-name-thats-so-very-long (in-list some-list)]) + (* a-very-very-very-long-variable-name-thats-so-very-long 2)) +------------------------------ + + +test: "map with multiple body forms to for/list" +------------------------------ +(define some-list (list 1 2 3)) +(map + (λ (x) + (define y (* x 2)) + (+ x y)) + some-list) +------------------------------ +------------------------------ +(define some-list (list 1 2 3)) +(for/list ([x (in-list some-list)]) + (define y (* x 2)) + (+ x y)) +------------------------------ + + +test: "map with let expression to for/list with definitions" +------------------------------ +(define some-list (list 1 2 3)) +(map (λ (x) (let ([y 1]) (+ x y))) some-list) +------------------------------ +------------------------------ +(define some-list (list 1 2 3)) +(for/list ([x (in-list some-list)]) + (define y 1) + (+ x y)) +------------------------------ + + +test: "map range to for/list" +------------------------------ +(require racket/list) +(map + (λ (x) + (define y 1) + (+ x y)) + (range 0 10)) +------------------------------ +------------------------------ +(require racket/list) +(for/list ([x (in-range 0 10)]) + (define y 1) + (+ x y)) +------------------------------ + + +test: "map string->list to for/list in-string" +------------------------------ +(map + (λ (c) + (displayln c) + (char-upcase c)) + (string->list "hello")) +------------------------------ +------------------------------ +(for/list ([c (in-string "hello")]) + (displayln c) + (char-upcase c)) +------------------------------ + + +test: "map bytes->list to for/list in-bytes" +------------------------------ +(map + (λ (b) + (displayln b) + (* b 2)) + (bytes->list #"hello")) +------------------------------ +------------------------------ +(for/list ([b (in-bytes #"hello")]) + (displayln b) + (* b 2)) +------------------------------ + + test: "for-each with short single-form body not refactorable" ------------------------------ (define some-list (list 1 2 3)) diff --git a/default-recommendations/for-loop-shortcuts.rkt b/default-recommendations/for-loop-shortcuts.rkt index 81d123c..e6b1782 100644 --- a/default-recommendations/for-loop-shortcuts.rkt +++ b/default-recommendations/for-loop-shortcuts.rkt @@ -142,6 +142,15 @@ #:with (body ...) #'(only-body))) +(define-refactoring-rule map-to-for + #:description "This `map` operation can be replaced with a `for/list` loop." + #:literals (map) + [(map function:worthwhile-loop-body-function loop:for-clause-convertible-list-expression) + ((~if loop.flat? for/list for*/list) + (loop.leading-clause ... [function.x loop.trailing-expression]) + function.body ...)]) + + (define-refactoring-rule for-each-to-for #:description "This `for-each` operation can be replaced with a `for` loop." #:literals (for-each) @@ -303,6 +312,7 @@ for-each-to-for list->set-to-for/set list->vector-to-for/vector + map-to-for named-let-loop-to-for/first-in-vector nested-for-to-for* or-in-for/and-to-filter-clause