【问题标题】:MIT Scheme Message Passing AbstractionMIT 方案消息传递抽象
【发布时间】:2013-05-05 01:14:32
【问题描述】:

在我正在参加的计算机科学课程中,作为家庭作业,我们的任务是处理几个与消息传递有关的不同问题。除了一个,我已经能够解决所有问题,它要求以下:

编写一个不带参数的邮递员对象工厂(make-mailman) 返回一个响应以下消息的消息传递对象:

  • 'add-to-route:返回一个接收任意数量邮箱对象的过程 并将它们添加到 mailman 对象的“路由”
  • 'collect-letters:返回一个接收任意数量字母对象的过程,并且 收集它们以供将来分发
  • 'distribute:将收集到的每封信件添加到邮递员路线上的邮箱中 address 与信件的目的地相匹配,并返回其目的地的任何信件的列表 与路线上的任何邮箱都不匹配(注意:每次经过后 'distribute 这 mailman 对象应该没有收集到的信件。)

为简化代码而给出的一些说明包括:

  • 如果在一轮分发中将多封信分发到同一个邮箱,则任意一封 其中可能是通过 'get-latest-message 返回消息的“最新”信件 到邮箱。

  • 没有两个邮箱会有相同的地址。

  • 不会将任何邮箱或信件多次传递给邮递员。

  • distribute 返回的坏信不需要按特定顺序。

  • 使用. args 语法接受任意数量的参数。

这是我自己能够弄清楚的:

