首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在lisp中嵌套循环来处理2d数组-什么是好的样式(有和/或没有循环宏)?

在lisp中嵌套循环来处理2d数组-什么是好的样式(有和/或没有循环宏)?
EN

Code Review用户
提问于 2019-04-19 14:49:38
回答 1查看 1.1K关注 0票数 1

下面的代码是对Paul的ANSI Common (前例)中的练习的回答。4.1)。挑战是将数组旋转90度。我找到了一个示例解决方案,我在下面作了评论。

这似乎没问题,我很喜欢学习如何使用do,但在这种特殊情况下,它实际上似乎比用于处理2d数组的家族c样式嵌套的循环更加冗长。我想知道下面的款式是好的还是可以改进的?

答案是循环宏吗?在学习的同时,我正在避免这种情况,直到我更好地掌握了基本知识。但却不想染上坏习惯。因此,这个关于风格的问题与下文有关。

代码语言:javascript
复制
(defun quarter-turn (arr)
  (let* ((dim (array-dimensions arr))  ; let* sets sequentially, not in parallel.
         (row (first dim))
         (col (second dim))
         (n row)  ; initialise n to row, just to organise
         new-arr) ; shorthand for (new-arr nil)
    (cond ((not (= row col))
           (format t "The arg is not a square array.~%"))
          (t (setf new-arr (make-array dim :initial-element nil))
             (do ((i 0 (+ i 1)))  ; Q. surprisingly, lisp's 'do' here looks more
                 ((= i n))        ; verbose than c-style 'for'. Is this good style?
                 (do ((j 0 (+ j 1)))
                     ((= j n))
                     (setf (aref new-arr j i) (aref arr (- n i 1) j))))
             new-arr))))

以上代码的来源:http://www.cs.uml.edu/~lhao/ai/lisp/ansi-common-lisp/solution-ch04.htm

EN

回答 1

Code Review用户

回答已采纳

发布于 2019-04-19 17:26:30

关于您的代码的一些评论:

  1. 为什么要引入另一个变量的新变量n副本?如果您想更加简洁,可以在nm中使用rowcol (我不喜欢它们,因为它们是单数名称,而它们代表行数和列数)。
  2. 为什么在测试之前定义new-arr,然后在测试的正方形之后分配它呢?不要在需要的情况下多次使用let,在需要的时候引入变量。
  3. 使用assert而不是cond来检查是否有正确的参数:通过这种方式,您可以给用户纠正参数的机会,并产生更短、更易读的代码。
  4. 为什么要将新数组初始化为立即被覆盖的值nil
  5. 第一个do可以返回结果,以避免函数的最后一行。
  6. 使用原语函数1+,而不是1求和。
  7. 记录该函数,并对其范围作为函数主体的第一种形式进行注释。

因此,在这第一组注释之后,函数可以重写为:

代码语言:javascript
复制
(defun quarter-turn (arr)
  "rotate a square matrix 90° clockwise"
  (let* ((dim (array-dimensions arr))
         (n (first dim))
         (m (second dim)))
    (assert (= n m) (arr) "The argument is not a square array.")
    (let ((new-arr (make-array dim)))
      (do ((i 0 (1+ i)))
          ((= i n) new-arr)
        (do ((j 0 (1+ j)))
            ((= j n))
          (setf (aref new-arr j i) (aref arr (- n i 1) j)))))))

DO与循环

正如您已经注意到的,在本例中,doloop更冗长。我认为,在这种情况下,它们或多或少是等同的(只是个人意见)。我更喜欢loop表单,这不仅是因为在我看来它略显简洁,而且还因为用两种嵌套loop表单的术语来考虑二维数组的经典嵌套循环更“自然”:

代码语言:javascript
复制
(defun quarter-turn (arr)
  "rotate a square matrix 90° clockwise"
  (let* ((dim (array-dimensions arr))
         (n (first dim))
         (m (second dim)))
    (assert (= n m) (arr) "The argument is not a square array.")
    (let ((new-arr (make-array dim)))
      (loop for i below n
            do (loop for j below n
                     do (setf (aref new-arr j i) (aref arr (- n i 1) j))))
      new-arr)))
票数 3
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/217739

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档