Как заставить функцию в лямбде вызываться в другой функции, используемой внутри тела лямбды

Я хочу использовать call/cc для имитации оператора обработки исключений: try...(throw)...exception. Вот код:

(define (month n) ; check if it's a month number (1-12)
  (if (or (not (integer? n)) (< n 1) (> n 12))
    (throw -1)
    (display n)
  )
)

(define error (call/cc
   (lambda(throw)
     (begin
       (month 12)
       (month -1)
       (throw -1) ; won't be executed
       (month 10)
       (display "Hello world")
      )
     )
   )
 )

(if error
  (display Error occured!")
)

Однако, когда я выполнил это, это показало ошибку (в biwascheme):

Error: execute: unbound symbol: "throw" [(anon), month]

Я думаю, что бросок в лямбде не совпадает с броском в вызываемой функции "месяц", однако, как я могу решить это? Это можно решить с помощью Марко с некоторыми ключевыми словами? например:

(define-syntax exception-handling
    (syntax-rules (throw raise error)
      ((_ body catch)
        (define (error
                  (call/cc (lambda (throw) (begin body))))
        )
        (if error (begin catch)))
    )
 )

3 ответа

Решение

На схеме продолжения первоклассные. Захваченное продолжение - просто еще одна ценность. Передайте это вашему month функционировать как еще один аргумент:

(define (month n throw) ; check if it's a month number (1-12)
  (if (or (not (integer? n)) (< n 1) (> n 12))
    (throw -1)
    (display n)))

И назвать это как

     ....
     (month 12 throw)
     ....
     (month 10 throw)
     ....

Ваш стиль отступов не способствует удобочитаемости вашего кода.

Я нашел способ имитации обработки и обработки исключений:

(define-syntax try
   (syntax-rules (catch)
     ((_ body catch handling)
        (let ()
          ; evaluating body and save it as an exception.
          (define except (begin body)) 
          (if (and
                (pair? except)
                (eq? (car except) 'exception))
             (handling except)
          )
        )
      )
   )
)

; returns an exception '(exception, "Error messenge")
(define (exception-content msg throw)
  (throw (cons 'exception msg)))
; throw an exception if n = 0
(define (reciprocal n throw)
  (if (= n 0)
     (exception-content "Div 0 error" throw)
     (/ 1 n)
  )
)

; f1(n) = reciprocal(n) + 1
(define (f1 n throw)
  (+ (reciprocal n throw) 1)
)

; main program 
(try ; with call/cc and the continuation variable "throw"
   (call-with-current-continuation
     (lambda (throw)
       (display (f1 2 throw))
       (newline)
       (display (f1 0 throw))

       ; the following won't be executed
       (newline)
       (display (f1 1 throw))
     )
   )

 catch
   ; exception handling
   (lambda (exception)
     (display (cdr exception))
   )
)

Напечатанный результат:

3/2
Div 0 error

Вот пример того, как использовать call-with-current-continuation сделать "бросок".

#lang r5rs

(define (month n) ; check if it's a month number (1-12)
  (call-with-current-continuation
    (lambda (throw)       
      (define ok (and (integer? n) (<= 1 n 12)))
      (if (not ok)
        (throw "the month number must be between 1 and 12"))
      (display n)
      (newline))))

(month 12)
(month -1)
(month 10)
(display "Hello world\n")
Другие вопросы по тегам