【问题标题】:How to make the function in a lambda be called in another function used inside the body of lambda如何使 lambda 中的函数在 lambda 体内使用的另一个函数中被调用
【发布时间】:2018-12-30 11:43:25
【问题描述】:

我想用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]

我认为 lambda 中的 throw 与被调用函数“month”中的 throw 不一样,但是,我该如何解决呢?用一些关键字制作marco可以解决吗?例如:

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

【问题讨论】:

  • 对重新格式化表示敬意——最重要的是,保持参与!在编写代码时,将右括号放在一行中的方式可以使编辑更容易;但是一旦我们有了代码,习惯上将所有右括号放在同一行,让缩进指导我们阅读代码。

标签: exception-handling scheme callcc


【解决方案1】:

在 Scheme 中,延续是一等。捕获的延续只是另一个值。将其作为另一个参数传递给您的 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)
     ....

你的缩进风格不利于代码的可读性。

【讨论】:

    【解决方案2】:

    这是一个如何使用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")
    

    【讨论】:

      【解决方案3】:

      我找到了模拟尝试和异常处理的方法:

      (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
      

      【讨论】:

      • 当然,所有throw 引用的传递都向我们展示并模拟了动态(例如,不是词法)异常的性质。 :)
      猜你喜欢
      • 2019-02-08
      • 1970-01-01
      • 2019-07-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-12-05
      • 2018-05-19
      • 2019-03-08
      相关资源
      最近更新 更多