MIT Scheme Message Передача абстракции Процедура Mailman

Ранее я задавал вопрос об абстракции передачи сообщений здесь: Абстракция передачи сообщений схемы MIT

Вопрос задавался тем, что я:

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)))

person CodeRook    schedule 07.05.2013    source источник


Ответы (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 сообщения и иметь "адреса". У «письменных» объектов также должны быть «адреса» (которые мы получаем с помощью вызова (letter 'get-address), а для почтового ящика мы вызываем (mbox 'get-address)), и эти адреса должны быть такими, чтобы мы могли сравнить их на равенство.

Это означает, что письма и почтовые ящики должны быть объектами, определенными с помощью той же процедуры, что и почтальон, с внутренними процедурами и процедурой отправки, экспортируемой как сам объект.

Это все нужно в дальнейшем реализовывать, а может они у вас уже есть в рамках какого-то предыдущего задания?


теперь, когда вы предоставили свои дополнительные определения, давайте посмотрим.

make-letter вроде нормально. Буква поддерживает два сообщения: 'get-destination и get-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) функционально такой же, как и (member letter T). В Scheme любое неложное значение похоже на #t.

Ваш previous-post (если он исправлен с (12) ) возвращает последнюю ячейку cdr своего списка аргументов. Если он содержит буквы (a b c d), (previous-post T) возвращает (d). Разве вы не имели в виду, что это будет a ? В конце концов, сообщение, которое он обрабатывает, называется 'get-latest-message. Все, что вы только что добавили с помощью cons в список 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 .... ))))
person Will Ness    schedule 07.05.2013
comment
Отредактировал мой вопрос, чтобы включить другие процедуры в мое задание и текущий почтовый ящик поиска. Я попытался определить этот случай поиска почтового ящика с помощью element?, процедуры, которую мне нужно было определить, которая проверяет, находится ли элемент x в списке (она возвращает true, если да, и false, если нет). Тем не менее, все еще возвращает ту же ошибку. Я действительно не уверен, почему здесь, так как сейчас я просматриваю весь список и проверяю 2 условия, чтобы убедиться, что адрес складывается. - person CodeRook; 08.05.2013
comment
Спасибо, что пролили больше света на то, что я делал неправильно. Однако у меня все еще есть некоторые проблемы, поэтому я переместил более информативную и обновленную версию этого вопроса в обзор кода, как вы предложили. codereview.stackexchange.com /вопросы/25942/ - person CodeRook; 08.05.2013
comment
@ Гейб, извини, не знал этого. Я хотя это для любого кода. последний код находится здесь. - person Will Ness; 08.05.2013
comment
@Уилл Несс, не беспокойся об этом. Спасибо за помощь. Мне удалось заставить код работать так, как мне нужно, и я ценю ваше руководство. :) - person CodeRook; 10.05.2013