如何在最后放置 Lisp/Scheme/Racket 符号?
How to put Lisp/Scheme/Racket symbol at the end?
Lisp/Scheme/Racket 中的表格将符号放在第一个位置。此代码适用于 Racket:
(define (? a b) (if a (display b) 0))
(? #t "Hello")
但我想在C/C++中模拟a? b:0
语句,问号(符号)应该在最后,在a
之后。
如何把?
和a
和b
按这个顺序排列?
(define (a ? b) (if a (display b) 0))
(#t ? "Hello")
我需要使用 define-syntax
之类的东西吗?
你的问题我有三个答案。
1 不要那样做
每种语言都有规则、惯例和语用学。如果你试图强迫它看起来像 C/C++,你的 Racket 体验将会很痛苦。你会在这样的问题上浪费时间,而不是学习在 Racket 编程模型中思考并使用 Racket 围绕该模型开发的工具。
对于一个具体的例子,Racket 有一个规则,即一个形式(表达式、定义、声明等)以 运算符 开头(如 display
或 list
或 +
) 或 语法关键字 (如 define
或 if
)。该规则消除了许多妨碍可扩展语法的复杂问题。例如,与其他特殊形式相比,中缀语法的优先级是什么?在 (lambda ? 5)
中,是 lambda
形式还是(错误的)?
形式?
澄清一下:Racket 绝对鼓励您在 S 表达式、运算符优先语法的范围内使用新的语法形式扩展语言。
2 部分解决方案
Racket 的 reader 对 "infix syntax" 的支持形式有限。如果您在带括号的组中的单个术语周围加上点,reader 会将括起来的术语移到前面。因此 reader 将以下两个术语视为相同:
(1 . < . 2)
(< 1 2)
所以你可以这样写
(#t . ? . "Hello")
就个人而言,我认为这通常会使代码更难阅读。
3 个开放研究课题
人们正在研究扩展 Racket 的语言构建框架,以便与基于非 S 表达式的语法很好地协同工作。一个例子是 Honu;请参阅论文 "Honu: Syntactic Extension for Algebraic Notation through Enforestation。还有其他的,话题还没完呢
让我通过覆盖应用程序语法来提供替代解决方案 #%app
。下面是类 C 语言中的三元运算符示例:
#lang racket
(require syntax/parse/define
(only-in racket [#%app racket:#%app]))
(define-syntax-parser #%app
[(_ test-expr {~datum ?} then-expr {~datum :} else-expr)
#'(if test-expr then-expr else-expr)]
[(_ xs ...)
#'(racket:#%app xs ...)])
> ((= 42 42) ? "a" : "b")
"a"
> ((= 42 0) ? "a" : "b")
"b"
因为应用语法的优先级最低,所以会优先考虑其他语法:
> (define-simple-macro (discard-all xs ...) 1)
> (discard-all ? 42 : 123)
1
> (if ? 1 : 2)
if: bad syntax ;; because if should have exactly three subforms, but the above line has four.
但正如 Ryan 所说,从某种意义上说,这不是 "good" Racket 代码,因为它违背了 Racket 惯例,没有人(嗯,可能除了你)能够理解你的代码。
Lisp/Scheme/Racket 中的表格将符号放在第一个位置。此代码适用于 Racket:
(define (? a b) (if a (display b) 0))
(? #t "Hello")
但我想在C/C++中模拟a? b:0
语句,问号(符号)应该在最后,在a
之后。
如何把?
和a
和b
按这个顺序排列?
(define (a ? b) (if a (display b) 0))
(#t ? "Hello")
我需要使用 define-syntax
之类的东西吗?
你的问题我有三个答案。
1 不要那样做
每种语言都有规则、惯例和语用学。如果你试图强迫它看起来像 C/C++,你的 Racket 体验将会很痛苦。你会在这样的问题上浪费时间,而不是学习在 Racket 编程模型中思考并使用 Racket 围绕该模型开发的工具。
对于一个具体的例子,Racket 有一个规则,即一个形式(表达式、定义、声明等)以 运算符 开头(如 display
或 list
或 +
) 或 语法关键字 (如 define
或 if
)。该规则消除了许多妨碍可扩展语法的复杂问题。例如,与其他特殊形式相比,中缀语法的优先级是什么?在 (lambda ? 5)
中,是 lambda
形式还是(错误的)?
形式?
澄清一下:Racket 绝对鼓励您在 S 表达式、运算符优先语法的范围内使用新的语法形式扩展语言。
2 部分解决方案
Racket 的 reader 对 "infix syntax" 的支持形式有限。如果您在带括号的组中的单个术语周围加上点,reader 会将括起来的术语移到前面。因此 reader 将以下两个术语视为相同:
(1 . < . 2)
(< 1 2)
所以你可以这样写
(#t . ? . "Hello")
就个人而言,我认为这通常会使代码更难阅读。
3 个开放研究课题
人们正在研究扩展 Racket 的语言构建框架,以便与基于非 S 表达式的语法很好地协同工作。一个例子是 Honu;请参阅论文 "Honu: Syntactic Extension for Algebraic Notation through Enforestation。还有其他的,话题还没完呢
让我通过覆盖应用程序语法来提供替代解决方案 #%app
。下面是类 C 语言中的三元运算符示例:
#lang racket
(require syntax/parse/define
(only-in racket [#%app racket:#%app]))
(define-syntax-parser #%app
[(_ test-expr {~datum ?} then-expr {~datum :} else-expr)
#'(if test-expr then-expr else-expr)]
[(_ xs ...)
#'(racket:#%app xs ...)])
> ((= 42 42) ? "a" : "b")
"a"
> ((= 42 0) ? "a" : "b")
"b"
因为应用语法的优先级最低,所以会优先考虑其他语法:
> (define-simple-macro (discard-all xs ...) 1)
> (discard-all ? 42 : 123)
1
> (if ? 1 : 2)
if: bad syntax ;; because if should have exactly three subforms, but the above line has four.
但正如 Ryan 所说,从某种意义上说,这不是 "good" Racket 代码,因为它违背了 Racket 惯例,没有人(嗯,可能除了你)能够理解你的代码。