lisp read command works wrong for sbcl [duplicate] - lisp

This question already has an answer here:
Lisp format and force-output
(1 answer)
Closed 5 years ago.
I schlocked this example of a read function from (Land of Lisp)in to my sbcl repl and it does not show the prompt: "Please type your name" until after I type in a response. then it shows the response. I know this is wrong what gives?
(defun say-hello ()
(princ "Please type your name:") (let ((name (read-line)))
(princ "Nice to meet you, ")
(princ name)))
I have tried other example write functions and have tried write instead of princ. No luck
here's the cut and paste from my repl:
* (defun say-hello ()
(princ "Please type your name:") (let ((name (read-line)))
(princ "Nice to meet you, ")
(princ name)))
WARNING: redefining COMMON-LISP-USER::SAY-HELLO in DEFUN
SAY-HELLO
* (say-hello)
gregg
Please type your name:Nice to meet you, gregg
"gregg"

You should call finish-output after the first princ, to ensure that the output has actually been flushed.

Related

Display value of a global variable in a message

I am having what I believe to be a syntax issue in Common Lisp. I have a global variable, *LOC*, I can set its initial value and change it. My issue isn't with the variable, it works fine, it is when I try to display a message with its value.
For example, When i use an if statement and say something like:
(if ( UPSTAIRSP *LOC*)
(progn (princ "I AM UPSTAIRS IN THE *LOC*"))
(progn (princ "I AM DOWNSTAIRS IN THE *LOC*"))
)
I will get:
I AM UPSTAIRS IN THE *LOC*
I'm pretty sure it is because my variable is in the quotations, but I don't know how else to express it.
First, you don't need to use progn if you only have a single expression in one of the IF branches.
Now, as you said, variables are not interpolated in strings.
For actual string interpolation, see this answer, but I think you should first try to learn a little more about the basics.
You could print things like so:
(if (upstairsp *LOC*)
(progn
(princ "I AM UPSTAIRS IN THE ")
(princ *LOC*))
(progn
(princ "I AM DOWNSTAIRS IN THE ")
(princ *LOC*)))
Generally, when you spot IF with PROGN, chances are that you need COND. Here this is not necessary because you print *LOC* in both branches and you can factor that outside of the conditional.
(progn
(if (upstairsp *LOC*)
(princ "I AM UPSTAIRS IN THE ")
(princ "I AM DOWNSTAIRS IN THE "))
(princ *LOC*))
But you should probably use FORMAT instead.
For example:
(if (upstairsp *LOC*)
(format t "I AM UPSTAIRS IN THE ~A" *LOC*)
(format t "I AM DOWNSTAIRS IN THE ~A" *LOC*))
In fact, FORMAT supports conditional directives.
Below, the return value of (upstairsp *LOC*), a boolean, is used in the ~:[...~;...~] directive to select which text to print:
(format t
"I AM ~:[DOWNSTAIRS~;UPSTAIRS~] IN THE ~A"
(upstairsp *LOC*)
*LOC*)
Have a look at A Few Format Recipes (Practical Common Lisp, Seibel) for more examples.
In Common Lisp you can compose string and values either for printing or for other purposes with the format operator:
(if (upstairsp *LOC*)
(format t "I AM UPSTAIRS IN THE ~a" *LOC*)
(format t "I AM DOWNSTAIRS IN THE ~a" *LOC*"))
The first parameter of format is a stream (or T for the standard output), to print the message on that stream, or NIL to produce a formatted string. You can find all the details in tha manual.

"Wrong type argument: stringp, cons" when calling apply function on concatenated lists

I wanted to write some functionality in Emacs which will allow me to run my favorite editor and file manager in directory where my current buffer file resides. I'm not familiar with Lisp so this code may be ugly, anyway:
(setq terminal-program "rxvt-unicode")
(defun buffer-dir-name ()
(file-name-directory buffer-file-name))
(defun terminal-option-buffer-dir ()
(let ((dir (format "'%s'" (buffer-dir-name))))
`("-cd" ,dir)))
(setq terminal-option-ranger '("-e" "ranger"))
(defun run-terminal ()
(interactive)
(start-process "terminal" nil terminal-program) (terminal-option-buffer-dir))
;; outdated, see below
(defun run-file-manager ()
(interactive)
(let ((args (append (terminal-option-buffer-dir) terminal-option-ranger)))
(message (type-of args)
(apply 'start-process "filemanager" nil terminal-program args))))
Function run-terminal works fine. But when I try to run run-file-manager I'm experiencing following error: Wrong type argument: stringp, cons. Why? Documentation says that return value of append function is a list, not cons.
After Drew response I saw that run-file-manager function has some trash left after my debugging. Now it looks as follow:
(defun run-file-manager ()
(interactive)
(let ((args (append (terminal-option-buffer-dir) terminal-option-ranger)))
(apply 'start-process "filemanager" nil terminal-program args)))
;; (apply 'start-process "filemanager" nil terminal-program '("-cd" "/opt/" "-e" "ranger"))))
Now I have an another issue. When I call this function it does nothing. But if first invocation of apply is commented and second one is uncommented it works as I expect: it runs ranger in terminal in /opt directory. Any ideas?
I solved my problem, which was slightly different from that in question title. Problem was that function terminal-option-buffer-dir was returning -cd option with valued starting with ' not / which is required by urxvt.
I debugged that by setting parameter BUFFER of start-process function to "*Messages*".
The error msg says that something in run-file-manager was expecting a string and got the symbol cons instead.
message expects a string as its first argument. But type-of returns a symbol. In this case, it returns the symbol cons.

how to update evaluation result comments of Emacs Lisp forms easilly

Say I have this code which shows usage examples of mapcar
(mapcar #'1+ (list 10 20 30)) ; ⇒ (11 21 31)
(mapcar (lambda (it)
(* 2 it))
(list 0 1 2 3))
;; ⇒ (0 2 4 6)
(require cl-lib)
(cl-mapcar #'+
'(1 2 3)
'(10 20 30))
;; ⇒ (11 22 33)
I may be keeping that code somewhere written so that I can use it on a tutorial or so that whenever I forget how mapcar works, I can quickly read the code.
Now suppose I want to update some of the examples in the code. For example, I may change (list 0 1 2 3) in the second example to some other list. Right after I change the example, the corresponding result comment is then outdated. The result comment need to be updated as well. So I evaluate the form, copy the result, and replace the old result in the comment with new result. Is there a package I can use to help me do that all easily and less tediously? This is a different problem than problems that the litable or ielm package solve because this is simply about updating existing example code.
Right now what I use is:
(defun my-insert-eval-last-sexp ()
(interactive)
(let ((beg (point)))
(let ((current-prefix-arg '(4)))
(call-interactively 'eval-last-sexp))
(goto-char beg)
(if (looking-back ")")
(insert " ; "))
(insert "⇒ ")
(move-end-of-line 1)))
which still isn't enough because it simply adds the result comment rather than updating an old one, and has a bug of odd stuff getting inserted when the form evaluates to a number:
(+ 1 2)
;; ⇒ 3 (#o3, #x3)
Well, I'm not sure I want to encourage this kind of thing ;-), but this will get you a little closer to what you are trying to do, IIUC:
(defun my-insert-eval-last-sexp ()
(interactive)
(let ((this-command 'eval-print-last-sexp))
(save-excursion (eval-last-sexp-1 t)))
(when (looking-back ")") (insert " ; "))
(insert "⇒ ")
(move-end-of-line 1))
You don't need to save point and then explicitly go back to it --- use save-excursion.
You don't need to bind the prefix arg and call the command interactively. Just call it (or its helper function) directly, passing the arg you want.
You need to tweak the behavior to prevent it from thinking this is the second occurrence of the command, which is what causes it to print the octal etc. number info. The let binding does that (but is an ugly little hack).
Respective thing your function does is implemented in org-mode, i.e. org-babel.
See in Info, Org Mode, 14 Working with source code

Why do some use #'(lambda instead of just (lanbda in Common Lisp? [duplicate]

This question already has answers here:
Why use #' with lambda?
(2 answers)
Closed 9 years ago.
Why do some use #'(lambda instead of just (lambda in Common Lisp? Are there performance benefits or something?
Because, as Peter Siebel and others explain, in CL, "the following LAMBDA expression: (lambda () 42) expands into the following when it occurs in a context where it evaluated: (function (lambda () 42))".
There is not performance benefits except few milliseconds of compile time vs few millisecods of read time :)
I think real reason is consistency. If one writes (mapcar #'myfunc ...) (not just (mapcar myfunc ...)), it is natural to write (mapcar #'(lambda ...) ...) too.

Reacting to a "wrong-type-argument"

So I'm starting to learn a bit of lisp/elisp to optimize my emacs environment, and I've started making a simple emacs library, the major roadblock is being able to tell if a parenthesis entered has a match or not. I've been looking through the emacs source (paren.el.gz) and realized I can use the function show-paren-function to determine if it is a match or not.
Here's what I've got so far:
(defun it-is-a-paren()
(interactive)
(insert ")")
(if (show-paren-function)
(message "%s" "it is a match")
(message "%s" "it is not")))
So this is pretty basic, and "it is a match" works as it should, but when it is supposed to throw "it is not", it doesn't, instead it gives me "Wrong type argument: integer-or-marker-p, t".
Is anyone familiar enough to advise use of a different function, or maybe I should be writing my own altogether instead of using show-paren-function. Or is there a way around this error (sort of like exception handling)?
The "exception handling"-like construct you're looking for is condition-case.
(defun its-a-paren()
(interactive)
(insert ")")
(condition-case ex
(if (show-paren-function)
(message "its a match")
(message "its not"))
(error (message "its not"))))
Edit: Looking into show-paren-function's code, it seems to me that this error is a bug as it comes from the expression (goto-char pos) where pos is t.
Anyways, show-paren-function uses scan-sexps to look for the matching paren. Adapting from the way it's done in show-paren-function, a simplified function for your case would be:
(defun its-a-paren()
(interactive)
(insert ")")
(condition-case ()
(progn
(scan-sexps (point) -1)
(message "It's a match"))
(error (message "It's not a match"))))
Using show-paren-function for this purpose is overkill (like giving your car to a garage a checking if the oil-level has changed, to determine if the car needed more oil) and doesn't work right, as you've noticed.
I'd recommend you try
(condition-case nil
(progn (forward-sexp -1)
(message "Moved to the matching opener"))
(scan-error (message "No matching opener")))