(define (make-mailman)
  (let ((T '()))
    (define (route-adder . mobjects)
      (assoc mobjects T))
    (define (letter-collecter . lobjects)
      (assoc lobjects T))
    (define (add-to-route mobjects)
      (begin (set! T (cons (route-adder . mobjects) T)) 'done))
    (define (collect-letters lobjects)
      (begin (set! T (cons (sort-strings (letter-collecter . lobjects)) T)) 'done))
    (define (dispatch z)
      (cond ((eq? z 'add-to-route) add-to-route)
        ((eq? z 'collect-letters) collect-letters)
        ((eq? z 'distribute) "unsure of what to do here")
        (else "Invalid option")))
    dispatch))

任何可以在这里给我的帮助都将不胜感激,因为我已经尝试研究这个问题一段时间了,但无法从这里弄清楚该怎么做。

【问题讨论】:

  • 标题和这个有什么关系?建议“方案消息传递抽象”
  • 感谢您的建议。更改了标题以使其更有意义。
  • 像你一样改变你的问题是令人困惑的,因为这里的答案是指你以前的代码。现在无法理解此 Q/A 条目。我已将您的问题恢复到以前的版本,如果您愿意,可以使用新代码提出新问题。
  • 哦,好的。谢谢你。我不习惯在这里进行编辑,所以我想我犯了一些错误。

标签: scheme


【解决方案1】:

您的代码有各种混淆。 :) 让我们一步一步来。

dispatch 位几乎没问题:

(define (make-mailman)
 (let ...
  ...
  (define (dispatch msg)                ;; use short but suggestive var names
   (cond 
    ((eq? msg 'add-to-route)    add-to-route)
    ((eq? msg 'collect-letters) collect-letters)
    ((eq? msg 'distribute) 
       ;; "unsure of what to do here" <<-- Distribute the letters, what else?
                                distribute-the-letters)
    (else "Invalid option")))
  dispatch))

对于此类对象,示例调用将是 (define ob (make-mailman)),然后是 ((ob 'add-to-route) box1 box2 ... boxn) 等。因此必须以这种方式定义 add-to-route 过程:

(define (make-mailman)
 (let ((self (list '(ROUTE)           ; each mailman has a route, and a mailbag
                   '(MAILBAG))))      ; use suggestive name here (T, what T?)
  ...
  (define (add-to-route . mailboxes)
    (let ((route (assoc 'ROUTE self))) 
      (set-cdr! route
          (append mailboxes           ; there will be no duplicates
            (cdr route)))
      'DONE))

对吗?与字母相同:

  (define (collect-letters . letters)
    (let ((mailbag (assoc 'MAILBAG self)))
      .....
      'DONE))

现在我们可以处理缺失的部分了,distribute-the-letters

  (define (distribute-the-letters)
    ;; for each letter in my mailbag
    (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 ()))
    ;;   access its address, 
          (let* ((address (letter 'get-address))
            ;; (we assume it supports this interface, 
            ;;   or maybe that's part of a previous assignment)
    ;;     and find a mailbox on my route such that
                 (mbx (find-mailbox address mailboxes)))
    ;;     its address matches the letter's
    ;;     and if so,
             (if .....
    ;;        put that letter into this mailbox: 
               ((mbx 'put-letter) letter)
    ;;            (we assume it supports this interface, 
    ;;             or maybe that's part of a previous assignment)
    ;;     but if not, add letter to the "not-delivered" list
               ..... )
            (if (null? letters)
    ;; having emptied the mailbag, return the "not-delivered" list
              (begin (set-cdr! mailbag nil) not-delivered)
              (loop (car letters) (cdr letters) not-delivered)))))))

我们假设lettermailbox 对象都支持'get-address 的消息类型,它们都返回相同的可比较address 类型的对象,并且mailbox 对象支持'put-letter 消息。

【讨论】:

  • 非常感谢您对我做错了什么进行了澄清。我确实尝试过使用您的代码(上面的当前代码),但是当我尝试运行它时发现一个奇怪的错误。它说作为长度参数传递的对象分发字母不是列表。我不知道为什么这么说,因为传入的都是列表(至少,从我所见)。
  • @Gabe distribute-the-letters 在我的代码中应该是一个函数。如此处所示:(define (distribute-the-letters) ...。您不应该在代码中的 SO 上使用制表符,它会混淆缩进。
  • 很抱歉,我对您在这里的回答有些困惑。我不明白如果所有内容都在正确的环境中正确间隔,为什么制表符会成为问题。
  • @Gabe 你最新的代码看起来缩进不均匀,仅此而已。它只是使它难以阅读,正确性当然仅取决于括号。 - 我已经回滚了您的最新编辑,因为这里的这些答案响应了您之前版本的代码。您的新代码与以前的版本有很大不同;既然你对新代码有疑问,你真的应该问一个新问题,从你的最新版本开始。 :)
【解决方案2】:

除了消息功能的细节之外,您似乎已经掌握了它。但是有一些错误:

这个(route-adder . mobjects) 应该是(router-adder objects)(letter-collector . lobjects) 类似。

不需要使用begin(define (func . args) &lt;body&gt; ...) 的主体隐式包含在 begin 中。

通常你的代码可以写成:

(define (make-mailman)
  (let ((T '()))
    ;; ...
    (lambda (z)
      (case z
        ((add-to-route)    add-to-route)
        ((collect-letters) collect-letters)
        ((distribute)      distribute)
        (else (error "Invalid option"))))))

[但你可能还不知道caselambda...]

至于解决实际的消息传递功能。您将需要维护一组邮箱,每个邮箱将保存一组信件。一封信可能包含一个地址和一些内容(回信地址的额外信用)。分发行为将检查每封信上的地址并将其存入其邮箱。邮递员需要保留信件(在他的路线上收集信件时),直到被指示分发。

为此,您可以先构建较低级别的功能,然后使用较低级别构建实际的消息传递功能。例如,开始:

(define (make-letter addr content)
  `(LETTER ,addr ,content))
(define letter-addr cadr)
;; ...

(define (make-mailbox addr)
  '(MBOX ,addr))
(define mailbox-letters cddr)
(define (mailbox-letters-add mailbox letter)
  (set-cdr! (cdr mailbox) (cons letter (mailbox-letters mailbox))))

;;...

【讨论】:

  • 感谢您的建议,但是对于您提到的应用程序,我尝试将其实现到代码中,但它只是返回了应用程序使用不正确的错误。您的意思是要更改其他内容吗?
  • 已更新;看起来(router-adder objects)(没有.)就足够了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-24
  • 1970-01-01
  • 2014-04-03
  • 2012-10-24
  • 2011-03-14
相关资源
最近更新 更多