变量定义与函数定义的基本区别

时间:2017-01-01 17:27:19

标签: racket

我正在通过书籍Realm of Racket学习球拍。我注意到定义变量和定义函数是通过相同的关键字 - define完成的。这让我想到了一个不带参数的函数和简单地返回值5之间的根本区别,以及一个返回值5的变量。即:

(define fiveVar 5)

(define (fiveFun)
  5)

(道歉,如果骆驼案不是正确的命名惯例 - 只是拿起书并且不知道任何Lisp)。

乍一看,在我看来,在两种情况下,我只是给值5命名。事实上,我甚至可以使用变量重新附加名称fiveFun(set fiveFun 6)

再次,在我看来,定义变量和定义函数之间没有区别。在这两种情况下,我都给数据类型命名。在函数数据类型的情况下,可以应用它,而数字则不能。

1 个答案:

答案 0 :(得分:7)

差不多,是的。事实上,(define (f x ...) ...)表示法只是Scheme和其他Lisp-1中的一个方便的缩写,与Common Lisp和其他Lisp-2形成鲜明对比,后者将函数和值分成不同的名称空间。

在Racket和Scheme中,当你写这个:

(define (f x) (+ x 1))

这实际上只是写这个的简写符号:

(define f (lambda (x) (+ x 1)))

lambda表单是一个生成过程值的特殊表单,但是创建的绑定(在本例中为f)与绑定没有区别一个普通的价值。由于过程只是与其他过程一样的值,因此使用所谓的“高阶”函数 - 接受函数作为参数的函数 - 易于编写和使用。例如,filter将函数作为其第一个参数:

> (filter even? '(1 2 3 4))
'(2 4)

现在,考虑到这一点,你在问题中写的函数定义实际上就是这样,没有简写:

(define fiveFun (lambda () 5))

那么,考虑一下这两件事之间的区别:

(define fiveVar 5)
(define fiveFun (lambda () 5))

好吧,其中一个是数字5,另一个是没有参数的函数,当应用时,生成 5.有些语言,大部分都是纯函数,甚至没有一个不带参数的函数的概念,因此没有有意义的方法来表达这些语言中的fiveFun。但是,在Racket中,有几个原因可能需要这样的功能:

  1. 您可以使用无参数函数将评估“延迟”到另一个时间,甚至多次运行,这在运行该函数时会产生副作用。例如:

    > (define x (begin (displayln "Hello!") 5))
    Hello!
    > x
    5
    > x
    5
    
    > (define f (lambda () (displayln "Hello!") 5))
    > f
    #<procedure:f>
    > (f)
    Hello!
    5
    > (f)
    Hello!
    5
    
  2. 此外,值可能需要很长的时间才能生成,您可能希望将其评估推迟到实际需要时。当实际使用该函数时,您可以使用零参数函数来“懒惰地”运行计算。

  3. 作为一小段术语,零参数函数通常被称为“thunk”,您可能会在Racket文档中的某些地方看到它。甚至还有一个来自thunk的名为racket/function的表单,它是零参数lambda的简写。