Racket 为什么在Redex中需要评估上下文?

Racket 为什么在Redex中需要评估上下文?,racket,semantics,plt-redex,redex,Racket,Semantics,Plt Redex,Redex,完全可以在不使用评估上下文的情况下为我的语言编写评估规则。我的语义完全是按值调用的,不允许在lambdas中向前推进术语。尽管如此,我看到的所有资源都以某种方式使用了reduce上下文。有没有一个很好的理由使用我所缺少的上下文?简短的回答:你没有,但是使用它们会容易得多 长句回答:几乎所有你将使用评估上下文的东西,你可以在你的简化关系中使用不同的简化规则,这会变得更令人讨厌,尤其是当你对任何东西建模时,除了最小的语言 假设您希望通过值lambda演算对调用进行建模。其语言(无评估上下文)为: (

完全可以在不使用评估上下文的情况下为我的语言编写评估规则。我的语义完全是按值调用的,不允许在lambdas中向前推进术语。尽管如此,我看到的所有资源都以某种方式使用了reduce上下文。有没有一个很好的理由使用我所缺少的上下文?

简短的回答:你没有,但是使用它们会容易得多

长句回答:几乎所有你将使用评估上下文的东西,你可以在你的简化关系中使用不同的简化规则,这会变得更令人讨厌,尤其是当你对任何东西建模时,除了最小的语言

假设您希望通过值lambda演算对调用进行建模。其语言(无评估上下文)为:

(define-language Lv
  (v (λ (x) e))
  (e v
     (e e))
  (x variable-not-otherwise-mentioned)
  #:binding-forms
  (λ (x) e #:refers-to x))
(此处,最后两行用于利用Redex的优势

现在,让我们尝试在不使用求值上下文的情况下为这种语言创建语义。我们可以在两个地方展开子表达式,即运算符和函数应用程序的操作数。因此,包括使用普通beta缩减的子表达式,我们可以得到:

(define red
  (reduction-relation
   Lv
   (--> (e_1 e_2)
        (v_1 e_2)
        (where v_1 ,(first (apply-reduction-relation red (term e_1)))))
   (--> (v_1 e_2)
        (v_1 v_2)
        (where v_2 ,(first (apply-reduction-relation red (term e_2)))))
   (--> ((λ (x) e) e_2)
        (substitute e x e_2))))
这还不算太糟,但请记住,我们必须为子表达式可以求值的每个位置添加一个附加规则。因此,如果需要自己的规则,则需要自己的规则,等等。请记住,这是每个表单的规则之上

一种更简单的方法是使用求值上下文,它允许我们指定哪些表达式具有可以执行步骤的子表达式,以及它们的发生顺序。因此,让我们尝试使用求值上下文重写我们的
Lv
语言:

(define-language Lv2
  (v (λ (x) e))
  (e v
     (e e))
  (x variable-not-otherwise-mentioned)
  (E hole
     (E e)
     (v E))
  #:binding-forms
  (λ (x) e #:refers-to x))
现在它长了三行,但这告诉redex我们将在计算上下文中计算表达式,
E
,当计算完表达式后,将其放入上下文中(可以说,
hole
是顶级上下文)因此,我们可以将缩减关系缩减为一条规则,即β缩减:

(define red2
  (reduction-relation
   Lv2
   (--> (in-hole E ((λ (x) e) e_2))
        (in-hole E (substitute e x e_2)))))
这里我们使用
in-hole
来表示我们在
E
后面的一个洞中,如上图所示。这是在按值调用语义之后,因为洞只能在应用程序中从左到右出现

你可以想象,如果你有一个更大的结石和许多子表达式,这将使你免于编写大量的简化规则

所以,简单地说,您不需要这样做,它只会使您的模型更短