【问题标题】:build-list (error - expects a procedure) Racket/Scheme构建列表(错误 - 需要一个程序)球拍/方案
【发布时间】:2012-03-25 04:15:03
【问题描述】:

尝试制作一个产生 n × n 板的函数

(new-board 2)

应该产生

(list (make-posn 0 0) (make-posn 0 1) (make-posn 1 0) (make-posn 1 1))

我的代码的当前版本如下:

(define (new-board y)
    (build-list y (lambda (x) (build-list x (make-posn y x))))
      )

我很确定它会起作用,但鉴于我目前在 Racket 方面的知识和经验,我找不到错误。

我输入了:

> (new-board 3)

并得到错误:

build-list: expects a procedure (arity 1); given (make-posn 3 0)

我在构建列表中调用构建列表是否犯下了滔天罪行? 请告诉我。谢谢!

【问题讨论】:

    标签: scheme racket


    【解决方案1】:

    关于这个程序:

    (define (new-board y)
        (build-list y (lambda (x) (build-list x 
                                              (make-posn y x))))) ;error!
    

    让我们看看build-list 接收到什么作为参数。第一个参数是y,一个数字,第二个参数是一个过程,但您传递的是评估make-posn的结果,这不是一个过程,它是一个值。这就是您遇到错误的原因。

    编辑 1:

    现在我明白你的意图了。我可以想到一个解决方案,但它比你想象的要复杂一点:

    (define (new-board n)
      (flatten
       (map (lambda (x)
              (map (lambda (y)
                     (make-posn x y))
                   (build-list n identity)))
            (build-list n identity))))
    
    (define (flatten lst)
      (if (not (list? lst))
          (list lst)
          (apply append (map flatten lst))))
    

    它是这样工作的:

    • build-list 只是用于生成从0n-1 的数字,我将identity 作为过程传递,因为每个数字都不需要进一步处理
    • 对于列表中的每个数字,我们还想生成另一个列表,再次从0n-1,因为需要棋盘中的所有坐标。例如,如果 n 为 3,则坐标为 '((0 0) (0 1) (0 2) (1 0) (1 1) (1 2) (2 0) (2 1) (2 2))
    • 我在map 中使用map 来构建嵌套列表,这是一种从here 借用的技术(请参阅:“嵌套映射”)
    • 最后,我必须展平生成的列表,这就是 flatten 所做的(否则,我们会以列表列表结束)

    编辑 2:

    想想看,我找到了一个更简单的方法,更接近你的想法。请注意,flatten 过程是不可避免的:

    (define (new-board n)
      (flatten
       (build-list n
                   (lambda (x)
                     (build-list n
                                 (lambda (y)
                                   (make-posn x y)))))))
    

    现在,当您输入以下内容时:

    (new-board 2)
    

    结果如预期:

    (#(struct:posn 0 0) #(struct:posn 0 1) #(struct:posn 1 0) #(struct:posn 1 1))
    

    【讨论】:

    • 啊,我猜是遗漏了程序的整体意图是个错误。这是解决 n-Queens 问题的前奏。尽管我还没有准备好这样做,因为我仍然无法解决这个简单程序中的问题。是的,它应该产生一个 posns 列表。虽然我完全明白你为什么会这样问! :P
    • @WhiteBit 不管怎样,你应该把build-listmake-posn 的代码贴出来,否则我们就一头雾水了
    • 另外,build-list 是一个内置函数。 (build-list n proc) → list (build-list 5 add1) 将产生 (list 1 2 3 4 5) // (make-posn n n) 创建一个具有两个数字的结构 posn。 (我通常将它用作关联数组,但这次它用于表示板上的图块。)
    • @WhiteBit 我忽略了这个事实。我编辑了我的答案,现在错误很明显。请发布make-posn,以及您期望从new-board 获得的输出的示例 - 列表(list (make-posn 0 0) (make-posn 0 1) (make-posn 1 0) (make-posn 1 1)) 或评估列表中每个元素的make-posn结果跨度>
    • 我认为 (make-posn) 听起来如此陌生的原因可能是它仅在如何设计程序的初级学生计划中引入。好吧,这是make-posn。 make-posn : (number number -> posn)。大概是这样定义的: (define-struct posn (x y)) 其中 x 和 y 是数字。希望清除它。感谢您的时间奥斯卡!
    【解决方案2】:

    如果你查看build-list1的签名(合同),你会发现它是

     build-list : Nat (Nat -> X) -> (listof X)
    

    所以它需要一个(自然)数,然后是一个 函数,它需要一个自然数并返回一个您希望包含在列表中的类型 (X) 的元素。因此,在您的情况下,您希望 X 对于您向build-list 进行的每次调用都是什么特定类型(在每种情况下都可能不同)。在内部build-list 的情况下,看起来您正在尝试制作posns 的列表。但是,(make-posn y x) 会立即生成一个 posn,而不是 build-list 所期望的函数。因此,正如您向外部 build-list 提供函数 (lambda (x) ...) 一样,您也应该向内部函数提供函数 (lambda (...) ...)

    为第一个 lambda 的参数选择名称 x 可能有点令人困惑。我可能会做的是将new-board 函数参数的名称更改为N,因为您似乎想要创建一个N 行(和列)的板。第一个build-list 的目的是创建这些行中的每一行(或列,取决于您的想法)。所以如果你有:

     (define (new-board N)
       (build-list N (lambda (x) ...)))
    

    然后你像这样使用它:

     (new-board 5)
    

    它将减少/简化/评估如下:

     ==> (build-list 5 (lambda (x) ...))
     ==> (list ( (lambda (x) (build-list ... x ...))  0 )
               ( (lambda (x) (build-list ... x ...))  1 )
               ( (lambda (x) (build-list ... x ...))  2 )
               ( (lambda (x) (build-list ... x ...))  3 )
               ( (lambda (x) (build-list ... x ...))  4 )
     ==> (list (build-list ... 0 ...)
               (build-list ... 1 ...)
               (build-list ... 2 ...)
               (build-list ... 3 ...)
               (build-list ... 4 ...))
    

    所以,嵌套build-list 没有任何问题。看看你现在是否能弄清楚一旦当前行被固定为特定的x 值,如何让内部构建列表生成一个 posns 列表。

    【讨论】:

      【解决方案3】:

      顺便说一句,如果你被允许使用完整的 Racket,有一个很好的方法来表达 for 循环的计算:

      (define (new-board n)
        (for*/list ([i n]
                    [j n])
          (make-posn i j)))
      

      获得相同结果但采用不同方法的另一种方法是使用quotientremainder 的算术技巧。

      (define (new-board n)
        (build-list (* n n)
                    (lambda (k)
                      (make-posn (quotient k n)
                                 (remainder k n)))))
      

      【讨论】:

        猜你喜欢
        • 2021-01-24
        • 2021-01-07
        • 1970-01-01
        • 2018-12-20
        • 2012-02-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-12-08
        相关资源
        最近更新 更多