Racket 变量定义和函数定义的根本区别

Racket 变量定义和函数定义的根本区别,racket,Racket,我正在通过《球拍王国》一书学习球拍。我注意到定义变量和定义函数是通过相同的关键字来完成的-define。这让我思考了不带参数且仅返回值5的函数与返回值5的变量之间的根本区别。i、 e: (define fiveVar 5) (define (fiveFun) 5) (如果camel case不是正确的命名约定,则表示歉意-只是拿起书,不知道任何Lisp) 乍一看,在这两种情况下,我似乎只是给值5起了个名字。事实上,我甚至可以重新附加名称fiveFun:(set fiveFun 6),就像

我正在通过《球拍王国》一书学习球拍。我注意到定义变量和定义函数是通过相同的关键字来完成的-
define
。这让我思考了不带参数且仅返回值
5
的函数与返回值
5
的变量之间的根本区别。i、 e:

(define fiveVar 5)

(define (fiveFun)
  5)
(如果camel case不是正确的命名约定,则表示歉意-只是拿起书,不知道任何Lisp)

乍一看,在这两种情况下,我似乎只是给值
5
起了个名字。事实上,我甚至可以重新附加名称
fiveFun
(set fiveFun 6)
,就像使用变量一样


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

差不多,是的。事实上,
(define(f x…)
符号只是Scheme和其他Lisp-1中的一个方便的缩写,这与将函数和值分离到不同名称空间的普通Lisp和其他Lisp-2不同

在Racket and 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中,您可能需要这样一个功能有几个原因:

  • 您可以使用无参数函数将计算“延迟”到下一次,甚至可以多次运行它,如果运行该函数有副作用,这将非常有用。例如:

    > (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
    
    >(定义x(开始(显示“Hello!”)5))
    你好
    >x
    5.
    >x
    5.
    >(定义f(lambda()(displayln“Hello!”)5))
    >f
    #
    >(f)
    你好
    5.
    >(f)
    你好
    5.
    
  • 此外,生成一个值可能需要很长时间,您可能希望将其计算推迟到实际需要时。当实际使用该函数时,可以使用零参数函数“延迟”运行计算


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

    Alexis,谢谢你的解释。这张长手稿清楚地表达了我的想法。在这个意义上与哈斯克尔非常相似。@StevenL。是的,非常相似!当然,区别在于Haskell没有无参数函数的概念,因为Haskell既懒惰又纯粹,所以它们没有用处。