Display value of a global variable in a message - lisp

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.

Related

How to remove the brackets from this text

So I have been given the task by my tutor to make a small function that returns a description of your zodiac sign but I"m having problems with the final output of the sign description, the output is still in brackets and I don't know how to get them out.
(defparameter *month-signs* '((January Capricorn Aquarius 19 nil)
(February Aquarius Pisces 18 nil)
....)))
(defparameter *sign-traits* '((Capricorn (You are a goat be happy!))
....)))
(defun cookie (month-signs sign-traits)
(format t "Please input your month of birth followed by return, and then your day of birth.
e.g january <ret> 22 <ret> Thank You. ~%")
(let* ((month (read t));reads in month of birth
(day (read t));reads in day of birth
(month-assoc (assoc month month-signs)))
(cond
((>=(cadddr month-assoc)day);checks if your sign is the first part of the month
(format t "You are ~D~%" (cadr month-assoc));if it is, prints your sign and signs description
(format t "Your sign description is: ~D~%" (cadr(assoc(cadr month-assoc) sign-traits))))
((< (cadddr month-assoc)22);same as above but for the other sign
(format t "You are ~D~%" (caddr month-assoc))
(format t "Your sign description is: ~D~%" (cadr(assoc(caddr month-assoc) sign-traits)))))))
It all works dandy except this bit "(cadr(assoc(caddr month-assoc) sign-traits)" which returns what I want but in brackets and all caps.
CL-USER> (cookie *month-signs* *sign-traits*)
Please input your month of birth followed by return, and then your day of birth.
e.g january <ret> 22 <ret> Thank You.
january
12
You are CAPRICORN
Your sign description is: (YOU ARE A GOAT BE HAPPY)
I'm really struggling to work out what I need to get rid of the (YOU ARE A GOAT BE HAPPY) on the last bit, I'd like it to just print "Your sign description is: You are a goat be happy." it's probably something obvious that I've missed :\
One more thing the .... are just for your sake as the variable is large and would take up a large amount of page space, I slimmed it down as they are all laid out the same way.
In the list '(January Capricorn Aquarius 19 nil), the first three elements are symbols, which are printed out by the REPL in UPPERCASE. Symbols are different from strings. When you quote a list like this, the literals are treated as symbols, not strings.
Similarly, '(You are a goat be happy!) is a list of six symbols. It gets printed out as a list (enclosed in parentheses) of uppercase symbols.
If you replace the symbols and lists with strings:
(defparameter *month-signs* '((January "Capricorn" "Aquarius" 19 nil)...
(defparameter *sign-traits* '((Capricorn "You are a goat be happy!")...
you should get the output you want.
read takes the input as a symbol, so you want to leave the association key (January) as a symbol.
Printing a list with symbols
Common Lisp can print symbols in many ways. The function WRITE gives a basic interface to the printer. We don't want to print string quotes and we want to control how a word gets capitalized.
(defun write-sentence (sentence
&aux ; local variable bindings
(*print-escape* nil) ; no escaping
(*print-readably* nil)) ; we don't print for the reader
(write (first sentence) :case :capitalize)
(dolist (word (rest sentence))
(write " ")
(write word :case :downcase))
(write ".")
(values)) ; return no values
CL-USER 94 > (write-sentence '(YOU ARE A GOAT BE HAPPY))
You are a goat be happy.
PRINC
The standard function to print in a human readable form is PRINC. It does not provide options, other than to optionally specify the output stream. Those need to be bound in the printer control variables. Here we need to tell PRINC which case to use:
(defun write-sentence (sentence)
(let ((*print-case* :capitalize))
(princ (first sentence)))
(dolist (word (rest sentence))
(princ " ")
(let ((*print-case* :downcase))
(princ word)))
(princ ".")
(values))
Format
Similar functionality can be written in a more compact way using the function FORMAT, which includes features to iterate over lists. This example is left as an exercise to decipher:
CL-USER 115 > (format t
"~{~#(~A~)~#{ ~(~A~)~}~}."
'(YOU ARE A GOAT BE HAPPY))
You are a goat be happy.
Case in symbols
It's also possible to specify symbols with case. They need to be escaped in the source code:
|This is a single symbol in Common Lisp!|

emacs lisp pcase error

I am having a hard time reading/understanding the syntax of the pcase statement in emacs-lisp. Please help me figure out how to make the following a valid pcase statement.
(defun execute-play (str)
(setq parse (mapcar (lambda (s) (split-string s ":")) (split-string str " ")))
(pcase (string-to-char (caar parse))``
((pred (<= (string-to-char "5"))) (t-to-pparse))
((pred (<= (string-to-char "d"))) (f-to-p parse))
((string-to-char "w") (w-to-p parse))
(_ "bad input")))
Note that typical input is "1:2 3" or "a 5".
The error from emacs that I get is: 'edebug-signal: Unknown upattern '(string-to-char w)'
This is the second to last case, -- I thought that this would just match the value of (caar parse) against (string-to-char "w") if it did not already match a case before this. Note that I also tried replacing (string-to-char "w") with (SELFQUOTING (string-to-char "w")) since the documentation says that: SELFQUOTING matches itself. This includes keywords, numbers, and strings.
Please help me get this emacs-lisp pcase statement working -- Thanks for all the help!
There are multiple issues with your code:
Since you're not doing any binding or deconstruction in your patterns, you don't need pcase — the conditional is better written using cond.
You have a spurious pair of backquotes at the end of line 3.
You appear to have inverted the first two tests — the first clause will match if the expression is larger than ?5, so the remaining clauses will never match.
pcase doesn't seem to support matching against evaluated values, so third clause should be written (pred (equal (string-to-char "0"))).

How do I print a string in Emacs lisp with ielm?

I'd like to print a string in ielm. I don't want to print the printed representation, I want the string itself. I'd like this result:
ELISP> (some-unknown-function "a\nb\n")
a
b
ELISP>
I can't see any way to do this. The obvious functions are print and princ, but these give me the printable representation:
ELISP> (print "* first\n* second\n* third\n")
"* first\n* second\n* third\n"
I've played with pp and pp-escape-newlines, but these still escape other characters:
ELISP> (setq pp-escape-newlines nil)
nil
ELISP> (pp "a\n")
"\"a
\""
Is this possible? For inspecting large strings, message doesn't cut it.
How about inserting directly into the buffer?
(defun p (x) (move-end-of-line 0) (insert (format "\n%s" x)))
That gets you:
ELISP> (p "a\nb\n")
a
b
nil
ELISP>
EDIT: Use format to be able to print things other than strings.
;;; Commentary:
;; Provides a nice interface to evaluating Emacs Lisp expressions.
;; Input is handled by the comint package, and output is passed
;; through the pretty-printer.
IELM uses (pp-to-string ielm-result) (so binding pp-escape-newlines has an effect in general), but if you want to bypass pp altogether then IELM doesn't provide for that, so I suspect Sean's answer is your best option.
ELISP> (setq pp-escape-newlines nil)
nil
ELISP> "foo\nbar"
"foo
bar"
#Sean's answer is correct if you want to display the string as part of your session.
However, you say you want to inspect large strings. An alternative approach would be to put the string in a separate window. You could use with-output-to-temp-buffer to do this. For instance:
(with-output-to-temp-buffer "*string-inspector*"
(print "Hello, world!")
nil)
A new window will pop up (or if it already exists, its output will be changed). It's in Help mode, so it's readonly and can be closed with q.
If you want to do some more sophisticated stuff in your output buffer you could use with-temp-buffer-window instead, like so:
(with-temp-buffer-window "*string-inspector*"
#'temp-buffer-show-function
nil
(insert "hello, world!!"))

How can I idiomatically transform some text in place using elisp?

I've got some json that I'd like to process in emacs. I've found and used the elisp library to extract the desired content from the json, and I'd like to replace the json with the elisp equiivalent that I've extracted.
This is what I've written:
(defun extract-foo (start end)
"Extract the foo field from a json object in the region"
(interactive "r")
(let ((my_json (cdr (assoc 'FOO (json-read-from-string (buffer-substring-no-properties start end))))))
(delete-region start end)
(SOMETHING)
))
I'm stuck at the something. I can't seem to find a way to write the contents of my_json to the buffer at the mark. The only way I can think of is to save the text instead to a temporary buffer, and then (insert-buffer) it. This seems excessive to me though.
How can I do this idiomatically in elisp?
to write back JSON partial
(insert (format "%s" (json-encode my-json)))
to write back elisp:
(insert (format "%s" my-json))
Note that your use of underscore in variable naming is contrary to convention.

Help with an interactive Emacs Lisp function for replacing text

I've been using Emacs for a couple months now, and I want to get started in elisp programming. Specifically, I'd like to write my own interactive function. However, I'm more than a bit lost. (interactive ...) has tons of options and I'm not sure which one I want. Then, I don't really know the names of the functions I need. If someone could kindly help me turn my pseudocode into real code, I would be mighty appreciative! (And as always, any links to informative places would be good. Right now I've just been reading this.)
Here is pseudocode for what I'd like to do:
(defun my-func (buffer) ; I think I need the buffer as an arg?
"does some replacements"
(interactive ???) ; ?
(let (replacements (list
'("a-regexp-string" . "a-replacement-string-with-backreferences")
...)) ; more of the above
(while replacements
(let (current (car replacements)) ; get a regexp-replacement pair
(some-regexp-replace-func buffer (car current) (cdr current)) ; do the replacement
(setq replacements (cdr replacements))))))
First, from the looks of your function you would probably be doing it in the current buffer, so no, you don't need to have a 'buffer' argument. If that's a bad assumption, I can change the code. Next, in a 'let' if you are assigning to variables you need another set of parens around each pair of var/value. Finally, when looping through a list I prefer to use functional-programming-like functions (mapcar, mapc, etc.). I'll try to inline some comments here:
(defun my-func ()
"Do some replacements"
(interactive)
(let ((replacements (list '("foo" . "bar")
'("baz" . "quux"))))
(save-excursion ; So point isn't moved after this function
(mapc (lambda (x) ; Go through the list, with this 'inline' function
; being called with each element as the variable 'x'
(goto-char (point-min)) ; Start at the beginning of the buffer
(while (re-search-forward (car x) nil t) ; Search for the car of the replacement
(replace-match (cdr x)))) ; And replace it with the cdr
replacements)))) ; The list we're mapc'ing through
As for what to read, I'd suggest the Elisp manual that comes with Emacs.