为什么我的计划程序最终没有正确地合并我的两个列表?

时间:2016-03-08 05:47:18

标签: scheme racket

(define unzip (lambda (l)

            (define front (lambda (a)

            (if (null? a)
                '()
                 (cons (car (car a)) (unzip (cdr a)))
            )))

            (define back (lambda (b)
                           (if (null? b)
                               '()
                               (cons (car (cdr (car b))) (unzip (cdr b)))
                            )))
            (list (front l) (back l))))

(解压'((1 2)(3 4)(5 6)))

这个电话应该返回((1 3 5)(2 4 6)) 如果我用(前面l)或(后面l)替换最后一行代码“(list(前面l)(后面l))我得到正确的列表但我似乎无法将它们放在一起它只是不断吐出每次尝试都会产生奇怪的输出。

2 个答案:

答案 0 :(得分:2)

你的代码结构非常传统,我怀疑你是计划/球拍的新手。您的程序可以用更加惯用的方式编写。

我可能对您的代码提出的第一个批评是,它假设您解压缩的列表每个只有2个元素。

  • 如何解压缩3个5个元素的列表或5个3个元素的列表?
  • 解压缩4个4 elemens的列表怎么样?
  • 如何解压缩1个7个元素的列表或7个1个元素的列表?
  • 如何解压缩什么?

这些问题都指向一个有助于塑造结构良好程序的基本概念:

"什么是"总计"程序?"

总程序是为所接受类型的所有值定义的程序。这对我们意味着,如果我们编写unzip程序,它应该

  • 接受空列表
  • 接受任意数量的名单
  • 接受任何长度 1
  • 的列表

让我们来看一下现在这样做的unzip程序。这个程序可能会得到改善,但至少,它易于理解和理解

(define (unzip xs (ys empty))
  ; if no xs are given, return ys
  (cond [(empty? xs) empty]
        ; if the first input is empty, return the final answer; reversed
        [(empty? (car xs)) (reverse ys)]
        ; otherwise, unzip the tail of each xs, and attach each head to ys
        [else (unzip (map cdr xs) (cons (map car xs) ys))]))

(unzip '((1 2) (3 4) (5 6)))

; => '((1 3 5) (2 4 6))

让我们逐步完成评估。

; initial call
(unzip '((1 2) (3 4) (5 6)))

; (empty? xs) nope
; (empty? (car xs)) nope
; (unzip (map cdr xs) (cons (map car xs) ys))

; substitue values
(unzip (map cdr '((1 2) (3 4) (5 6)))
       (cons (map car '((1 2) (3 4) (5 6))) empty))

; eval (map cdr xs)
(unzip '((2) (4) (6))
       (cons (map car '((1 2) (3 4) (5 6))) empty))

; eval (map car xs)
(unzip '((2) (4) (6))
       (cons '(1 3 5) empty))

; eval cons
; then recurse unzip
(unzip '((2) (4) (6))
       '((1 3 5)))

; (empty? xs) nope
; (empty? (car xs)) nope
; (unzip (map cdr xs) (cons (map car xs) ys))

; substitue values
(unzip (map cdr '((2) (4) (6)))
       (cons (map car '((2) (4) (6))) '((1 3 5))))

; eval (map cdr xs)
(unzip '(() () ())
       (cons (map car '((2) (4) (6))) '((1 3 5))))

; eval (map car xs)
(unzip '(() () ())
       (cons '(2 4 5) '((1 3 5))))

; eval cons
; then recurse
(unzip '(() () ())
       '((2 4 5) (1 3 5)))

; (empty? xs) nope
; (empty? (car xs)) yup!
; (reverse ys)

; substituion
(reverse '((2 4 5) (1 3 5)))

; return
'((1 3 5) (2 4 5))

这是另一件值得思考的事情。您是否注意到unzip基本上与zip做同样的事情?让我们仔细看看你的输入

'((1 2)
  (3 4)
  (5 6))
   ^ ^

查看列。如果我们要zip这些,我们就会

'((1 3 5) (2 4 6))

"等等,你是说unzip只是另一个zip,反之亦然?"

烨。

(unzip '((1 2) (3 4) (5 6)))
; => '((1 3 5) (2 4 6))

(unzip (unzip '((1 2) (3 4) (5 6))))
; '((1 2) (3 4) (5 6))

(unzip (unzip (unzip '((1 2) (3 4) (5 6)))))
; '((1 3 5) (2 4 6))

了解这一点,如果您已经有zip程序,那么您对unzip的定义就变得非常简单

(define unzip zip)

这基本上意味着:

您不需要unzip程序,只需重新zip

(zip '((1 2) (3 4) (5 6)))
; => '((1 3 5) (2 4 6))

(zip (zip '((1 2) (3 4) (5 6))))
; '((1 2) (3 4) (5 6))

(zip (zip (zip '((1 2) (3 4) (5 6)))))
; '((1 3 5) (2 4 6))

无论如何,我猜测你的unzip程序实现是一个功课。你教授期待的长期答案可能与我最初提供的程序有关。偷偷摸摸的答案是(define unzip zip)

"这个unzip程序是否也被视为完整程序?"

  • 如何解压缩3个5个元素的列表或5个3个元素的列表?

    (unzip '((a b c d e) (f g h i j) (k l m n o p)))
    ; => '((a f k) (b g l) (c h m) (d i n) (e j o))
    
    (unzip '((a b c) (d e f) (g h i) (k l m) (n o p)))
    ; => '((a d g k n) (b e h l o) (c f i m p))
    
  • 如何解压缩4个4个元素的列表?

    (unzip '((a b c d) (e f g h) (i j k l) (m n o p)))
    ; => '((a e i m) (b f j n) (c g k o) (d h l p))
    
  • 如何解压缩1个7个元素的列表或7个1个元素的列表?

    (unzip '((a b c d e f g)))
    ; => '((a) (b) (c) (d) (e) (f) (g))
    
    (unzip '((a) (b) (c) (d) (e) (f) (g)))
    ; => '((a b c d e f g))
    
  • 怎么样解压缩?

    (unzip '())
    ; => '()
    
  • 如何解压缩3个空列表?

    (unzip '(() () ()))
    ; => '()
    
  

1 我们说unzip应该"接受任何长度的列表"但是我们在这里稍微弯曲规则。 unzip接受任何长度的列表都是正确的,但每个列表的长度与其他列表的长度相同也是正确的。对于不同长度的列表,目标"正确"解决方案是不可能的,在本课程中,我们将混合长度列表的行为保留为 undefined

; mixed length input is undefined
(unzip '((a) (b c d) (e f))) ; => ???    

附注:

这样的事情
(car (car x))
(car (cdr (car x)))

可以简化为

(caar x)
(cadar x)

以下pair accessor short-hand procedures存在

caar    ; (car (car x))
cadr    ; (car (cdr x))
cdar    ; (cdr (car x))
cddr    ; (cdr (cdr x))
caaar   ; (car (car (car x)))
caadr   ; (car (car (cdr x)))
cadar   ; (car (cdr (car x)))
caddr   ; (car (cdr (cdr x)))
cdaar   ; (cdr (car (car x)))
cdadr   ; (cdr (car (cdr x)))
cddar   ; (cdr (cdr (car x)))
cdddr   ; (cdr (cdr (cdr x)))
caaaar  ; (car (car (car (car x))))
caaadr  ; (car (car (car (cdr x))))
caadar  ; (car (car (cdr (car x))))
caaddr  ; (car (car (cdr (cdr x))))
cadaar  ; (car (cdr (car (car x))))
cadadr  ; (car (cdr (car (cdr x))))
caddar  ; (car (cdr (cdr (car x))))
cadddr  ; (car (cdr (cdr (cdr x))))
cdaaar  ; (cdr (car (car (car x))))
cdaadr  ; (cdr (car (car (cdr x))))
cdadar  ; (cdr (car (cdr (car x))))
cdaddr  ; (cdr (car (cdr (cdr x))))
cddaar  ; (cdr (cdr (car (car x))))
cddadr  ; (cdr (cdr (car (cdr x))))
cdddar  ; (cdr (cdr (cdr (car x))))
cddddr  ; (cdr (cdr (cdr (cdr x))))

答案 1 :(得分:0)

它正确地组合了列表,但它没有组合正确的列表。

提取本地定义使它们可以单独测试:

(define (front a)
  (if (null? a)
      '()
      (cons (car (car a)) (unzip (cdr a)))))

(define (back b)
  (if (null? b)
      '()
      (cons (car (cdr (car b))) (unzip (cdr b)))))


(define (unzip l)
    (list (front l) (back l)))

(define test '((1 2) (3 4) (5 6)))

测试:

> (front test)
'(1 (3 (5 () ()) (6 () ())) (4 (5 () ()) (6 () ())))
> (front '((1 2)))         
'(1 () ())
> (back '((1 2)))
'(2 () ())

...怪异

> (unzip '())
'(() ())
> (unzip '((1 2)))
'((1 () ()) (2 () ()))

看起来某事是正确的,但是列表'尾巴是错的。

如果仔细查看frontback的定义,他们会重新加入unzip
但他们应该回归自己 - front是第一个"第一个"其次是"第一"其余的,back是"第一秒"其次是"秒" unzip与此无关。

(define (front a)
  (if (null? a)
      '()
      (cons (car (car a)) (front (cdr a)))))

(define (back b)
  (if (null? b)
      '()
      (cons (car (cdr (car b))) (back (cdr b)))))

现在......

> (front test)
'(1 3 5)
> (back test)
'(2 4 6)
> (unzip test)
'((1 3 5) (2 4 6))