【问题标题】:Racket/Scheme - (define ((function-name arg1) arg2) (body ...)) - NotationRacket/Scheme - (define ((function-name arg1) arg2) (body ...)) - 符号
【发布时间】:2021-03-20 02:42:00
【问题描述】:

这个符号的名称是什么/它代表什么?

(define ((function-name arg1) arg2) (body ...))

我了解在 Racket/Scheme 中您可以通过以下两种方式定义函数:

(define (function-name arg1 arg2 ...) (body ...))

(define function-name (lambda (arg1 ...) (body ...))

不过,我最近在 Chris Hanson 和 Gerald Jay Sussmaan 的 Software Design For Flexibility 中看到了这个符号:

(define ((function-name arg1) arg2) (body ...))

我注意到这个符号在 Scheme(本书是用它编写的)和 Racket 中也适用。

有谁知道define语句参数中的函数应用程序的这个符号的名称? / 它可能代表什么?

【问题讨论】:

标签: scheme racket


【解决方案1】:

这是一个扩展,不是标准方案的一部分。这个扩展在 MIT/GNU Scheme 中已经有很长一段时间了,其他一些实现也采用了它。

R7RS 规范未显示与 OP 发布的示例定义匹配的表单。最接近的匹配是 5.3 中的 this。变量定义

  • (define (<variable> <formals>) <body>)
    <Formals> 是零个或多个变量的序列,或者是一个或多个变量后跟一个空格分隔的句点和另一个变量的序列(如在 lambda 表达式中)。

有问题的定义是:

(define ((function-name arg1) arg2) (body ...))

这里,(function-name arg1) 必须被视为一个变量才能匹配标准中的描述;但它不是变量,甚至不是标识符。

来自 3.1。变量、句法关键字和区域

命名位置的标识符称为变量,并且被称为绑定到该位置。

值得指出的是,Hanson 和 Sussman 的书的附录 B 简要讨论了这种结构:

在 MIT/GNU 方案中,我们可以递归地使用糖来编写:

(define ((compose f g) x)
  (f (g x)))

现在,在第 1 页。 MIT/GNU Scheme Reference Manual (11.1) 的第 17 节表明:

(define (name1 name2 ...)
  expression
  expression ...)

相当于:

(define name1
  (named-lambda (name1 name2 ...)
    expression
    expression ...))

请注意,MIT/GNU 手册中显示的语法显示了 lambda

lambda formals expr expr ... [扩展标准特殊形式]

这里,formals 被描述为“形参列表”,但请注意没有使用术语variable。术语变量在手册的其他地方使用,例如,在let 表单的描述中。

named-lambda 特殊形式描述:

named-lambda formals 表达式 表达式 ... [特殊形式]
named-lambda 特殊形式与 lambda 类似,只是 formals 中的第一个“必填参数”不是参数而是 结果过程的名称;因此 formals 必须至少有一个必需参数。该名称没有语义含义,但包含在过程的外部表示中,因此对调试很有用。在 MIT/GNU Scheme 中,lambda 被实现为 named-lambda,具有一个特殊的名称,意思是“未命名”。

所以,(define ((function-name arg1) arg2) (body ...)) 的定义可以改写为:

(define (function-name arg1)
  (named-lambda ((function-name arg1) arg2) (body ...)))

根据手册提供的上述转换规则,由于形式参数列表已在 MIT/GNU 方案中进行了扩展,因此它不仅限于包含 变量

然后可以使用相同的规则再次(递归)扩展最后一个结果:

(define function-name
  (named-lambda (function-name arg1)
    (named-lambda ((function-name arg1) arg2)
      (body ...))))

由于named-lambdalambda 类似,即不同之处仅在于有一些额外的元数据与之关联,但语义相同,我们可以写出语义等价:

(define function-name
  (lambda (arg1)
    (lambda (arg2)
      (body ...))))

这只是高阶过程的定义。因此,所讨论的符号只是便于定义高阶过程的语法糖。请注意,SRFI 201 旨在为其他 Scheme 实现提供此功能,并将其称为“高阶 define 形式”,以及“@ 的“柯里化”变体987654339@ 表格。”

回到Software Design for Flexibility附录B中的示例程序,可以看出如何使用这种句法糖巧妙地表达函数组合的思想。

(define ((compose f g) x)
  (f (g x)))

这里,compose 是一个带有两个参数 fg 的过程,它返回一个带有一个参数 x 的过程:

1 (user) => (define my-composition (compose square cube))
;Value: my-composition
1 (user) => (my-composition 2)
;Value: 64

【讨论】:

    【解决方案2】:

    这绝对是不寻常的,我从未在任何地方看到它明确记录,但它确实适用于至少一些方案实现(Chicken、Racket,无论你尝试接受它的任何其他方案,Guile 都不接受)。

    R7RS 的措辞提供了一些见解:

    (define (〈variable〉 〈formals〉)〈body〉)

    〈Formals〉 是零个或多个变量的序列,或者是一个或多个变量的序列,后跟一个空格分隔的句点和另一个变量(如在 lambda 表达式中)。这种形式相当于(define〈variable〉(lambda (〈formals〉)〈body〉))

    所以这个:

    (define ((example a) b) (printf "~A~%~A~%" a b))
    

    可以认为等价于

    (define (example a) (lambda (b) (printf "~A~%~A~%" a b)))
    

    相当于

    (define example (lambda (a) (lambda (b) (printf "~A~%~A~%" a b))))
    

    并且接受这种表示法的方案可能会在某些时候在内部进行类似的转换,作为它们实现define-ing 函数的一部分。这与使用第一种形式定义鸡时 example 对鸡的行为相匹配。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-01-29
      • 1970-01-01
      • 1970-01-01
      • 2013-05-01
      • 2010-09-25
      • 2020-05-23
      相关资源
      最近更新 更多