方案中的正常顺序与应用顺序程序
Normal order vs Applicative order procedure in scheme
假设我想知道 scheme/racket 中的解释器是正常顺序还是应用顺序。
(define normal?
(lambda()
(let ((e (display 'not-)))
(display 'normal))))
这将在正常顺序上打印 normal 而在 applicative 顺序上打印 not-normal,但是我可以编写一个程序来对 applicative 顺序执行相同的操作吗(意思是在 applicative 顺序上显示 applicative 而在正常顺序上显示 not-applicative )?
我的想法是这是不可能的,因为如果应用订单程序终止,它必须 return 具有与正常订单相同的结果。
亲爱的华生,这是变异的基础:
(define applicative?
(lambda ()
(let ((test #t))
(let ((e (begin (set! test #f) #f)))
(if test (display 'normal) (display 'applicative))))))
你没有禁止变异吧?但如果您坚持,请使用 call/cc
快速退出:
(define applicative?
(lambda ()
(call/cc (lambda (exit)
(let ((e (begin (display 'applicative) (exit #f))))
(display 'not-applicative))))))
现在你知道 Scheme 不是 lambda 演算了。
这是为您提供的第三种解决方案。定义 display1
仅在第一次调用时打印其参数,并且在任何后续调用中不执行任何操作,然后使用
(define applicative?
(lambda()
(let ((e (display1 'applicative)))
(display1 'not-applicative))))
就像您在代码中使用副作用原语一样,我也是! :)
基础分析
应用顺序和正常顺序之间的一个明显区别是逻辑 dead code 路径的行为包含引发 errors/exceptions.
的过程
实施
在 #lang racket
中,我们可以使用 arity = 2 的局部函数 foo
编写一个简单的测试套件。第一个参数在 foo
中有效,第二个参数无效.然后我们传递一个值 [`(/ 1 0)],当沿着死代码路径评估时会引发异常。
将其全部封装在测试框架中可以让我们养成良好的习惯:
#lang racket/base
(require rackunit
rackunit/text-ui
racket/function)
(define evaluation-order
(let ((foo (lambda (x y) x)))
(test-suite
"Test the evaluation order."
(test-exn
"Applicative Order Test"
exn:fail?
(thunk (foo (+ 1 0)
(/ 1 0))))
(test-not-exn
"Normal Order Test"
(thunk (foo (+ 1 0)
(/ 1 0)))))))
(run-tests evaluation-order)
示例输出
racket@29657169.rkt> ,enter "/media/ben/Data/Programming/Whosebug/29657169.rkt"
--------------------
Test the evaluation order. > Normal Order Test
Normal Order Test
FAILURE
name: check-not-exn
location: /media/ben/Data/Programming/Whosebug/29657169.rkt:19:5
params: #<procedure:temp5>
message: "Exception raised"
exception-me"/: division by zero"
exception: #(struct:exn:fail:contract:divide-by-zero "/: division by zero" #<continuation-mark-set>)
Check failure
--------------------
1 success(es) 1 failure(s) 0 error(s) 2 test(s) run
1
假设我想知道 scheme/racket 中的解释器是正常顺序还是应用顺序。
(define normal?
(lambda()
(let ((e (display 'not-)))
(display 'normal))))
这将在正常顺序上打印 normal 而在 applicative 顺序上打印 not-normal,但是我可以编写一个程序来对 applicative 顺序执行相同的操作吗(意思是在 applicative 顺序上显示 applicative 而在正常顺序上显示 not-applicative )?
我的想法是这是不可能的,因为如果应用订单程序终止,它必须 return 具有与正常订单相同的结果。
亲爱的华生,这是变异的基础:
(define applicative?
(lambda ()
(let ((test #t))
(let ((e (begin (set! test #f) #f)))
(if test (display 'normal) (display 'applicative))))))
你没有禁止变异吧?但如果您坚持,请使用 call/cc
快速退出:
(define applicative?
(lambda ()
(call/cc (lambda (exit)
(let ((e (begin (display 'applicative) (exit #f))))
(display 'not-applicative))))))
现在你知道 Scheme 不是 lambda 演算了。
这是为您提供的第三种解决方案。定义 display1
仅在第一次调用时打印其参数,并且在任何后续调用中不执行任何操作,然后使用
(define applicative?
(lambda()
(let ((e (display1 'applicative)))
(display1 'not-applicative))))
就像您在代码中使用副作用原语一样,我也是! :)
基础分析
应用顺序和正常顺序之间的一个明显区别是逻辑 dead code 路径的行为包含引发 errors/exceptions.
的过程实施
在 #lang racket
中,我们可以使用 arity = 2 的局部函数 foo
编写一个简单的测试套件。第一个参数在 foo
中有效,第二个参数无效.然后我们传递一个值 [`(/ 1 0)],当沿着死代码路径评估时会引发异常。
将其全部封装在测试框架中可以让我们养成良好的习惯:
#lang racket/base
(require rackunit
rackunit/text-ui
racket/function)
(define evaluation-order
(let ((foo (lambda (x y) x)))
(test-suite
"Test the evaluation order."
(test-exn
"Applicative Order Test"
exn:fail?
(thunk (foo (+ 1 0)
(/ 1 0))))
(test-not-exn
"Normal Order Test"
(thunk (foo (+ 1 0)
(/ 1 0)))))))
(run-tests evaluation-order)
示例输出
racket@29657169.rkt> ,enter "/media/ben/Data/Programming/Whosebug/29657169.rkt"
--------------------
Test the evaluation order. > Normal Order Test
Normal Order Test
FAILURE
name: check-not-exn
location: /media/ben/Data/Programming/Whosebug/29657169.rkt:19:5
params: #<procedure:temp5>
message: "Exception raised"
exception-me"/: division by zero"
exception: #(struct:exn:fail:contract:divide-by-zero "/: division by zero" #<continuation-mark-set>)
Check failure
--------------------
1 success(es) 1 failure(s) 0 error(s) 2 test(s) run
1