Racket读文件出现'(#<void>...)输出的原因及for循环差异
Racket遍历输出时末尾出现void列表的原因
末尾'(#<void> #<void> ...)的产生逻辑
- 根因是
map函数的使用场景不对:Racket中map是列表转换函数,它会遍历传入的列表,对每个元素执行传入的处理函数,最后把所有处理函数的返回值收集成一个新列表作为整个map表达式的返回值,设计目标是生成转换后的新列表,不是用来执行打印这类只需要副作用的操作。 - 传入
map的处理函数是display,这个函数只负责把内容打印到控制台,没有有效业务返回值,执行后固定返回Racket里表示“无有效值”的#<void>。 - 目标文件被
file->lines读取后一共得到7个元素:4行正文加3行段间空行,所以map执行完会收集到7个#<void>,拼成一个列表作为do-sth-to-each-line函数的返回值。 - Racket的REPL(交互运行环境)会自动打印所有顶层表达式的返回值,只有当返回值是单个
#<void>时才会默认隐藏不打印。这个返回值是包含多个void的列表,不属于被隐藏的情况,所以就被直接输出到控制台,出现在打印文本的末尾。
为什么for循环不会产生这类额外输出
- Racket中基础的
for遍历形式本身就是为副作用遍历设计的,它不会收集循环体每次执行的返回值,整个for表达式执行完成后,自身的返回值就是单个#<void>。 - 按照REPL的默认规则,单个
#<void>类型的返回值不会被打印,所以看不到额外的输出内容。
修正方法
如果要遍历列表执行打印这类纯副作用操作,不要用map,换成专门做副作用遍历的for-each即可,它的参数形式和map一致,但不会收集处理函数的返回值,执行完自身返回#<void>,就不会产生多余的列表输出:
(define (do-sth-to-each-line fn-name) (define f "../file-to-be-read.short") (define content (file->lines f)) (for-each fn-name content))
内容的提问来源于stack exchange,提问作者John Smith
相关产品推荐
相关产品推荐

