scheme中的正常顺序与应用顺序程序

scheme中的正常顺序与应用顺序程序,scheme,racket,Scheme,Racket,假设我想知道scheme/racket中的解释器是正常顺序还是应用顺序 (define normal? (lambda() (let ((e (display 'not-))) (display 'normal)))) 这将按正常顺序打印正常,按应用程序顺序打印非正常,但我是否可以编写一个对应用程序顺序执行相同操作的过程(即按应用程序顺序显示应用程序,按正常顺序显示非应用程序) 我的想法是,这是不可能的,因为如果应用程序顺序过程终止,它必须返回与正常顺序相同的结果。为什

假设我想知道scheme/racket中的解释器是正常顺序还是应用顺序

(define normal?
  (lambda()
    (let ((e (display 'not-)))
      (display 'normal))))
这将按正常顺序打印正常,按应用程序顺序打印非正常,但我是否可以编写一个对应用程序顺序执行相同操作的过程(即按应用程序顺序显示应用程序,按正常顺序显示非应用程序)


我的想法是,这是不可能的,因为如果应用程序顺序过程终止,它必须返回与正常顺序相同的结果。

为什么,这是变异的基础,亲爱的沃森:

(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))))))
现在你们可以看到,这个方案不是lambda演算

这里有第三个解决方案。定义
display1
仅在第一次调用时打印其参数,在后续调用时不执行任何操作,然后使用

(define applicative?
  (lambda()
    (let ((e (display1 'applicative)))
      (display1 'not-applicative))))
正如您在代码中使用副作用原语一样,我也一样!:)

基础分析 应用程序顺序和正常顺序之间的一个明显区别是包含引发错误/异常的过程的逻辑路径的行为

实施 在
#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>,输入“/media/ben/Data/Programming/StackOverflow/29657169.rkt”
--------------------
测试评估顺序。>正常顺序检验
正常顺序检验
失败
名称:check not exn
位置:/media/ben/Data/Programming/StackOverflow/29657169.rkt:19:5
参数:#
消息:“引发异常”
例外情况“/:除零”
异常:#(结构:exn:fail:contract:divide by zero”/:divide by zero“#)
检查失败
--------------------
1成功1失败0错误2测试运行
1.

这听起来很熟悉;这可能是一个已经存在的问题的重复。例如,搜索applicative、normal和scheme-on-Stack-Overflow时出现。@JoshuaTaylor或者我们可以自己搜索:““如果scheme/racket中的解释器”我认为racket默认情况下禁止变异,但这在scheme中会起作用。(然而,这确实取决于if的特殊计算语义,这可能会有问题。我不知道这两种情况下if语义的区别。我当时认为
set!
会更加不确定。:)但我认为在惰性操作语义下(即存储lambda w/memorization)
set
会像预期的那样工作。@WillNess谢谢你的回答,但我一直在寻找一个没有变异的解决方案(没有集合!)@JoshuaTaylor变量变异在Racket和Scheme中的作用是一样的。Racket有不可变的cons单元格(默认)。@WillNess我的观点是,如果解释器完全是应用程序,那么if可能会计算它的所有三个参数,并根据第一个参数的值返回后两个参数中的一个。当然,这不是我们所期望的控制流的工作方式(尽管就返回的值而言,它是相同的(除了突变等副作用)。
racket@29657169.rkt> ,enter "/media/ben/Data/Programming/StackOverflow/29657169.rkt"
--------------------
Test the evaluation order. > Normal Order Test
Normal Order Test
FAILURE
name:       check-not-exn
location:   /media/ben/Data/Programming/StackOverflow/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