缩短重复的代码行

时间:2016-06-27 05:59:42

标签: loops for-loop recursion scheme racket

我正在使用temp将搜索列表中的值保留为临时值,从最大数量的temp(temp-5)开始到最小数量的temp(temp-1)。我想在search-list的undo功能中添加这个功能。如果我使用temp-100而不是temp-1到temp-5,如何将代码行缩短为循环?如果我使用“for loop”,我在哪里放cond?

#lang racket
(define temp-flag 0)
(define temp-1 '())
(define temp-2 '())
(define temp-3 '())
(define temp-4 '())
(define temp-5 '())
(define search-list '(1 2 3 4 5 6 7 8 9 10))
(define (place-temp tf)
  (cond
    [(equal? tf 1)
     (set! temp-1 search-list)
     (set! temp-flag 5)]
    [(equal? tf 2)
     (set! temp-2 search-list)
     (set! temp-flag 1)]
    [(equal? tf 3)
     (set! temp-3 search-list) (set! temp-flag 2)]
    [(equal? tf 4)
     (set! temp-4 search-list) (set! temp-flag 3)]
    [(set! temp-5 search-list) (set! temp-flag 4)]
    ))  

 (place-temp temp-flag)

1 个答案:

答案 0 :(得分:1)

问题的基本解决方案是Michael Vehrs所建议的。第一个(最少侵入性)尝试可能是这样的:

    (define temp-flag 0)
    (define search-list '(1 2 3 4 5 6 7 8 9 10))

    (define *num-of-temps* 5) ;; you will just have to change it to 100
    (define *temps* (make-vector *num-of-temps* '()))

    (define (next-temp-flag tf)
      (cond ((= tf 1) *num-of-temps*)
        ((and (> tf 1) (< tf *num-of-temps*)) (- tf 1))
        (else (- *num-of-temps* 1))))

    (define (place-temp tf)
      (vector-set! *temps* (- tf 1) search-list)
      (set! temp-flag (next-temp-flag tf)))

从temp-flag的角度来看,它的工作方式完全相同。但这不是一个很酷的程序,所以让我们尝试改进它。

首先,这个 next-temp-flag 有点奇怪,但它精确地模仿你的cond语句相对于 tf 的行为TEMP-标志。 我假设您仅使用 temp-flag 来索引 temp-1 temp-2 等,而您并不在意关于 tf 大于5(或100,或者通常比 * num-of-temps * )的更多信息。所以你可以先简化一点:

    (define (next-temp-flag tf)
      (if (= tf 1) *num-of-temps* (- tf 1)))

现在第二件事是向量(cf https://docs.racket-lang.org/reference/vectors.html)中的位置(''index'')从0开始,而不是1,所以例如你的 temp-1 现在是*(vector-ref temps 0)*。所以你可以像这样使用''减去 tf s':

    (define (next-temp-flag tf)
      (if (= tf 0) (- *num-of-temps* 1) (- tf 1)))

    (define (place-temp tf)
      (vector-set! *temps* tf search-list)
      (set! temp-flag (next-temp-flag tf)))

显然(或不是;))这个 next-temp-flag 现在可以用模数函数表示:

    (define (next-temp-flag tf) (modulo (- tf 1) *num-of-temps*))

...如果您想要更短的代码,您也可以在 place-temp 中内联它。

最后一件事是命名约定:也许你刚刚使用这些 define 来设置一个最小的例子,但如果你的项目中确实有这些''全局变量'',那么命名惯例是使用星号,所以你宁愿使用 * search-list * * temp-flag * 。 另请注意, place-temp 会导致副作用,因此您可能需要将其命名为 place-temp!。如果您计划仅将 place-temp!应用于 * temp-flag * ,则可以完全删除该参数。并且 * temp-position * 可能听起来比 * temp-flag * 更容易,因为它现在是一个位置。 总而言之,你可能会以这样的结局结束:

    (define *num-of-temps* 5) ;; you will just have to change it to 100
    (define *temps* (make-vector *num-of-temps* '()))

    (define *temp-position* (- *num-of-temps* 1)) ;; because (modulo -1 n) is n-1.
    (define *search-list* '(1 2 3 4 5 6 7 8 9 10))

    (define (place-temp!)
      (vector-set! *temps* *temp-position* *search-list*)
      (set! *temp-position* (modulo (- *temp-position* 1) *num-of-temps*)))

    (place-temp!)

对不起,这是一个很长的答案,但正如诗人所说''我没有足够的时间写一个较短的''。我还怀疑如果你想实现撤销,你可能想要别的东西(堆栈而不是循环缓冲区) - 但这超出了你的问题。

祝你的项目好运!

PS我希望当你习惯了方案时,你将更少依赖全局变量和程序,更多地依赖于本地绑定和函数(正如另一位诗人所说''保持功能我的朋友!'')。但事情需要时间,最重要的是你喜欢你的黑客行为。