Scheme的“define”原语是命令式语言的特征吗?为什么或者为什么不?

时间:2015-10-31 15:29:57

标签: functional-programming scheme programming-languages

(define hypot
 (lambda (a b)
   (sqrt (+ (* a a) (* b b)))))

这是一种Scheme编程语言。

  • “define”创建变量和全局绑定
  • lambda创建一个过程

我想知道“define”是否会被视为命令式语言功能!只要我知道命令功能就是静态范围。我认为这是一个必要的功能,因为“define”创建一个全局绑定和静态作用域查看任何变量定义的全局绑定,而在动态中它查看当前最活跃的绑定。

请帮我找到正确的答案!!我想知道为什么或为什么不呢?

3 个答案:

答案 0 :(得分:4)

在Scheme程序中,(define var expr)语句既是声明又是初始化。声明在范围中引入了新名称。声明和初始化都存在于命令式和声明式语言中。

但是,如果同一个变量被定义了两次,那么define就像一个赋值 - 它属于命令式范例。

答案 1 :(得分:1)

您已经指出了一个微妙而有争议的问题。关于define应该如何工作的长期以来有两个非正式的阵营,我将其标记(非常不完美,非常有争议!)作为静态动态营。

静态阵营将define视为非副作用的顶级声明 - 它的语法只是在顶级范围内定义名称,就像let一样用于在本地范围中定义名称的语法。更确切地说,这个阵营倾向于将顶级环境视为等同于letrec的大define,所有define s作为绑定,并且所有"松散"作为正文的顶级表达式。顺便提一下,这类似于简单编译器的工作方式 - 从一个或多个文件中读取整个程序,找出所有顶级绑定并生成具有整个程序源文本知识的代码。 / p> 另一方面,动态阵营倾向于将顶层环境视为可在运行时添加绑定的可变数据结构,(provided? feature)则是修改顶层的操作。水平环境。顺便提一下,这类似于简单的交互式解释器如何工作 - 从输入中交互式地读取定义,一次一个,并在用户提供时将它们合并到环境中。

举一个例子,SLIB library是一个我记得被批评为在动态"中过于坚定的人。营。如果您阅读Section 1.1 on "features",就会从一开始就看到这一点:

  

SLIB维护Scheme 会话支持的功能列表。会话提供的功能集可能会在该会话期间发生变化。

您在SLIB中使用的documentation for the require form加载"模块继续这样:

  

程序:需要 功能

     
      
  • 如果(provided? feature)为真,则只需要返回。
  •   
  • 否则,如果在目录中找到了功能,则将加载相应的文件,#t将从此返回provide。之后提供该功能。
  •   
  • 否则(目录中未找到功能),将发出错误信号。
  •   

如果你仔细阅读这篇文章,你会感到震惊的是,当模块被加载时,它会构成整个框架。在运行时 - 而不是编译时链接,这对设计来说是陌生的。

所以"会话"是一组绑定,其 - 而不仅仅是它们的 - 在程序运行时期间发生变化。程序可以使用requireprovided? 突变会话。他们能够用require 直接观察突变。并且暗示他们可以间接观察由于require而在顶级环境变化中绑定的标识符集 - 对define的调用导致过程调用,这会导致运行时错误。事后再也不再如此。

因此,我们无法提供帮助,但总结说,按照设计此库的人员的理念,double A[10]; double B[10]; // ... do stuff ... // copy elements 3 to 7 in A to elements 2 to 6 in B memcpy(B+2, A+3, 5*sizeof(double) 是必不可少的。但并非每个Scheme用户或实施者都有这种理念。

答案 2 :(得分:0)

首先关闭Scheme是词法范围的。定义通常不仅限于在Racket中的顶级绑定。它可以在其他过程体中创建绑定。

在某些实现中,define可以操作状态,但仅适用于顶级定义。否则它就像let一样,将变量绑定到本地范围。以编程方式实际利用顶级重新绑定很困难。

因此,定义不会在方案代码中引入命令式样式。比较定义到设置!及其亲属,通过在任何环境中修改变量,从而允许在方案代码中使用命令式样式。