函数 returns 列表但在 LISP 中打印出 NIL
Function returns list but prints out NIL in LISP
我正在一个字符一个字符地读取一个文件,并构建一个由单词字母列表组成的列表。我这样做了,但是当涉及到测试时,它打印出 NIL。当我打印列表时,在测试功能之外,它打印得很好。这里有什么问题? LET关键字还有其他含义吗?
这是我的阅读功能:
(defun read-and-parse (filename)
(with-open-file (s filename)
(let (words)
(let (letter)
(loop for c = (read-char s nil)
while c
do(when (char/= c #\Space)
(if (char/= c #\Newline) (push c letter)))
do(when (or (char= c #\Space) (char= c #\Newline) )
(push (reverse letter) words)
(setf letter '())))
(reverse words)
))))
这是测试函数:
(defun test_on_test_data ()
(let (doc (read-and-parse "document2.txt"))
(print doc)
))
这是输入文本:
hello
this is a test
您没有正确使用 let
。语法是:
(let ((var1 val1)
(var2 val2)
...)
body)
如果变量的初始值为NIL
,可以将(varN nil)
简写为varN
.
您写道:
(let (doc
(read-and-parse "document2.txt"))
(print doc))
综合以上,这是使用缩写,相当于:
(let ((doc nil)
(read-and-parse "document2.txt"))
(print doc))
现在您可以看到这将 doc
绑定到 NIL
,并将变量 read-and-parse
绑定到 "document2.txt"
。它从不调用函数。正确的语法是:
(let ((doc (read-and-parse "document2.txt")))
(print doc))
Barmar 的回答是正确的。有趣的是,这是 read-and-parse
的一个版本,它可能更惯用地使用 loop
,并且还抽象出 'is the character white' 的决定,因为这在作为标准字符集的便携式 CL 非常差(例如没有制表符!)。我确定通过 Quicklisp 可以使用一些库,它比下面的更好地处理这个问题。
我认为这相当可读:有一个收集单词的外循环,以及一个将字符收集成单词的内循环,跳过空格直到找到下一个单词。两者都使用 loop
的 collect
功能来收集转发列表。另一方面,每次使用 loop
时我都感觉有点糟糕(我知道还有其他选择)。
默认情况下,它会将单词收集为字符列表:如果您告诉它,它会将它们收集为字符串。
(defun char-white-p (c)
;; Is a character white? The fallback for this is horrid, since
;; tab &c are not a standard characters. There must be a portability
;; library with a function which does this.
#+LispWorks (lw:whitespace-char-p c)
#+CCL (ccl:whitespacep c) ;?
#-(or LispWorks CCL)
(member char (load-time-value
(mapcan (lambda (n)
(let ((c (name-char n)))
(and c (list c))))
'("Space" "Newline" "Page" "Tab" "Return" "Linefeed"
;; and I am not sure about the following, but, well
"Backspace" "Rubout")))))
(defun read-and-parse (filename &key (as-strings nil))
"Parse a file into a list of words, splitting on whitespace.
By default the words are returned as lists of characters. If
AS-STRINGS is T then they are coerced to strings"
(with-open-file (s filename)
(loop for maybe-word = (loop with collecting = nil
for c = (read-char s nil)
;; carry on until we hit EOF, or we
;; hit whitespace while collecting a
;; word
until (or (not c) ;EOF
(and collecting (char-white-p c)))
;; if we're not collecting and we see
;; a non-white character, then we're
;; now collecting
when (and (not collecting) (not (char-white-p c)))
do (setf collecting t)
when collecting
collect c)
while (not (null maybe-word))
collect (if as-strings
(coerce maybe-word 'string)
maybe-word))))
我正在一个字符一个字符地读取一个文件,并构建一个由单词字母列表组成的列表。我这样做了,但是当涉及到测试时,它打印出 NIL。当我打印列表时,在测试功能之外,它打印得很好。这里有什么问题? LET关键字还有其他含义吗?
这是我的阅读功能:
(defun read-and-parse (filename)
(with-open-file (s filename)
(let (words)
(let (letter)
(loop for c = (read-char s nil)
while c
do(when (char/= c #\Space)
(if (char/= c #\Newline) (push c letter)))
do(when (or (char= c #\Space) (char= c #\Newline) )
(push (reverse letter) words)
(setf letter '())))
(reverse words)
))))
这是测试函数:
(defun test_on_test_data ()
(let (doc (read-and-parse "document2.txt"))
(print doc)
))
这是输入文本:
hello
this is a test
您没有正确使用 let
。语法是:
(let ((var1 val1)
(var2 val2)
...)
body)
如果变量的初始值为NIL
,可以将(varN nil)
简写为varN
.
您写道:
(let (doc
(read-and-parse "document2.txt"))
(print doc))
综合以上,这是使用缩写,相当于:
(let ((doc nil)
(read-and-parse "document2.txt"))
(print doc))
现在您可以看到这将 doc
绑定到 NIL
,并将变量 read-and-parse
绑定到 "document2.txt"
。它从不调用函数。正确的语法是:
(let ((doc (read-and-parse "document2.txt")))
(print doc))
Barmar 的回答是正确的。有趣的是,这是 read-and-parse
的一个版本,它可能更惯用地使用 loop
,并且还抽象出 'is the character white' 的决定,因为这在作为标准字符集的便携式 CL 非常差(例如没有制表符!)。我确定通过 Quicklisp 可以使用一些库,它比下面的更好地处理这个问题。
我认为这相当可读:有一个收集单词的外循环,以及一个将字符收集成单词的内循环,跳过空格直到找到下一个单词。两者都使用 loop
的 collect
功能来收集转发列表。另一方面,每次使用 loop
时我都感觉有点糟糕(我知道还有其他选择)。
默认情况下,它会将单词收集为字符列表:如果您告诉它,它会将它们收集为字符串。
(defun char-white-p (c)
;; Is a character white? The fallback for this is horrid, since
;; tab &c are not a standard characters. There must be a portability
;; library with a function which does this.
#+LispWorks (lw:whitespace-char-p c)
#+CCL (ccl:whitespacep c) ;?
#-(or LispWorks CCL)
(member char (load-time-value
(mapcan (lambda (n)
(let ((c (name-char n)))
(and c (list c))))
'("Space" "Newline" "Page" "Tab" "Return" "Linefeed"
;; and I am not sure about the following, but, well
"Backspace" "Rubout")))))
(defun read-and-parse (filename &key (as-strings nil))
"Parse a file into a list of words, splitting on whitespace.
By default the words are returned as lists of characters. If
AS-STRINGS is T then they are coerced to strings"
(with-open-file (s filename)
(loop for maybe-word = (loop with collecting = nil
for c = (read-char s nil)
;; carry on until we hit EOF, or we
;; hit whitespace while collecting a
;; word
until (or (not c) ;EOF
(and collecting (char-white-p c)))
;; if we're not collecting and we see
;; a non-white character, then we're
;; now collecting
when (and (not collecting) (not (char-white-p c)))
do (setf collecting t)
when collecting
collect c)
while (not (null maybe-word))
collect (if as-strings
(coerce maybe-word 'string)
maybe-word))))