Chez Scheme遵从R6RS 规范
chez scheme 中输入 (apropos 'scheme) (apropos 'env)
(apropos 'print)
(pp (apropos-list 'print))
(apropos-list "str")
模糊查询全局 symbol
(feng: 管理与编程相似... 稍有不周,就是bug,)
在Chez Scheme中,我们可以使用检查器查看导出过程的源代码。让我们加载我的chez-stats
库并检查mean
(inspect mean)
chez scheme 重要的一个宏mat 在 mat.ms 中.
(eval-when (load eval)
(define-syntax mat
(lambda (x)
(syntax-case x (parameters)
[(_ x (parameters [param val ...] ...) e ...)
#'(let f ([p* (list param ...)] [v** (list (list val ...) ...)])
(if (null? p*)
(mat x e ...)
(let ([p (car p*)])
(for-each
(lambda (v)
(parameterize ([p v])
(f (cdr p*) (cdr v**))))
(car v**)))))]
[(_ x e ...)
(with-syntax ([(source ...)
(map (lambda (clause)
(let ([a (syntax->annotation clause)])
(and (annotation? a) (annotation-source a))))
#'(e ...))])
#'(mat-run 'x '(e source) ...))]))))
Chez Scheme 从头到尾都是 Kent 一个人的作品。它的工作原理是从 Scheme 源程序一直编译到机器代码,而不依赖任何其他语言的编译器。它甚至不依赖第三方的汇编器,所有三种体系构架(Intel, ARM, SPARC)的汇编器,都是 Kent 自己写的。为什么这样做呢?因为几乎没有其它人的编译器代码能够达到他的标准。连 Intel 自己给自己的处理器写的汇编器,都不能满足他的要求。
ppc32.ss 是PowerPC 没有32位 .因为年轻 1993年发布的
arm32.ss 是 arm cpu
x86.ss 和 x86
chez scheme 一级目录 (2021年5月27日)
.
├── BUILDING
├── CHARTER.md
├── CONTRIBUTING.md
├── LICENSE
├── LOG
├── NOTICE
├── README.md
├── bintar
├── boot
├── c ;运行时 垃圾收集
├── checkin
├── configure
├── csug
├── examples
├── lz4
├── makefiles
├── mats ;测试文件夹
├── nanopass ;编译框架
├── newrelease
├── pkg
├── release_notes
├── rpm
├── s ;scheme ss 文件
├── scheme.1.in
├── stex
├── unicode
├── wininstall
├── workarea
└── zlib
cmacros.ss
(define-syntax define-who
(lambda (x)
(syntax-case x ()
[(k (id . args) b1 b2 ...)
#'(k id (lambda args b1 b2 ...))]
[(k #(prefix id) e)
(and (identifier? #'prefix) (identifier? #'id))
(with-implicit (k who)
(with-syntax ([ext-id (construct-name #'id #'prefix #'id)])
#'(define ext-id (let ([who 'id]) (rec id e)))))]
[(k id e)
(identifier? #'id)
(with-implicit (k who)
#'(define id (let ([who 'id]) e)))])))
Manufacturing Automated Test System mats?
https://open.163.com/newview/movie/free?pid=EEV1GO9MG&mid=AEV1GO9OS
好的编译课程
pre-defined or built-in 相当重要.. 内置的函数. lisp的7个原生操作符. 还有clojure启动起来就包含的核心库函数.
If you looked up the primitive operations of BSL, you saw that primitive
(sometimes called pre-defined or built-in) operations can consume strings and produce numbers:
http://htdp.org/2021-5-4/Book/part_prologue.html 好书..
http://www.r6rs.org/final/html/r6rs/r6rs-Z-H-2.html 规范
What all this means for you is that functions provide a rather economic way of computing lots of interesting values with a single expression. Indeed, programs are functions; and once you understand functions well, you know almost everything there is to know about programming. Given their importance, let’s recap what we know about functions so far:
-
First,
(define (FunctionName InputName) BodyExpression)
https://www.zhihu.com/question/292102918
如果查找BSL的基元操作,您会发现基元(有时称为预定义或内置)操作可以使用字符串并生成数字:
https://www.cnblogs.com/lsgxeva/p/9432975.html
1.1. 基本类型
Scheme程序操作对象(object),有时也被成为值(value)。Scheme对象被组织为叫做类型(type)的值的集合。本节将给你Scheme语言十分重要的类型的一个概述。更多的类型将在后面章节进行描述。
注意:由于Scheme采用隐式类型,所以本报告中术语类型的使用与其它语言文本中本术语的使用不同,尤其是与那些显式语言中的不同。
布尔(Booleans) 布尔类型是一个真值,可以是真或假。在Scheme中,对象“假”被写作#f
。对象“真”被写作#t
。然而,在大部分需要一个真值的情况下,凡是不同于#f
的对象被看作真。
数值(Numbers) Scheme广泛支持各类数值数据结构,包括任意精度的整数,有理数,复数和各种类型的非精确数。第3章给了Scheme数值塔结构的概述。
字符(Characters) Scheme字符多半等价于一个文本字符。更精确地说,它们同构与Unicode字符编码标准的标量值(scalar values)。
字符串(Strings) 字符串是确定长度字符的有限序列,因此它代表任意的Unicode文本。
符号(Symbols) 符号是一个表示为字符串的对象,即它的名字。不同于字符串,两个名字拼写一样的符号永远无法区分。符号在许多应用中十分有用;比如:它们可以像其它语言中枚举值那样使用。
点对(Pairs)和表(lists) 一个点对是两个元素的数据结构。点对最常用的用法是(逐一串联地)表示表,在这种表结构中,第一个元素(即“car”)表示表的第一个元素,第二个元素(即“cdr”)表示表的剩余部分。Scheme还有一个著名的空表,它是表中一串点对的最后一个cdr。
向量(Vectors) 像表一样,向量是任意对象有限序列的线性数据结构。然而,表的元素循环地通过链式的点对进行访问,向量的元素通过整数索引进行标识。所以,比起表,向量更适合做元素的随机访问。
过程(Procedures) 在Scheme中过程是值。
1.2. 表达式(Expressions)
Scheme代码中最重要的元素是表达式。表达式可以被计算(evaluated),产生一个值(value)。(实际上,是任意数量的值—参见5.8节。)最基本的表达式就是字面的表达式:
#t ⇒ #t
23 ⇒ 23
这表明表达式#t
的结果就是#t
,也就是“真”的值,同时,表达式23计算得出一个表示数字23的对象。
复合表达式通过在子表达式周围放置小括号来组合。第一个子表达式表示一个运算;剩余的子表达式是运算的操作数:
(+ 23 42) ⇒ 65
(+ 14 (* 23 42)) ⇒ 980
上面例子中的第一个例子,+
是内置的表示加法的运算的名字,23和42是操作数。表达式(+ 23 42)
读作“23和42的和”。复合表达式可以被嵌套—第二个例子读作“14和23和42的积的和”。
正如这些例子所展示的,Scheme中的复合表达式使用相同的前缀表示法(prefix notation)书写。所以,括号在表达这种结构的时候是必要的。所以,在数学表示和大部分语言中允许的“多余的”括号在Scheme中是不被允许的。
正如其它许多语言,空白符(包括换行符)在表达式中分隔子表达式的时候不是很重要,它也可以用来表示结构。
1.3. 变量(variable)和绑定(binding)
Scheme允许标识符(identifier)代表一个包含值得位置。这些标识符叫做变量。在许多情况下,尤其是这个位置的值在创建之后再也不被修改的时候,认为变量直接代表这个值是非常有用的。
(let ((x 23)
(y 42))
(+ x y)) ⇒ 65
在这种情况下,以let
开头的表达式是一种绑定结构。跟在let
之后的括号结构列出了和表达式一起的变量:和23一起的变量x
,以及和42一起的变量y
。let
表达式将x
绑定到23,将y
绑定到42。这些绑定在let
表达式的内部(body)是有效的,如上面的(+ x y)
,也仅仅在那是有效的。
1.4. 定义
let
表达式绑定的变量是局部的(local),因为绑定只在let
的内部可见。Scheme同样允许创建标识符的顶层绑定,方法如下:
(define x 23)
(define y 42)
(+ x y) ⇒ 65
(这些实际上是在顶层程序或库的内部的“顶层”;参见下面的1.12节。)
开始的两个括号结构是定义,它们创造了顶层的绑定,绑定x
到23,绑定y
到42。定义不是表达式,它不能出现在所有需要一个表达式出现的地方。而且,定义没有值。
绑定遵从程序的词法结构:当存在相同名字的绑定的时候,一个变量参考离它最近的绑定,从它出现的地方开始,并且以从内而外的方式进行,如果在沿途没有发现局部绑定的话就使用顶层绑定:
(define x 23)
(define y 42)
(let ((y 43))
(+ x y)) ⇒ 66
(let ((y 43))
(let ((y 44))
(+ x y))) ⇒ 67
1.5. 形式(Forms)
尽管定义不是表达式,但是复合表达式和定义有相同的语法形式:
(define x 23)
(* x 2)
尽管第一行包含一个定义,第二行包含一个表达式,但它们的不同依赖于define
和*
的绑定。在纯粹的语法层次上,两者都是形式,形式是Scheme程序一个语法部分的名字。特别地,23是形式(define x 23)
的一个子形式(subform)。
1.6. 过程
定义也可以被用作定义一个过程:
(define (f x)
(+ x 42))
(f 23) ⇒ 65
简单地说,过程是一个表达式对象的抽象。在上面这个例子中,第一个定义定义了一个叫f
的过程。(注意f x
周围的括号,这表示这是一个过程的定义。)表达式(f 23)
是一个过程调用,大概意思是“将x
绑定到23计算(+ x 42)
(过程的内部)的值”。
由于过程是一个对象,所以它们可以被传递给其它过程:
(define (f x)
(+ x 42))
(define (g p x)
(p x))
(g f 23) ⇒ 65
在上面这个例子中,g
的内部被视为p
绑定到f
,x
绑定到23,这等价于(f 23)
,最终结果是65。
实际上,Scheme许多预定义的操作不是通过语法提供的,而是值是过程的变量。比如,在其它语言中受到特殊对待的+
操作,在Scheme中只是一个普通的标识符,这个标识符绑定到一过程,这个过程将数字对象加起来。*
和许多其它的操作也是一样的:
(define (h op x y)
(op x y))
(h + 23 42) ⇒ 65
(h * 23 42) ⇒ 966
过程定义不是定义过程的唯一方法。一个lambda表达式可以在不指定一个名字的情况下以对象的形式生成一个过程:
((lambda (x) (+ x 42)) 23) ⇒ 65
这个例子中的整个表达式是一个过程调用;(lambda (x) (+ x 42))
,相当于一个输入一个数字并加上42的过程。
1.7. 过程调用和语法关键词(syntactic keywords)
尽管(+ 23 42)
, (f 23)
和((lambda (x) (+ x 42)) 23)
都是过程调用的例子,但lambda
和let
表达式不是。这时因为尽管let
是一个标识符,但它不是一个变量,而是一个语法关键词。以一个语法关键词作为第一个子表达式的形式遵从关键词决定的特殊规则。define
标识符是一个定义,也是一个语法关键词。因此,定义也不是一个过程调用。
lambda
关键词的规则规定第一个子形式是一个参数的表,其余的子形式是过程的内部。在let
表达式中,第一个子形式是一个绑定规格的表,其余子形式构成表达式的内部。
通过在形式的第一个位置查找语法关键词的方法,过程调用通常可以和这些特殊形式区别开来:如果第一个位置不包含一个语法关键词,则这个表达式是一个过程调用。(所谓的标识符的宏(identifier macros)允许创建另外的特殊形式,但相当不常见。)Scheme语法关键词的集合是非常小的,这通常使这项任务变得相当简单。可是,创建新的语法关键词的绑定也是有可能的,见下面的1.9节。
1.8. 赋值(Assignment)
Scheme变量通过定义或let
或lambda
表达式进行的绑定不是直接绑定在各自绑定时指定的对象上,而是包含这些对象的位置上。这些位置的内容随后可通过赋值破坏性地改写:
(let ((x 23))
(set! x 42)
x) ⇒ 42
在这种情况下,let
的内部包括两个表达式,这两个表达式被顺序地求值,最后一个表达式的值会成为整个let
表达式的值。表达式(set! x 42)
是一个赋值,表示“用42代替x
所指向位置的对象”。因此,x
以前的值,23,被42代替了。
1.9. 衍生形式(Derived forms)和宏(macros)
在本报告中,许多特殊的形式可被转换成更基本的特殊形式。比如,一个let
表达式可以被转换成一个过程调用和一个lambda表达式。下面两个表达式是等价的:
(let ((x 23)
(y 42))
(+ x y)) ⇒ 65
((lambda (x y) (+ x y)) 23 42) ⇒ 65
像let
表达式这样的特殊形式叫做衍生形式,因为它们的语义可以通过语法转换衍生自其它类型的形式。一些过程定义也是衍生形式。下面的两个定义是等价的:
(define (f x)
(+ x 42))
(define f
(lambda (x)
(+ x 42)))
在Scheme中,一个程序通过绑定语法关键词到宏以定义它自己的衍生形式是可能的:
(define-syntax def
(syntax-rules ()
((def f (p ...) body)
(define (f p ...)
body))))
(def f (x)
(+ x 42))
define-syntax
结构指定一个符合(def f (p ...) body)
模式的括号结构,其中f
,p
和body
是模式变量,被转换成(define (f p ...) body)
。因此,这个例子中的def
形式将被转换成下面的语句:
(define (f x)
(+ x 42))
创建新的语法关键词的能力使得Scheme异常灵活和负有表现力,允许许多内建在其它语言的特性在Scheme中以衍生形式出现。
1.10. 语法数据(Syntactic data)和数据值(datum values)
Scheme对象的一个子集叫做数据值。这些包括布尔,数据对象,字符,符号,和字符串还有表和向量,它们的元素是数据。每一个数据值都可以以语法数据的形式被表现成字面形式,语法数据可以在不丢失信息的情况下导出和读入。一个数据值可以被表示成多个不同的语法数据。而且,每一个数据值可以被平凡地转换成一个一个字面表达式,这种转换通过在程序中加上一个'
在其对应的语法数据前:
'23 ⇒ 23
'#t ⇒ #t
'foo ⇒ foo
'(1 2 3) ⇒ (1 2 3)
'#(1 2 3) ⇒ #(1 2 3)
在数字对象和布尔中,前一个例子中的'
是不必要的。语法数据foo
表示一个名字是“foo”的符号,且'foo
是一个符号作为其值对的字面表达式。(1 2 3)
是一个元素是1,2和3的表的语法数据,且'(1 2 3)
是一个值是表的字面表达式。同样,#(1 2 3)
是一个元素是1,2和3的向量,且'#(1 2 3)
是对应的字面量。
语法数据是Scheme形式的超集。因此,数据可以被用作以数据对象的形式表示Scheme形式。特别地,符号可以被用作表示标识符。
'(+ 23 42) ⇒ (+ 23 42)
'(define (f x) (+ x 42))
⇒ (define (f x) (+ x 42))
这方便了操作Scheme源代码程序的编写,尤其是解释和程序转换。
1.11. 继续(Continuations)
在Scheme表达式被求值的时候,总有一个继续在等待这个结果。继续表示计算的一整个(默认的)未来。比如,不正式地说,表达式
(+ 1 3)
中3的继续给它加上了1。一般地,这些普遍存在的继续是隐藏在背后的,程序员不需要对它们考虑太多。可是,偶尔,一个程序员需要显示地处理继续。过程call-with-current-continuation
(见11.15节)允许Scheme程序员通过创建一个接管当前继续的过程来处理这些。过程call-with-current-continuation
传入一个过程,并以一个逃逸过程作为参数,立刻调用这个过程。随后,这个逃逸过程可以用一个参数调用,这个参数会成为call-with-current-continuation
的结果。也就是说,这个逃逸过程放弃了它自己的继续,恢复了call-with-current-continuation
调用的继续。
在下面这个例子中,一个代表加1到其参数的逃逸过程被绑定到escape
上,且然后以参数3被调用。escape
调用的继续被放弃,取而代之的是3被传递给加1这个继续:
(+ 1 (call-with-current-continuation
(lambda (escape)
(+ 2 (escape 3)))))
⇒ 4
一个逃逸过程有无限的生存期:它可以在它捕获的继续被调用之后被调用,且它可以被调用多次。这使得call-with-current-continuation
相对于特定的非本地跳转,如其它语言的异常,显得异常强大。
1.12. 库
Scheme代码可以被组织在叫做库的组件中。每个库包含定义和表达式。它可以从其它的库中导入定义,也可以向其它库中导出定义。
下面叫做(hello)
的库导出一个叫做hello-world
的定义,且导入基础库(base library)(见第11章)和简单I/O库(simple I/O library)(见库的第8.3小节)。hello-world
导出的是一个在单独的行上显示Hello World的过程。
(library (hello)
(export hello-world)
(import (rnrs base)
(rnrs io simple))
(define (hello-world)
(display "Hello World")
(newline)))
1.13. 顶层程序
一个Scheme程序被一个顶层程序调用。像库一样,一个顶层程序包括导入,定义和表达式,且指定一个执行的入口。因此,一个顶层程序通过它导入的库的传递闭包定义了一个Scheme程序。
下面的程序通过来自(rnrs programs (6))
库(见库的第10章)的command-line
过程从命令行获得第一个参数。它然后用open-file-input-port
(见库的第8.2小节)打开一个文件,产生一个端口(port),也就是作为一个数据源的文件的一个连接,并调用get-bytes-all
过程以获得文件的二进制数据。程序然后使用put-bytes
输出文件的内容到标准输出:
(译注:以下的示例程序已根据勘误表进行了修正。)
#!r6rs
(import (rnrs base)
(rnrs io ports)
(rnrs programs))
(let ((p (standard-output-port)))
(put-bytevector p
(call-with-port
(open-file-input-port
(cadr (command-line)))
get-bytevector-all))
(close-port p))
2. 需求等级
本报告中的关键词“必须(must)”, “必须不(must not)”, “应该(should)”, “不应该(should not)”, “推荐的(recommended)”, “可以(may)”和“可选的(optional)”按照RFC211914描述的进行解释。特别地:
必须 这个词意味着一个陈述是规范的一个绝对必要条件。
必须不 这个短语意味着一个陈述是规范绝对禁止的。
应该 这个词,或形容词“推荐的”,意味着有合适的理由的时候,在特定的情况下可以忽略这个陈述,但应当理解其含义,并在选择不同的做法前要仔细权衡。
不应该 这个短语,或短语“不推荐”,意味着有合适的理由的时候,在特定的情况下,一个陈述的行为是可接受的,但应当理解其含义,且选择本陈述的描述前应当仔细权衡。
可以 这个词,或形容词“可选的”,意味着一个条目是真正可选的。
尤其,本报告偶尔使用“应该”去指定本报告规范之外但是实际上无法被一个实现检测到的情况;见5.4小节。在这种情况下,一个特定的实现允许程序员忽略本报告的建议甚至表现出其它合理的行为。然而,由于本报告没有指定这种行为,这些程序可能是不可移植的,也就是说,它们的执行在不同的实现上可能产生不同的结果。
此外,本报告偶尔使用短语“不要求”来指示绝对必要条件的缺失。
3. 数字(Numbers)
本章描绘Scheme的数字模型。区别如下对象的不同是重要的:数学上的数字,尝试去建模这些数字的Scheme对象,用于实现这些数字的机器表示和用于书写数字的符号。在本报告中,术语数字表示数学上的数字,术语数字对象(number object)表示代表一个数字的Scheme对象。本报告使用类型复数(complex),实数(real),有理数(rational)和整数(integer)同时表示数学上的数字和数字对象。定长数(fixnum)和浮点数(flonum)类型表示这些数字对象的特殊子集,由通常的机器表示决定,这些会在下面说明。
3.1. 数值塔(Numeracal tower)
数字可以被组织在一个子集的塔中,在这个塔中,每一层是上一层的子集:
number
complex
real
rational
integer
比如,5是一个整数。因此,5也是一个有理数,实数和复数。为5建模的数字对象也一样。
数字对象也被组织为一个对应的子类型的塔,这些类型被谓词(predicates)number?
, complex?
, real?
, rational?
和integer?
定义;见11.7.4.1节。整形数字对象也被叫做整数对象(integer objects)。
包含一个数字的子集和它在计算机中的表示是没有简单的关系的。比如,整数5可以有多个表示。Scheme的数值操作将数字对象当作抽象数据对待,尽可能和它们的表示相独立。尽管Scheme的实现可以使用不同的数字表示方法,但这些对于偶尔编些简单程序的程序员来说不应该是明显可见的。
3.2. 精确性(Exactness)
区分一个已知的精确等于一个数字的数字对象和那些在计算过程中有近似和误差的数字对象是有用的。比如,数据结构的索引操作可能需要精确地了解索引,符号代数系统中的多项式系数也应如此。另一方面,测量的结果在本质上就是不精确的,无理数可以被近似地表示为有理数,这也是不精确的近似。为了在需要精确数的地方使用非精确数,Scheme显式区分精确(exact)和非精确(inexact)数。这种区分和类型的划分是正交的(orthogonal)关系。
如果一个数值被写作精确的常量,或是完全通过精确运算从精确数得出,它就是精确的。一个精确的数字对象明显地与一个数学上的数字相一致。
同样地,如果一个数值被写作非精确的常量,或者是由非精确的成分得出的,或者是由非精确的运算得出的,它就是非精确的。也就是说,非精确性是数值的一种可传染的特性。
精确算术在下面的场景是可靠的:一个精确数对象被传递到11.7.1节描述的任意一个算术过程,并返回一个精确数对象,这个结果是数学上正确的。然而在涉及到非精确数的计算的时候,这通常是不正确的,这时因为像浮点算法的近似方法可能被使用,但是,让结果尽可能接近数学上的理想结果是每个实现的职责。
3.3. 定长数和浮点数
一个定长数是一个精确的整数对象,这个整数对象在精确的整数对象的一个特定的实现相关的子范围(subrange)。(库的第11.2小节描绘了一个计算定长数的库。)同样地,每个实现应当指定一个非精确实数对象的子集作为浮点数,并将特定的外部表示转换成浮点数。(库的第11.3小节描绘了一个计算浮点数的库。)注意,这并不意味着实现必须使用浮点表示。
3.4. 实现要求
Scheme的实现必须支持3.1节给出的子类型的整个塔的数字对象。此外,实现必须支持几乎无限(Practically unlimited)大小和精度的精确整数对象和精确有理数对象,并实现特定的过程(在11.7.1节列出),当给它们精确参数的时候这些过程总是返回精确结果。(“几乎无限”意味着这些数字的大小和精度应当仅受可用内存大小的限制。)
实现可以只支持任意类型非精确数字对象的一个有限的值域(range),但需要遵从本节的要求。比如,一个实现可以限制非精确实数对象的值域(且因此限制非精确整数和有理数对象的值域)在浮点格式的动态值域内。此外,在使用这种值域限制的实现中,非精确整数对象和有理数之间的差异很可能会很大。
一个实现可以为非精确数字使用浮点或其它近似表示方法。本报告推荐但不要求实现遵从IEEE的浮点格式标准,使用其他表示方法的实现应当在精度上达到或超过这些浮点标准15。
特别地,使用浮点数表示法的Scheme实现必须遵循以下规则:浮点数结果的表示精度必须达到或超过参与该运算的任意非精确参数的表示精度。只要有可能,像sqrt
这样潜在的非精确操作当传递一个精确的参数时,应该返回一个精确的结果(比如精确数4的平方根应当是精确的2)。可是,这不是必须的。另一方面,如果参数是精确数的运算会产生非精确的结果(如通过sqrt),且该结果被表示为浮点数,那么就必须使用当前可用的精度最高的浮点数格式;不过,如果该结果是用其他形式表示的,那么该表示方法在精度上就必须达到或超过当前可用的精度最高的浮点数格式。
避免使用量级或有效数字大到实现无法表示的非精确数是程序员的责任。
3.5. 无穷大(Infinities)和非数(NaNs)
一些Scheme实现,尤其是那些遵从IEEE浮点格式标准的实现区别叫做正无穷大,负无穷大和非数的特殊数字对象。
正无穷大被认为是一个非精确的实数(但不是有理数)对象,它表示大于所以有理数对象表示的数字的一个模糊的数字。负无穷大被认为是一个非精确的实数(但不是有理数)对象,它表示小于所以有理数对象表示的数字的一个模糊的数字。
一个非数被认为是一个非精确数(但不是一个实数)对象,它是如此不确定以至于它可以表示任何数,包括正负无穷大,且甚至可能大于正无穷大或小于负无穷大。
3.6. 可区别的-0.0
一些Scheme实现,尤其是那些遵从IEEE浮点格式标准的实现区别数字对象0.0和-0.0。也就是说,正的和负的非精确的零。本报告有时会指定在这些数字对象上的特定算术操作的行为。这些说明会被写作“如果-0.0的话是不一样的”或“实现区分-0.0”。