【问题标题】:How can I write `(if (null? x) (quote ()) (cdr x))` in CPS?如何在 CPS 中编写 `(if (null?x​​) (quote ()) (cdr x))`?
【发布时间】:2019-12-17 21:21:15
【问题描述】:

Scheme 编程语言说

因此,在任何表达式的求值过程中的任何时候,都有一个 continuation 准备完成或至少继续计算 从那时起。假设x 的值为(a b c)。我们可以 在评估(if (null? x) (quote ()) (cdr x)) 期间隔离六个延续——等待的延续

  1. (if (null? x) (quote ()) (cdr x))的值,
  2. (null? x)的值,
  3. null?的值,
  4. x的值,
  5. cdr的值,和
  6. x 的值(再次)。

(cdr x) 的延续没有列出,因为它与 等待(if (null? x) (quote ()) (cdr x))的那个。

我想知道如何在 CPS 中写 (if (null? x) (quote ()) (cdr x))

只能在 CPS 中重写过程调用吗?

【问题讨论】:

    标签: scheme continuations continuation-passing


    【解决方案1】:

    (if (null? x) (quote ()) (cdr x)) 的挑战在于它真的什么都不做。例如。如果我把它放在一个 R6RS 程序中并运行它,什么都不会发生。因此我建议我们写它:

    (display (if (null? x) (quote ()) (cdr x)))
    

    并假设这是整个程序,除了定义了x。现在if 需要知道(null? x) 的值来确定它是结果还是替代。例如。

    (null?& x
            continuation)
    

    延续需要判断它是否为真,并做两个延续之一:

    (null?& x
            (lambda (xn)
              (if& xn
                   continuation-consequent
                   continuation-alternative)))
    

    如果xn 为真,则延续应显示'(),但如果不是,则应显示xcdr

    (null?& x
            (lambda (xn) ; 201
              (if& xn
                   (lambda () ; 202 
                     (display& '() halt)
                   (lambda () ; 203 
                     (cdr& x (lambda (cdrx) ; 204
                               (display& cdrx halt)))))))
    

    halt 停止程序。现在让我们想象一下我们将其翻译成 Algol,例如。 JS。我将切换顺序,以便继续始终是第一个参数。所有的过程都只是得到一个数字 id,所以实现语言根本不需要过程。

    const undef = "BaNaNa";
    const x = [1, 2, 3]; // change this
    const stack = [200];
    main:
      while (true) {
        const cont = stack.pop();
        const cont2 = cont < 200 ? stack.pop() : undef;
        switch (cont) {
          case 1: // null?&
            stack.push(stack.pop().length === 0, cont2);
            break;
          case 2: // display&
            console.log(stack.pop());
            stack.push(undef, cont2);
            break;
          case 3: // cdr&
            stack.push(stack.pop().splice(1), cont2);
            break;
          case 4: // if&
            const cont3 = stack.pop();
            if (stack.pop()) {
              stack.push(cont2);
            } else {
              stack.push(cont3);
            }
            break;
            // continuations
          case 200:
            stack.push(x, 201, 1);
            break;
          case 201:
            stack.push(203, 202, 4);
            break;
          case 202:
            stack.push([], 1337, 2);
            break;
          case 203:
            stack.push(x, 204, 3);
            break;
          case 204:
            stack.push(1337, 2);
            break;
            // halt     
          case 1337:
            break main;
        }
      }

    现在我们确实错过了用户指定的过程和闭包约定,这两者都会使这个示例稍微复杂一些。有一些缺少类型检查一个正确的方案会完成,我使用数组而不是真正的对。

    【讨论】:

      【解决方案2】:

      (if (null? x) (quote ()) (cdr x))

      CPS 转化为

      (null?/k (lambda (v-1) (if v-1 (exit-cont (quote ())) (cdr/k exit-cont x))) x)

      原始过程null?cdr 被替换为延续版本null?/kcdr/k,它们将延续作为额外的第一个参数。

      【讨论】:

      • 您能否澄清一下,exit-cont 是什么?它在哪里以及如何定义?此外,我不清楚您的null?/k 调用中的内部if 会发生什么。毕竟我们定义了if如何翻译成CPS,那么在if的翻译中使用if似乎是循环逻辑?你能澄清一下吗?
      • @WillNess 不是halt,如果那是唯一的代码,或者不是程序的其余部分?
      猜你喜欢
      • 1970-01-01
      • 2014-05-29
      • 2012-06-03
      • 1970-01-01
      • 1970-01-01
      • 2013-12-23
      • 1970-01-01
      相关资源
      最近更新 更多