I'm new to Lisp and have a quite basic question.
I'm working with a list containing lists.
(defvar *stationen* nil)
(defun make-station (name uri)
(list :name name :uri uri))
(defun save-db ()
(with-open-file (out "list.txt"
:direction :output
:if-exists :supersede)
(with-standard-io-syntax
(princ *stationen* out))))
(defun load-db ()
(with-open-file (in "list.txt")
(with-standard-io-syntax
(setf *stationen* (READ in)))))
(load-db)
The data contains an uri http://www..... Well, I get the following error, when I try to read that list:
The name "HTTP" does not designate any package.
[Condition of type SB-KERNEL:SIMPLE-PACKAGE-ERROR]
I can guess why this happens (Lisp is trying to interpret "http" as a package, right?). But how can I save my uri to the file and read it again, without Lisp throwing this error?
Alternatives:
Just write it as a string.
use READ-CHAR, READ-LINE or READ-SEQUENCE
advanced: write and read using a custom reader macro
Btw., please post formatted Lisp code.
Alternatively, you can use PRINT instead of PRINC to write out the URL.
Related
I'm attempting to make a macro that will take an input stream and do something different depending on the contents of the first line read, and then read further input. I'm having trouble just having a macro that will take an input stream and read some values from it.
A contrived example:
(defmacro read-and-print (&optional in)
`(print
,(if (string= (read-line in) "greet")
`(concatenate 'string "hello" (read-line ,in))
`(read-line ,in))))
(with-input-from-string (in "greet
bob") (read-and-print in))
but even that is producing the following error
There is no applicable method for the generic function
#<STANDARD-GENERIC-FUNCTION SB-GRAY:STREAM-READ-LINE (1)>
when called with arguments
(IN).
[Condition of type SB-INT:COMPILED-PROGRAM-ERROR]
The thing that's really baffling me is even changing the function to take a string for the first line isn't working:
(defmacro read-and-print (command &optional in)
`(print
,(if (string= command "greet")
`(concatenate 'string "hello " (read-line ,in))
`(read-line ,in))))
(with-input-from-string (in "greet
bob")
(read-and-print (read-string in) in))
This gives me
The value
(READ-LINE IN)
is not of type
(OR (VECTOR CHARACTER) (VECTOR NIL) BASE-STRING SYMBOL CHARACTER)
when binding SB-IMPL::STRING1
[Condition of type SB-INT:COMPILED-PROGRAM-ERROR]
While this executes completely fine:
(with-input-from-string (in "greet
bob")
(read-and-print "greet" in))
Is there something special about the with-input-from-string macro that I'm missing? I suspect I'm missing something very obvious about macros, but googling has gotten me nowhere.
What you asked
Macros are a code generation tool.
They do not evaluate their arguments.
Your with-input-from-string example works because strings are self-evaluating. If you quite the string literal, you will get an error.
What you should have asked
You do not need a macro here. Use a function instead.
When deciding between a function and a macro, you need to ask yourself:
Am I defining a new syntax?
Does the code generate more code?
Unless you understand the questions and answer yes, you should be using functions.
See also How does Lisp let you redefine the language itself?
Your macro:
(defmacro read-and-print (&optional in)
`(print
,(if (string= (read-line in) "greet")
`(concatenate 'string "hello" (read-line ,in))
`(read-line ,in))))
But ,(if ... in ...) makes no sense, since the value of in typically isn't a stream at macro expansion time, but code (a symbol, an expression, ...). Since your code is not executing and the macro sees the source (and not the values of something which has not been executed yet) you can't do that. You can't also not usefully repair that: It's just the wrong approach. Use a function instead.
Use a function:
CL-USER 17 > (defun read-and-print (&optional in)
(if (string= (read-line in) "greet")
(concatenate 'string "hello" (read-line in))
(read-line in)))
READ-AND-PRINT
CL-USER 18 > (with-input-from-string (in "greet
foo
bar")
(read-and-print in))
"hellofoo"
Using a macro
You still can write it as a macro, but then you need to generate the code so that it runs at runtime, and not at macro-expansion time:
(defmacro read-and-print (&optional in)
`(print
(if (string= (read-line ,in) "greet")
(concatenate 'string "hello" (read-line ,in))
(read-line ,in))))
Note: one would actually might want to handle that in is not evaluated multiple times.
This macro would give you the advantage that the code is inlined.
This macro would give you the disadvantage that the code is inlined.
The function above gives you the advantage that the code typically is not inlined.
The function above gives you the advantage that the code can optionally be inlined, by telling the compiler to do so with an inline declaration.
I'm fairly new to Lisp, and I've run into a printing issue. I have one function which does printing to the standard output (among other things). I want to then run this function through another function where it still runs the same but instead nothing gets printed to the standard output.
Here is a simple example of what I mean. I have the following two functions described:
(defun does-printing()
(print "This goes to standard output."))
(defun run-other-function (function)
(funcall function)
(values))
Here's a dribble of what happens when I run this,
;; Dribble of #<IO TERMINAL-STREAM> started on 2014-10-05 21:49:49.
#<OUTPUT BUFFERED FILE-STREAM CHARACTER #P"example.out">
[7]> (run-other-function #'does-printing)
"This goes to standard output."
[8]> (dribble)
;; Dribble of #<IO TERMINAL-STREAM> finished on 2014-10-05 21:50:09.
Note that the printing function still prints to the standard output. It'd like to be able to suppress this printing somehow when running does-printing through run-other-function. I have tried many different variations of phrasing of my problem when searching for solutions, but nothing is getting at what I would like to do.
The simplest solution is to create an empty broadcast stream.
(with-open-stream (*standard-output* (make-broadcast-stream))
(call-some-function-1)
...
(call-some-function-n))
If a broadcast stream has no component stream all output will be discarded. Above binds the *standard-output* to such a stream. This does not cons up any data and it is portable.
You can just redirect your standard-output to some place. For example into /dev/null if you have one in your operating system. It looks like very idiomatic UNIX-way output suppressing.
Note, that you shouldn't set it to NIL, because print will signal type error in this case.
(defun does-printing()
(print "This goes to standard output."))
(defun run-other-function (function)
(with-open-file (*standard-output*
"/dev/null"
:direction :output
:if-exists :supersede)
(funcall function)
(values)))
CL-USER> (run-other-function #'does-printing)
; No value
Other option (and it may be better) is to use with-output-to-string, so you can capture this output value or just ignore it. Is think it's better, because why to do IO if we don't need it, and also it must work on any OS.
(defun run-other-function (function)
(with-output-to-string (*standard-output*
(make-array '(0)
:element-type 'base-char
:fill-pointer 0 :adjustable t))
(funcall function)
(values)))
If you doing it a lot, you can wrap it into macro or even function, to use in place of funcall.
(defun does-printing()
(print "This goes to standard output.")
"My result")
(defun funcall-with-no-output (fn)
(with-output-to-string (*standard-output*
(make-array '(0)
:element-type 'base-char
:fill-pointer 0 :adjustable t))
(funcall fn)))
CL-USER> (funcall-with-no-output #'does-printing)
"My result"
But i think macro will be more general and idiomatic for this case (may be I'm wrong).
(defmacro with-suppressed-output (&body body)
`(with-output-to-string (*standard-output*
(make-array '(0)
:element-type 'base-char
:fill-pointer 0 :adjustable t))
,#body))
So you can call many forms in with-suppressed-output.
there is a bunch of interactive functions which take string input as an argument:
(defun zb/run-cmd-X (arg1 argN)
(interactive "Marg1: Marg2: ")
;;; some logic
How to make each of such functions zb/run-cmd-1..zb/run-cmd-N have own independent history of input arguments arg1...argN? And it would be perfect if this history was persistent between Emacs launches (ideally somewhere in an external file; for sync).
Is there any ready solution for this?
Thanks
Basically you want to read the documentation for read-from-minibuffer and completing-read regarding the HIST argument which each of those functions accepts. There are other functions with history support of course, but these two are the standard/basic options.
Persistence is provided for by the savehist library, which writes to the file in savehist-file (which by default is ~/.emacs.d/history, but the old ~/.emacs-history will be used instead if that file exists -- in which case you might want to rename it to the modern preferred path).
Here's an example:
(defvar my-ssh-history nil)
(eval-after-load "savehist"
'(add-to-list 'savehist-additional-variables 'my-ssh-history))
(defun my-ssh (args)
"Connect to a remote host by SSH."
(interactive
(list (read-from-minibuffer "ssh " nil nil nil 'my-ssh-history)))
(let* ((switches (split-string-and-unquote args))
(name (concat "ssh " args))
(termbuf (apply 'make-term name "ssh" nil switches)))
(set-buffer termbuf)
(term-mode)
(term-char-mode)
(switch-to-buffer termbuf)))
(savehist-mode 1)
I'm porting some of my python scripts to Common Lisp. I need to get list of files in some directory and print each file's content by lines.
This code shows me all filenames. But lines are printed only for last file. Why?
Also, what is the best way ti iterate by file lines?
Thanks.
(dolist (file (directory (make-pathname :name :wild
:type :wild
:defaults "path\\to\\files\\")))
(print file)
(with-open-file (stream file)
(do ((line (read-line stream) (read-line stream)))
(nil t)
(print line))))
I would propose to write a function which prints a file given a pathname and a stream.
You iterate with DO. That's okay, but I would use something like LOOP which allows slightly easier to read code.
Your DO is an endless loop. You might want to end the loop when the EOF is reached.
READ-LINE generates an error when it reads past the end of the file. Thus your code signals an error on the end of the first file. This error causes your code to only print the first file.
You need to call READ-LINE such a way that you test for EOF and end the iteration then. See the arguments to READ-LINE. Alternatively you can catch the EOF error, but the other solution is slightly easier.
This seems to work for me:
(dolist (file (directory (make-pathname :name :wild
:defaults "/tmp/lt/files/")))
(print file)
(with-open-file (stream file)
(do ((line (read-line stream nil) (read-line stream nil)))
((null line))
(print line))))
I'm learning CL, and I have minimal experience in other languages. Could someone explain to me in layman terms what this means, especially what "out" here represents, and how it all fits together:
(defun save-db (filename)
(with-open-file (out filename
:direction :output
:if-exists :supersede)
(with-standard-io-syntax
(print *db* out))))
Mostly, the bit I don't understand is "out", but an explanation of the whole thing would be nice.
Thanks
out is the stream variable bound to the open file.
with-open-file guarantees that the file is open inside the scope, and closed
outside the scope, no matter how you exit.
As an addition to ddyer, you can also use MACROEXPAND or MACROEXPAND-1 to see what WITH-OPEN-FILE does:
(macroexpand '(with-open-file (out filename
:direction :output
:if-exists :supersede)
(with-standard-io-syntax
(print *db* out))))
tells us
(LET ((OUT (OPEN FILENAME :DIRECTION :OUTPUT :IF-EXISTS :SUPERSEDE)) (#:G748 T))
(UNWIND-PROTECT
(MULTIPLE-VALUE-PROG1 (PROGN (WITH-STANDARD-IO-SYNTAX (PRINT *DB* OUT)))
(SETQ #:G748 NIL))
(WHEN OUT (CLOSE OUT :ABORT #:G748))))
We can see that we open the file called filename and assign that open file stream to out , and do something. Should something bad happen, UNWIND-PROTECT will CLOSE the stream, should it be non-nil.
The #:G748 variable is a GENSYMed symbol (so it's a fresh, uninterned, symbol). If nothing goes wrong writing the file, we set #:G748 to nil.
Thus, when we CLOSE the stream, if something went wrong #:G748 will be T, so CLOSE will attempt to clean up any side effects of having created the stream.