1

我之前在这里问过一个关于消息传递抽象的问题:MIT Scheme Message Passing Abstraction

这个问题问我:

Write a mailman object factory (make-mailman) that takes in no parameters and returns 
a message-passing object that responds to the following messages:

'add-to-route: return a procedure that takes in an arbitrary number of mailbox objects 
 and adds them to the mailman object's “route”
'collect-letters: return a procedure that takes in an arbitrary number of letter 
 objects and collects them for future distribution
'distribute: add each of the collected letters to the mailbox on the mailman's route 
 whose address matches the letter's destination and return a list of any letters whose 
 destinations did not match any mailboxes on the route (Note: After each passing of 
 'distribute the mailman object should have no collected letters.)

作为此任务的一部分,我已经编写了 2 个程序来制作邮箱和写信:

(define (make-letter destination message)
  (define (dispatch x)
    (cond ((eq? x 'get-destination) destination)
          ((eq? x 'get-message) message)
          (else "Invalid option.")))
      dispatch)

(define (make-mailbox address)
  (let ((T '()))
    (define (post letter)
      (assoc letter T))
    (define (previous-post post)
      (if (null? (cdr post)) post (cdr (previous-post post))))
    (define (letter-in-mailbox? letter)
      (if (member (post letter) T) #t #f))
    (define (add-post letter)
      (begin (set! T (cons letter T)) 'done))
    (define (get-previous-post post)
      (if (letter-in-mailbox? post)
          (previous-post post)
          #f))
    (define (dispatch y)
      (cond ((eq? y 'add-letter) add-post)
            ((eq? y 'get-latest-message) (get-previous-post T))
            ((eq? y 'get-address) address)
            (else "Invalid option.")))
        dispatch))

在对我当前的答案做错了什么给出了很好的解释并对我的代码进行了许多必要的更改之后,我被告知我在该代码中遇到的任何问题最好在这个问题中提出。因此,这是基于我之前的问题的代码:

(define (make-mailman)
  (let ((self (list '(ROUTE) '(MAILBAG))))
    (define (add-to-route . mailboxes)
      (let ((route (assoc 'ROUTE self)))
        (set-cdr! route (append mailboxes (cdr route))) 
        'DONE))
    (define (collect-letters . letters)
      (let ((mailbag (assoc 'MAILBAG self)))
        (set-cdr! mailbag (append letters (cdr mailbag)))
        'DONE))
    (define (distribute-the-letters)
      (let* ((mailbag (assoc 'MAILBAG self))
             (mailboxes (cdr (assoc 'ROUTE self)))
             (letters (cdr mailbag)))
        (if (null? letters)
            ()
            (let loop ((letter (car letters))
                       (letters (cdr letters))
                       (not-delivered ()))
              (let* ((address (letter 'get-address))
                     (mbx (find-mailbox address mailboxes)))
                (if (equal? address letter)
                    ((mbx 'add-post) letter)
                    ((mbx 'add-post) not-delivered))
                (if (null? letters)
                    (begin (set-cdr! mailbag '()) not-delivered)
                    (loop (car letters) (cdr letters) not-delivered)))))))
    (define (dispatch z)
      (cond ((eq? z 'add-to-route) add-to-route)
            ((eq? z 'collect-letters) collect-letters)
            ((eq? z 'distribute) distribute-the-letters)
            (else "Invalid option")))
    dispatch))

本质上,我现在遇到了一个不同的错误,而是返回分发字母过程作为参数传递给长度,而不是列表。我不知道为什么会返回此错误,因为我认为我在需要时传入列表。任何人都可以对发生的事情有所了解吗?任何帮助将不胜感激。

更新:现在在我的 make-mailman 代码中使用此过程:

(define (find-mailbox address mailbox)
  (if (not (element? address self))
      #f
      (if (element? mailbox self)
          mailbox
          #f)))
4

1 回答 1

1

你的错误在这里:

(define (distribute-the-letters)
  (let* ((mailbag (assoc 'MAILBAG self))
         (mailboxes (cdr (assoc 'ROUTE self)))
         (letters (cdr mailbag)))
    (if (null? letters)
      ()
      (let loop ((letter (car letters))
                 (letters (cdr letters))
                 (not-delivered ()))
        (let* ((address (letter 'get-address))
               (mbx (find-mailbox address mailboxes)))  ;; has to be impl'd

      ;;  (if (equal? address letter)          ;; this makes
      ;;    ((mbx 'add-post) letter)           ;;  no
      ;;    ((mbx 'add-post) not-delivered))   ;;   sense   

          ;; here you're supposed to put the letter into the matching mailbox
          ;; or else - into the not-delivered list
          (if mbox                  ;; NB! find-mailbox should accommodate this
            ((mbox 'put-letter) letter)   ;; NB! "mailbox" should accom'te this
            (set! not-delivered      ;; else, it wasn't delivered
              (cons letter not-delivered)))

          (if (null? letters)
            (begin 
              (set-cdr! mailbag '())       ;; the mailbag is now empty
              not-delivered)                       ;; the final return
            (loop (car letters) 
                  (cdr letters) 
                  not-delivered)))))))

find-mailbox还是要在这里实现。它应该搜索匹配的邮箱,#f如果找不到则返回,如果找到则返回邮箱对象本身。“邮箱”对象必须能够响应'put-letter消息并具有“地址”。“信件”对象还必须有“地址”(我们使用 call 检索(letter 'get-address),对于邮箱我们会调用(mbox 'get-address)),并且这些地址必须是我们可以比较它们是否相等的地址。

这意味着信件和邮箱应该是通过与这里定义的邮递员相同的过程定义的对象,具有内部过程,并且分发过程作为对象本身导出。

这一切都需要进一步实施,或者您可能已经将它们作为先前任务的一部分?


现在您已经提供了额外的定义,让我们看看。

make-letter似乎还可以。一封信支持两种信息:'get-destinationget-message

make-mailbox有问题。

(define (make-mailbox address)
  (let ((T '()))
    (define (post letter)
      (assoc letter T))         ;; why assoc? you add it with plane CONS
    (define (previous-post post)
      (if (null? (cdr post))         ;; post == T (11)
          post 
          (cdr (previous-post post)  ;; did you mean (prev-p (cdr post)) ? (12)
          )))
    (define (letter-in-mailbox? letter)        ;; letter == T ???????  (3)
      (if (member (post letter) T) #t #f))
    (define (add-post letter)
      (begin (set! T (cons letter T)) 'done))  ;; added with plane CONS
    (define (get-previous-post post)
      (if (letter-in-mailbox? post)            ;; post == T            (2)
          (previous-post post)        ;; post == T (10)
          #f))
    (define (dispatch y)
      (cond ((eq? y 'add-letter) add-post)
            ((eq? y 'get-latest-message) 
               (get-previous-post T))          ;; called w/ T          (1)
            ((eq? y 'get-address) address)
            (else "Invalid option.")))
        dispatch))

你用 , 添加字母add-post,它会调用(set! T (cons letter T)). 所以它将每个字母按原样添加到T列表中。以后不需要用assoc它来检索它,它只是列表中的一个元素。打个电话(member letter T)看看是不是进去了。post没有功能可以执行,应该是(define (post letter) letter)

(if (member letter T) #t #f)在功能上与 just 相同(member letter T)。在 Scheme 中,任何非 false 值都类似于#t.

您的previous-post(如果固定 w/ (12) )返回cdr其参数列表的最后一个单元格。如果它包含字母(a b c d),则(previous-post T)返回(d)。你不是故意的a吗?它处理的消息'get-latest-message毕竟是被调用的。无论您刚刚添加cons到 list 中的什么ls,都可以通过一个简单的调用来取回...(什么?)。

为什么叫它get-latest-message?它会返回一封信,还是该信中的信息?(这里的消息一词在一个程序中以两种完全不相关的含义使用;更好的呼叫信的内容,也许,letter-contents??

最后,我们调用(find-mailbox address mailboxes)主程序,但你定义(define (find-mailbox address mailbox) .... 它应该比较(equal? address (mailbox 'get-address))self不需要,所以这个实用函数可以放在全局范围内。它必须枚举那些mailboxes

(define (find-mailbox address mailboxes)
  (if (not (null? mailboxes))
    (if (equal? address ((car mailboxes) 'get-address))
      (car ..... )
      (find-mailbox address .... ))))
于 2013-05-07T23:18:28.310 回答