Types 返回类型是什么(显示8)?/什么是空值表达式?
在方案的实施中,表达式Types 返回类型是什么(显示8)?/什么是空值表达式?,types,scheme,lisp,kawa,Types,Scheme,Lisp,Kawa,在方案的实施中,表达式 (空?()) 显然是回报 #t 但是如果我打字 (null?(显示8)) 在解释器中,输出是 8#f 因此,似乎display是一个确实有副作用的函数,即打印值和某种非空返回值。嗯。可能(显示8)返回8?毕竟,8和(显示8)都会在交互式口译员中显示8 所以我打了进去 (=8(显示8)) 反应是 /dev/stdin:5:6: warning - void-valued expression where value is needed java.lang.NullPoint
(空?())
显然是回报
#t
但是如果我打字
(null?(显示8))
在解释器中,输出是
8#f
因此,似乎display
是一个确实有副作用的函数,即打印值和某种非空返回值。嗯。可能(显示8)
返回8
?毕竟,8
和(显示8)
都会在交互式口译员中显示8
所以我打了进去
(=8(显示8))
反应是
/dev/stdin:5:6: warning - void-valued expression where value is needed
java.lang.NullPointerException
at gnu.math.IntNum.compare(IntNum.java:181)
at atInteractiveLevel-5.run(stdin:5)
at gnu.expr.ModuleExp.evalModule2(ModuleExp.java:293)
at gnu.expr.ModuleExp.evalModule(ModuleExp.java:212)
at kawa.Shell.run(Shell.java:283)
at kawa.Shell.run(Shell.java:196)
at kawa.Shell.run(Shell.java:183)
at kawa.repl.processArgs(repl.java:714)
at kawa.repl.main(repl.java:820)
8
所以,(显示8)
不是null,而是“void value”?这是什么意思?我可以像在Scheme中检查空值一样检查空值吗
另外,为什么
8
出现在错误消息之后?您的推断是正确的,即显示
是一个返回值的函数(除了具有打印到当前输出端口的副作用)。然而,display
的这一特定调用返回的值是read-eval-print循环在计算表达式时自行选择不打印的值
川有一些特殊的功能;其中之一就是#!void
,相当于计算表达式(值)
(表示“完全没有值”)的结果。如果您得到值#!void
从读取评估打印循环中,它不会打印:
#|kawa:1|# #!void
#|kawa:2|# (values)
#|kawa:3|#
这是因为Kawa的read-eval-print循环用于打印表达式计算结果的值,而display
在给定#时将选择不打印任何内容!作废
在比较
8
和(display 8)
行为的具体实验中,实际发生的情况有着至关重要的区别。当您向解释器提供任何输入时,它:
8
时,打印将在步骤3中进行。当您输入(显示8)
时,打印在步骤2中进行,然后步骤3中的打印不会打印任何内容(因为(显示8)
返回的值是解释器选择不打印的值)
观察这种区别的一种方法是:根据兴趣表达构建一个列表
#|kawa:1|# (list (display 7) 8 (display 9))
/dev/stdin:1:7: warning - void-valued expression where value is needed
/dev/stdin:1:21: warning - void-valued expression where value is needed
7 9 (#!null 8 #!null)
#|kawa:2|#
这里我们看到,在求值步骤中,解释器先显示7
,然后显示9
,然后构建了一个包含三个元素的列表:#!空
,8
,然后是#!再次为空
Kawa解释器还警告我们,我们的代码似乎有问题:Kawa解释器在读取和编译步骤(发生在评估和打印步骤之前)期间足够聪明,可以分析代码是否存在潜在问题。在这里,它表示“调用显示的结果
并不意味着它是一个正常值”(与数字或字符串相比)
因此,这就解释了为什么会看到错误消息(因为它认为调用display
的结果是无效值),并且它知道对这些值的处理可能与用户的期望不符。(它还解释了为什么在错误消息之后打印示例中的数字8
:因为错误消息是在“读取”步骤中生成的,但显示是在“评估”步骤中进行的,如上所述
为什么我要说“这些值的处理可能不符合用户的期望”?好吧,从上面我们运行(列表(显示7)8(显示9))
的实验中,您可能会推断评估(显示7)
的结果是#!null
。但事实并非如此
在Kawa中,#!null
是一个特殊常数,它不同于#!void
。出于某种原因,Kawa解释器决定,当您将(display 7)
插入列表构造表达式(或者更一般地说,我认为任何需要非void值的上下文)时,它可以丢弃的返回值(显示7)
并将#!null
插入其中
为什么我要这么说呢?还有另一种方法可以在Scheme中打印值:您可以使用写入
过程。显示
过程通常用于“人类(或最终用户)可读”输出,而write
过程旨在显示更多关于给定数据结构的信息(如果可用)。例如:
#|kawa:1|# (display "Hello World")
Hello World
#|kawa:2|# (write "Hello World")
"Hello World"
#|kawa:3|#
在上面的例子中,display
丢弃了我有一个字符串的信息,只关注该字符串的内容,而write
告诉我“我们这里有一个字符串,它有11个字符长。下面是它的内容。”
那么,如果我们编写调用display
的结果会发生什么呢
#|kawa:1|# (write (display 8))
8#!void
#|kawa:2|#
在这里,我们没有从读取和编译步骤得到任何警告。相反,它保留了(display 8)
的值。因此它首先计算(display 8)
(将8
打印到输出中),然后将从(#void)
生成的值输入到写入调用中
(我不会说这是有史以来最清晰的语义。但我的推断是,Kawa's告诉我们,编译器被允许插入一个#!null
来代替#!void
)你的推断是正确的,即display
是一个返回值的函数(除了具有打印到当前输出端口的副作用外)。但是,此特定调用显示返回的值是read eval print loop simp返回的值
(list (display 8)) ; ==> (#!void) (and prints 8 on the terminal as side effect)