函数返回列表,但在LISP中打印出NIL
我正在逐字符读取一个文件,并构建一个由单词字母组成的列表。我这样做了,但当涉及到测试它打印出零。在测试函数之外,当我打印列表时,它打印得很好。这里有什么问题?LET关键字还有其他含义吗 这是我的阅读功能:函数返回列表,但在LISP中打印出NIL,lisp,common-lisp,file-read,clisp,Lisp,Common Lisp,File Read,Clisp,我正在逐字符读取一个文件,并构建一个由单词字母组成的列表。我这样做了,但当涉及到测试它打印出零。在测试函数之外,当我打印列表时,它打印得很好。这里有什么问题?LET关键字还有其他含义吗 这是我的阅读功能: (defun read-and-parse (filename) (with-open-file (s filename) (let (words) (let (letter) (loop for c = (read-char s nil)
(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)
(let ((doc (read-and-parse "document2.txt")))
(print doc))
如果变量的初始值为NIL,则可以将varN NIL缩写为just varN
你写道:
(let (doc
(read-and-parse "document2.txt"))
(print doc))
基于上述情况,这是使用缩写,相当于:
(let ((doc nil)
(read-and-parse "document2.txt"))
(print doc))
现在您可以看到,这将doc绑定到NIL,并将变量read和parse绑定到document2.txt。它从不调用函数。正确的语法是:
(let ((var1 val1)
(var2 val2)
...)
body)
(let ((doc (read-and-parse "document2.txt")))
(print doc))
你没有正确使用let。语法是:
(let ((var1 val1)
(var2 val2)
...)
body)
(let ((doc (read-and-parse "document2.txt")))
(print doc))
如果变量的初始值为NIL,则可以将varN NIL缩写为just varN
你写道:
(let (doc
(read-and-parse "document2.txt"))
(print doc))
基于上述情况,这是使用缩写,相当于:
(let ((doc nil)
(read-and-parse "document2.txt"))
(print doc))
现在您可以看到,这将doc绑定到NIL,并将变量read和parse绑定到document2.txt。它从不调用函数。正确的语法是:
(let ((var1 val1)
(var2 val2)
...)
body)
(let ((doc (read-and-parse "document2.txt")))
(print doc))
巴尔马的答案是正确的。有趣的是,这里有一个版本的read and parse,它可能更习惯于使用循环,并且还抽象出了“是白色字符”的决定,因为这在portable CL中确实是不可能的,因为标准字符库非常糟糕,例如,没有制表符!。我相信有一些图书馆可以通过它来更好地处理这个问题 我认为这是相当可读的:有一个外循环收集单词,还有一个内循环收集单词中的字符,跳过空格直到找到下一个单词。两者都使用循环的收集功能来向前收集列表。另一方面,每次我使用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))))
巴尔马的答案是正确的。有趣的是,这里有一个版本的read and parse,它可能更习惯于使用循环,并且还抽象出了“是白色字符”的决定,因为这在portable CL中确实是不可能的,因为标准字符库非常糟糕,例如,没有制表符!。我相信有一些图书馆可以通过它来更好地处理这个问题 我认为这是相当可读的:有一个外循环收集单词,还有一个内循环收集单词中的字符,跳过空格直到找到下一个单词。两者都使用循环的收集功能来向前收集列表。另一方面,每次我使用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))))
仅供参考,您可以在一个LET中绑定多个变量:LET words letter…仅供参考,您可以在一个LET中绑定多个变量:LET words letter…顺便说一句,显示Tab是很奇怪的,但标准语法没有提到它。我认为在实践中,即使严格来说不是便携的,带t的peek-char也可以相对较好地工作。@coredump:peek-char技巧很聪明:谢谢!它并没有完全取代对“is character white”谓词的需要,但在许多情况下(包括本例),它确实避免了这种情况,尽管我没有更改代码。我只记得一半,现在我发现像tab这样的东西是半标准的:它们可能不存在,但如果它们存在,就必须被称为半标准。您可以通过名称字符选项卡检查它们是否存在。我已经增强了我的char-white-p来做这件事。顺便说一句,显示Tab很奇怪,但是标准语法没有提到它。我认为在实践中,即使严格来说不是便携的,带t的peek-char也可以相对较好地工作。@coredump:peek-char技巧很聪明:谢谢!它并没有完全取代对“is character white”谓词的需要,但在许多情况下(包括本例),它确实避免了这种情况,尽管我没有更改代码。我只记得一半,现在我发现像tab这样的东西是半标准的:它们可能不存在,但如果它们存在,就必须被称为半标准。您可以通过名称字符选项卡检查它们是否存在。我已经增强了我的char-white-p来做那件事。