在 Scheme 中,`nil` 和 `null` 有啥区别?

Posted

技术标签:

【中文标题】在 Scheme 中,`nil` 和 `null` 有啥区别?【英文标题】:In Scheme, what is the difference between `nil` and `null`?在 Scheme 中,`nil` 和 `null` 有什么区别? 【发布时间】:2022-01-15 23:25:35 【问题描述】:

在《小谋士》中,null 用于指代空列表()。但我还在 Scheme 的错误消息中看到称为 nil 的空列表,例如正在做:

(car ())

原因:

Error: Attempt to apply car on nil [car][1]

这听起来像是将() 称为nil


[1] 使用 replit.com 的 BiwaScheme 解释器 0.6.4 版


这个问题类似于What is the exact difference between null and null in common lisp。这是不同的,因为正如这里的答案所指出的那样,Common Lisp 和 Scheme 在处理 nilnull 方面存在差异。

【问题讨论】:

这能回答你的问题吗? What is the exact difference between NULL and NIL in Common Lisp? Scheme 是 LISP 的后代吗? 是的,Scheme 是一个 Lisp。 nullnil 是否都引用了空列表?我从您的链接中阅读了一些答案,但没有找到答案。 AFAICT,TLS 仅提及“空列表”,它在最常见的意义上使用“空”作为形容词。 (这也是 null? 谓词所做的。)另一方面,nil 是一个名词。 【参考方案1】:

我认为您所看到的是错误消息中的历史产物。

在传统的 Lisps 中,nil 既是空列表又是布尔 false,并且在其他各种方面都相当特殊(例如,它 也是 一个符号,这很奇怪)。

所以特别是()nil 在这样的Lisp 中是同一个对象,(not nil) 是真的,(not '()) 也是真的(事实上(not ()) 是合法的也是真的) .空列表对象的谓词是null(也许应该是nullp,但历史证明它就是这样),(null nil) 是真的,(null '())(null ()) 也是如此。

还有关于(car nil) aka (car '()) aka (car ()) 应该做什么的问题。传统上的答案是这很好,(car nil)nil。如果你够聪明的话,这会给你一个非常简洁的nil 实现。

方案现在取消了所有这些双关语:

有一个唯一的假对象#f/#false,不是空列表; 所有其他对象都为真,所以(not x) 仅当x#f 时为真; 有一个唯一的空列表对象,它是(),它不是#f,因此它是正确的; 此对象的谓词是null?,所以(null? '()) 为真,但(null? #f) 为假; carcdr() 是错误的; nil 只是一个符号,在语言中根本没有特殊地位。

我不认为给 () 起一个名字是标准的,但显然给它起一个名字可能会有用,null 很好:例如,Racket 就是这样做的。

所以在 Scheme 中,nil 已经消失了,空列表和布尔值之间的双关语也随之消失。

但是很多实现 Schemes 的人都知道nil 就是人们所说的空列表。所以当他们写错误信息的时候,他们写的是nil,当他们的意思是(),因为这是每个人都叫()很长一段时间了。

我认为,这就是你在这里看到的。

【讨论】:

可能值得补充:在 Common Lisp 中 nil() 是自评估符号,所以 (null nil)(null 'nil)(null ())(null '()) 都可以。在 Scheme 中 ()not 自评估的,(null? ()) 是语法错误;空列表必须在 Scheme 中引用:(null? '())。 WRT null vs nullp in CL:我有时希望它是nullp,而且我经常不小心输入nullp,尤其是在编写一些Common Lisp之前编写了一堆Scheme代码之后;) @adabsurdum:我同意这一点,但我不想深入了解它的血腥细节(我有一个较早的草稿,其中包含更多内容,但我认为它刚刚得到离原来的问题太远了)。 另外 () 在 Scheme 中不是一个有效的表达式。一些实现允许它,但标准很清楚你需要引用它来获取空列表。例如。 (null? ()) 不是有效的 Scheme 表达式,而 (null? '()) 是。 OP 表达式 (car ()) 有同样的问题,因此可能在 car 应用程序之前失败。 @Sylwester:是的。我想我一直在答案中引用(),除非明确指出它在传统的lisps中被允许不引用)。事实上,我现在也总是在 CL 中引用(),事实上,因为这对我来说更有意义。曾经我不习惯,但曾经我没有品味……【参考方案2】:

不同 Lisps 的区别在于它们处理 true、false 和 nil 的方式。

在 Common Lisp 中,t 表示真,nil 表示假,尽管除了 nil 之外的所有内容实际上都是真的。如果列表为空,或者find 什么也没找到,我们有nil,我们可以直接测试。技术术语是nil punning

'() ; => NIL
(= 1 2) ; => NIL
(if '() "full" "empty") ; => "empty"

(find 5 '(1 2 3 4)) ; => NIL
(if (find 5 '(1 2 3 4)) "found" "not found" ; => "not found"

Clojure 的做法不同。 true 有一个官方真值,falsenil 有两个假值 - 除了falsenil 之外的所有值也是真的。空列表不再是nil,您需要对空列表使用单独的测试,使用empty?nil 的值更像是 C 语言中的 void。是好是坏? - 你决定。

'() ; => ()
(= 1 1) ; => true
(= 1 2) ; => false
(if '() "full" "empty") ; => "full"
(if (empty? '()) "empty" "full") ; => "empty"
(if nil "full" "empty") ; => "empty"
(if (println "Hello world") "full" "empty") ; => empty

Scheme 在意图上更接近 Clojure。这里有一个错误值,#f。空列表不再是nil,需要对空列表使用单独的测试,用null?

(= 1 1) ; => #t
(= 1 2) ; => #f
(null? '()) ; => #t
(null? 'nil) ; => #f

所以,null 是空列表的另一个名称,但 nil'nil 不是。

null ; => ()
nil  ; =>  cannot reference an identifier before its definition
'nil ; => nil

(car ()) 怎么样?您的 Scheme 从评估 () 中返回 nil,这就是 car 所抱怨的。我的计划,Racket 博士,根本拒绝玩,说空列表中缺少表达式。

【讨论】:

以上是关于在 Scheme 中,`nil` 和 `null` 有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章

Objective-C 中 nil、NIL 和 null 之间的区别

nil和null的区别

NULL & nil & Nil & NSNULL

objective-C nil,Nil,NULL 和NSNull的小结

iOS 中nil,Nil,NULL,NSNull的区别

iOS中使用nil NULL NSNULL的区别