LINUX.ORG.RU

Как правильно реализуется нелокальный выход с помощью call/cc?

 ,


0

1

Экспериментирую тут с сабжем, и наткнулся на одну непонятку. Вот код:


(define mul (lambda(x y) (write 'foo) (* x y)))

(define fact (lambda(n opt)
   (call/cc (lambda(ret)
      (cond
         ((and (< n 2) opt) (ret 1))
         ((< n 2) 1)
         (#t (mul n (fact (- n 1) opt))))))))

(write (fact 5 #t))

; foofoofoofoo120

По моим расчетам, когда на вершине стека окажется единица, стек сбросится, соответственно, факториал считаться не будет, и побочные эффекты не отработают. Однако, этого не происходит. Интересно, что в JS аналогичный код работает именно так, как я ожидаю:


mul=function(x, y){console.log("foo"); return x*y}

fact=function(n, opt){
  if(opt&&(n<2)) throw 1 // если 2-й аргумент == истина -- бросить единицу
  if(n<2) return 1 // дальше как обычно
  return mul(n, fact(n - 1, opt))
}

try{
   fact(5, true)
}catch(n){console.log(n)} //  1

Ни хрена непонятно, чем этот код отличается от такого:


(define search (lambda(wanted? lst)
   (call/cc (lambda(c)
      (for-each (lambda(el) (if (wanted? el) (c el))) lst)))))
(define wanted-2? (lambda(el) (write el) (= el 2)))

(write (search wanted-2? '(1 2 3)))
; 122

Тут, вроде, работает как надо. В чем ошибка?



Последнее исправление: terminator-101 (всего исправлений: 1)

Ну так у тебя тут рекурсия. Вызов продолжения совершает выход только из того места, где был соответствующий вызов call/cc, а дальше будет обычный возврат из вложенных рекурсивных процедур. Сделай трассировку, поможет.

Интересно, что в JS аналогичный код работает именно так, как я ожидаю

Только это не аналогичный код.

theNamelessOne ★★★★★
()
Ответ на: комментарий от theNamelessOne

Скорее всего, ты хотел сделать так:

(define mul (lambda (x y) (write 'foo) (* x y)))

(define fact (lambda (n opt)
  (call/cc (lambda (ret)
    (let go ((n n))
      (cond
        ((and (< n 2) opt) (ret 1))
        ((< n 2) 1)
        (#t (mul n (go (- n 1))))))))))

(write (fact 5 #t))
theNamelessOne ★★★★★
()
Ответ на: комментарий от theNamelessOne

Либо так:

(define mul (lambda(x y) (write 'foo) (* x y)))

(define kont #f)

(define fact (lambda(n opt)
   (call/cc (lambda(ret)
      (or kont (set! kont ret)) -- save only first continuation
      (cond
         ((and (< n 2) opt) (kont 1))
         ((< n 2) 1)
         (#t (mul n (fact (- n 1) opt))))))))

(write (fact 5 #t))
theNamelessOne ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.