返回方案中的列表

问题描述

| 我想解决方案(R5RS)中的问题。这是我的示例数据:
(define zipcodes \'(
 (96774 ookala hawaii)
 (90001 losangeles california)
 (90263 malibu california)
 (10044 newyork newyork)
 ))
每个列表元素的格式为“ 1”。我想创建一个像这样工作的函数:将STATE作为输入传递,并且该函数返回该状态的邮政编码(如果没有用于此状态的元素,则返回一个空列表)。
>(findzips \'california)
(90001 900263)

>(findzips \'berlin)
empty
我尝试通过下面的代码做到这一点,但它只会返回第一个值而不是列表
(define (findzips x)
  (find x zipcodes))
(define find
  (lambda (x zipcodes)
    (if (EQ? x (caddr (car zipcodes)))
        (list (car (car zipcodes)))
      (find x (cdr zipcodes)))))
我不允许使用
!
函数
let
。     

解决方法

首先,您发布的代码中有一个错字:“ 6”应为“ 7”。 让我们看一下带有适当缩进的函数:
(define find
  (lambda (x zipcodes)
    (if (EQ? x (caddr (car zipcodes)))    ; if the current entry matches
        (list (car (car zipcodes)))       ; then return it,in a single-element list
      (find x (cdr zipcodes)))))          ; else return the subsequent matches
如果当前条目匹配,则不要尝试寻找任何后续匹配项。因此,您返回的列表绝不会包含多个元素。 您始终需要查找后续元素,即您始终需要调用
(find x (cdr zipcodes))
。一个好方法是叫ѭ5,但您的作业要排除在外。您可以重复通话。而不是通过
list
过程创建单元素列表,而是建立一个包含当前匹配项和随后匹配项列表的列表。将一个元素添加到列表的过程是
cons
(define find
  (lambda (x zipcodes)
    (if (EQ? x (caddr (car zipcodes)))    ; if the current entry matches
        (cons (car (car zipcodes))        ; then return it,followed by…
              (find x (cdr zipcodes)))    ; … the subsequent matches
      (find x (cdr zipcodes)))))          ; else return the subsequent matches
尚未完成:您会注意到此函数始终会引发异常。您会仔细研究列表,最终到达末尾……并cho之以鼻,因为您不处理列表为空的情况。我将把它保留为练习。 现在,还有其他方法可以编写此函数(实际上,更好的方法,但是对于初学者来说更难理解)。他们可能不是您计划的目的。假设您只想对
find
进行一次递归调用,而没有
let
或任何其他方式来存储调用
find
的结果。然后,您别无选择,只能调用
find
,但是根据是否找到该元素使用不同的参数。你该怎么做? (提示:您将需要第三个参数。)     ,理解此问题的第一步是明确声明我们正在使用的数据由什么组成。让我们写下一系列数据定义:
;; A ZIP is a number
;; A CITY is a symbol
;; A STATE is a symbol
ENTRY
ZIP
,a21ѭ和
STATE
的列表。但是,请记住,列表是一系列以null结尾的con单元格。让我们使用对
cons
的显式调用为
ENTRY
定义数据定义:
;; An ENTRY is of the form (cons ZIP (cons CITY (cons STATE null)))

;; A [listof ENTRY] is either:
;;
;;   1. The empty list,null,or
;;   2. (cons ENTRY [listof ENTRY])
有了这些数据定义,就可以更精确地确定我们希望函数执行的操作。我们将为我们的函数编写一个合同,该合同包括两部分:函数的名称和函数消耗的数据种类以及函数产生的数据种类。例如:
;; <FUNCTION NAME> : <WHAT OUR FUNCTION CONSUMES> -> <WHAT OUR FUNCTION PRODUCES>
现在,我们可以为要编写的函数编写合同:
;; find : STATE [listof ENTRY] -> [listof ZIP]
;; Produces the ZIPs in [listof ENTRY] that match the given STATE.
(define (find state entries)
  ...)

;; findzips : STATE -> [listof ZIP]
;; Produces the ZIPs in \'zipcodes\' that match the given STATE.
(define (findzips state)
  ...)
让我们开始填写
find
的定义。从我们的合同中我们知道,'find \'有两个参数,分别是
STATE
[listof ENTRY]
。从
[listof ENTRY]
的数据定义中我们知道,它可以是以下两项之一:
(cons ENTRY [listof ENTRY])
null
。任何时候我们必须处理一个以上的情况时,都可以对每种情况使用use34ѭ表示我们想要的行为:
;; find : STATE [listof ENTRY] -> [listof ZIP]
;; Produces the ZIPs for which there is an ENTRY in the [listof ENTRY]
;; with a STATE that matches the one given.
(define (find state entries)
  (cond ((null? entries) ...)
        (else ...)))
请参阅您的教科书或询问您的老师是否不熟悉
cond
。 到目前为止,一切都很好。那么,如果函数被称为null(给定合同的有效输入),我们应该返回什么呢?我们的合同建议我们返回一个空清单作为回报。
;; find : STATE [listof ENTRY] -> [listof ZIP]
(define (find state entries)
  (cond ((null? entries) null)
        (else ...)))
到目前为止,一切都很好。现在是困难的部分。如果输入列表不为空,则它必须至少包含一个“ 19”。对于任何给定的
ENTRY
,我们都必须处理两种情况:条目中的状态与我们要寻找的ѭ22matches相匹配,否则就没有。假设我们有一个函数
get-state
,给定
ENTRY
,我们得到它的
STATE
;; find : STATE [listof ENTRY] -> [listof ZIP]
(define (find state entries)
  (cond ((null? entries) null)
        (else (if (equal? state
                          (get-state (car entries)))
                  ... ;; matches
                  ...)))) ;; doesn\'t match
让我们先处理第二种情况。如果我们要搜索的ѭ22与条目中下一个ѭ19中的ѭ22不匹配,我们只希望列表中其余部分中的任何ѭ20都匹配。查看'find \'的合同,我们可以看到在列表的其余部分上调用find可以准确地满足我们的需求!填补这一点,我们有:
;; find : STATE [listof ENTRY] -> [listof ZIP]
(define (find state entries)
  (cond ((null? entries) null)
        (else (if (equal? state
                          (get-state (car entries)))
                  ... ;; matches
                  ...)))) ;; doesn\'t match
在第一种情况下,我们知道\'entires \'中的第一个
ENTRY
具有与我们要搜索的
STATE
匹配的状态。考虑在这种情况下我们想要的最终结果:我们想要一个列表,该列表以我们已经知道的
ZIP
开头,与我们要搜索的
STATE
匹配,其后是其他任何
ZIP
且其状态在其余部分也都匹配
entries
。我们可以使用ѭ12来构建一个新列表。
cons
具有以下合同:
;; cons : any [listof any] -> [listof any]
cons
的第一个参数很简单。再次假设我们有一个函数'get-zip \',对于给定的
ENTRY
,我们可以得到
ZIP
。然后我们可以简单地从
ENTRY
中提取
ZIP
;; find : STATE [listof ENTRY] -> [listof ZIP]
(define (find state entries)
  (cond ((null? entries) null)
        (else (if (equal? state
                          (get-state (car entries)))
                  (cons (get-zip (car entries))
                        ...)
                  (find state (cdr entries))))))
ѭ12的第二个参数我将作为练习留给您。 我们快完成了!现在我们有
find
写作
findzips
是微不足道的。我们简单地用给定的
STATE
zipcodes
称为
find
。填写其余的椭圆,您将完成:
;; get-zip : ENTRY -> ZIP
;; Produces the ZIP for a given ENTRY.
(define (get-zip entry)
  ...)

;; get-state : ENTRY -> STATE
;; Produces the STATE for a given ENTRY.
(define (get-state entry)
  ...)

;; find : STATE [listof ENTRY] -> [listof ZIP]
;; Produces the ZIPs in [listof ENTRY] that match the given STATE.
(define (find state entries)
  (cond ((null? entries) null)
        (else (if (equal? state
                          (get-state (car entries)))
                  (cons (get-zip (car entries))
                        ...)
                  (find state (cdr entries))))))

;; findzips : STATE -> [listof ZIP]
;; Produces the ZIPs in \'zipcodes\' that match the given STATE.
(define (findzips state)
  (find state zipcodes))
在解决此问题时,我们使用了“设计食谱”的元素,这是设计程序的逐步指南。 Felleisen,Findler,Flatt和Krishnamurthi在“如何设计程序”中完整概述了“设计食谱”。全文可在线获得:www.htdp.org。 祝好运!