Как я могу написать `(if (null? x) (quote ()) (cdr x))` в CPS?

Языки программирования схем говорят

Таким образом, в любой момент вычисления любого выражения существует продолжение, готовое завершить или, по крайней мере, продолжить вычисление с этой точки. Предположим, что 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)).

Мне было интересно, как написать (if (null? x) (quote ()) (cdr x)) в CPS?

Можно ли переписать в CPS только вызовы процедур?


person Community    schedule 10.08.2019    source источник


Ответы (2)


Проблема с (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 истинно, продолжение должно отображать '(), но если это не так, то оно должно отображать cdr из x:

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

halt останавливает программу. Теперь давайте представим, что мы переводим это на Алгол, например. JS. Я изменю порядок, чтобы продолжение всегда было первым аргументом. Все процедуры просто получают числовой идентификатор, поэтому язык реализации вообще не должен иметь процедур.

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;
    }
  }

Теперь мы упустили определяемые пользователем процедуры и соглашения о закрытии, что сделало бы этот пример немного более сложным. Существует некоторая отсутствующая проверка типов, которую сделала бы правильная схема, и я использую массивы вместо реальных пар.

person Sylwester    schedule 13.08.2019

(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?/k и cdr/k, которые принимают продолжение в качестве дополнительного первого параметра.

person rain1    schedule 11.08.2019
comment
не могли бы вы пояснить, что такое exit-cont? Где и как определяется? Кроме того, мне непонятно, что должно происходить с внутренним if в вашем вызове null?/k. В конце концов, мы определяем, как if переводится в CPS, поэтому использование if в переводе if кажется круговой логикой? Не могли бы вы уточнить? - person Will Ness; 12.08.2019
comment
@WillNess, разве это не было бы halt, если бы это был единственный код, или остальная часть программы, если бы это было не так? - person Sylwester; 13.08.2019