How to remove the brackets from this text - lisp

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!|

Related

LISP - Splitting string with delimiter also included in new list

I have a list of elements following
("(aviyon" "213" "flyingman" "no))") as list
What i want is that I want to split this list containing strings using parentheses as splitter but also want to include these parentheses in a new list without breaking the order
My desired output of new list(or same list modified)
("(" "aviyon" "213" "flyingman" "no" ")" ")")
I am coming from imperative languages and this would be 15 minute job in Java or C++. But here i'm stuck what to do. I know i have to
1- Get a element from list in a loop
I think this is done with (nth 1 '(listname) )
2- separate without removing delimiter put in to a new list
I found functions such as SPLIT-SEQUENCE but i can't do without removing it and without breaking original order.
Any help would be appreciated.
You can use cl-ppcre library to do the job.
For example:
CL-USER> (ql:quickload :cl-ppcre)
CL-USER> (cl-ppcre:split "([\\(\\)])" "(aviyon" :with-registers-p t)
("" "(" "aviyon")
CL-USER> (cl-ppcre:split "([\\(\\)])" "no))" :with-registers-p t)
("no" ")" "" ")")
CL-USER>
However, it makes empty-strings in a list. Use remove-if function to get rid of them:
CL-USER> (defun empty-string-p (s) (string= s ""))
EMPTY-STRING-P
CL-USER> (remove-if 'empty-string-p
(list "no" ")" "" ")"))
("no" ")" ")")
Finally, you can construct a function which does both, and run it in an imperative loop (yes, Common Lisp is not functional as many think):
CL-USER> (defun remove-empty-strings (l)
(remove-if 'empty-string-p l))
REMOVE-EMPTY-STRINGS
CL-USER> (defun split (s)
(cl-ppcre:split "([\\(\\)])"
s
:with-registers-p t))
SPLIT
CL-USER> (defparameter *the-list* '("(aviyon" "213" "flyingman" "no))"))
*THE-LIST*
CL-USER> (loop for item in *the-list*
for splitted = (split item)
for cleaned = (remove-empty-strings splitted)
append cleaned)
("(" "aviyon" "213" "flyingman" "no" ")" ")")
Let's have another answer, without external libraries.
Like you already did, we can split in the problem into smaller parts:
define a function which builds a list of tokens from a string, all-tokens
apply this function on all strings in your input list, and concatenate the result:
(mapcan #'all-tokens strings)
The first part, taking a state and building a list from it, looks like an unfold operation (anamorphism).
Fold (catamorphism), called reduce in Lisp, builds a value from a list of values and a function (and optionally an initial value).
The dual operation, unfold, takes a value (the state), a function, and generate a list of values.
In the case of unfold, the step function accepts a state and returns new state along with the resulting list.
Here, let's define a state as 3 values: a string, a starting position in the string, and a stack of tokens parsed so far.
Our step function next-token returns the next state.
;; definition follows below
(declare (ftype function next-token))
The main function which gets all tokens from a string just computes a fixpoint:
(defun all-tokens (string)
(do (;; initial start value is 0
(start 0)
;; initial token stack is nil
(tokens))
;; loop until start is nil, then return the reverse of tokens
((not start) (nreverse tokens))
;; advance state
(multiple-value-setq (string start tokens)
(next-token string start tokens))))
We need an auxiliary function:
(defun parenthesisp (c)
(find c "()"))
The step function is defined as follows:
(defun next-token (string start token-stack)
(let ((search (position-if #'parenthesisp string :start start)))
(typecase search
(number
;; token from start to parenthesis
(when (> search start)
(push (subseq string start search) token-stack))
;; parenthesis
(push (subseq string search (1+ search)) token-stack)
;; next state
(values string (1+ search) token-stack))
(null
;; token from start to end of string
(when (< start (1- (length string)))
(push (subseq string start) token-stack))
;; next-state
(values string nil token-stack)))))
You can try with a single string:
(next-token "(aviyon" 0 nil)
"(aviyon"
1
("(")
If you take the resulting state values and reuse them, you have:
(next-token "(aviyon" 1 '("("))
"(aviyon"
NIL
("aviyon" "(")
And here, the second return value is NIL, which ends the generation process.
Finally, you can do:
(mapcan #'all-tokens '("(aviyon" "213" "flyingman" "no))"))
Which gives:
("(" "aviyon" "213" "flyingman" "no" ")" ")")
The above code is not fully generic in the sense that all-tokens knows too much about next-token: you could rewrite it to take any kind of state.
You could also handle sequences of strings using the same mechanism, by keeping more information in your state variable.
Also, in a real lexer you would not want to reverse the whole list of tokens, you would use a queue to feed a parser.
solution
Since you didn't understood Alexander's solution and since I anyway wrote my solution:
;; load two essential libraries for any common lisper
(ql:quickload :cl-ppcre)
(ql:quickload :alexandria)
;; see below to see how to install quicklisp for `ql:quickload` command
;; it is kind of pythons `import` and if not install `pip install`
;; in one command for common-lisp
(defun remove-empty-string (string-list)
(remove-if #'(lambda (x) (string= x "")) string-list))
(defun split-parantheses-and-preserve-them (strings-list)
(remove-empty-string
(alexandria:flatten
(mapcar #'(lambda (el) (cl-ppcre:split "(\\(|\\))"
el
:with-registers-p t))
strings-list))))
;; so now your example
(defparameter *list* '("(aviyon" "213" "flyingman" "no))"))
(split-parantheses-and-preserve-them *list*)
;; returns:
;; ("(" "aviyon" "213" "flyingman" "no" ")" ")")
how this works
(cl-ppcre:split "(\\(|\\))" a-string)
splits the string by ( or ). Because in regex pattern ( or ) are used for capturing the match - like here too (the outer parantheses captures) - you have to escape them. \\( or \\).
So with cl-ppcre:split you can split any string in common lisp by regex-pattern. Super cool and super efficient package written by Edi Weitz. He wrote several super sophisticated packages for common lisp - they are also called ediware or edicls in the community.
By the way - cl-ppcre is even more efficient and faster than gold-standard for regex: the perl regex engine!
:with-regiesters-p t option then preserves the matched delimiter - which has to be captured by parentheses like this: (<pattern>) in the pattern.
mapcar this over the list to apply it on each string element in your string list.
However, what you got after that is a list of lists.
(Each inner list containing the splitted result for each string-element of the list).
Flatten the list by alexandria:flatten.
For many functions not in the standard of lisp, but which you think they are basic - like flatten a list - look always first in alexandria - mostly it has a function you desire - it is a huge library. That is why you need it anyway as a common lisper ;) .
But still, there will be empty strings around to be removed.
That is why I wrote remove-empty-string which uses remove-if - which together with remove-if-not is the standard filtering function for lists.
It takes a predicate function - here (lambda (x) (string= x "")) which gives T if string is an empty string and NIL if not.
It removes all elements in the resulting flattened list in our function, which are empty strings.
In other languages it will be named filter but yeah - sometimes function names in common-lisp are not very well chosen. Sometimes I think we should create alias names and move over to them and keep the old names for backward-compatibility. Clojure has nicer names for functions ... Maybe cl people should overtake clojure function names ...
quicklisp
#Alexander Artemenko wrote exactly my solution - he came first. I will add:
If you are so new to common lisp, maybe you don't know how to use quicklisp.
Do in terminal (linux or macos):
wget https://beta.quicklisp.org/quicklisp.lisp
Otherwise manually download in windows from the address.
I put it into ~/quicklisp folder.
Then in clisp or sbcl do:
(load "~/quicklisp/quicklisp.lisp") ;; just path to where downloaded
;; quicklisp.lisp file is!
;; then install quicklisp:
(quicklisp-quickstart:install)
;; then search for cl-ppcre
(ql:system-apropos "cl-ppcre")
;; then install cl-ppcre
(ql:quickload "cl-ppcre")
;; and to autoload everytime you start sbcl or clisp
;; in linux or mac - sorry I don't now windows that well
;; I have the opinion every programmer should us unix
;; as their OS
;; you have to let quicklisp be loaded when they start
;; by an entry into the init file
;; mostly located in ~/.sbclrc or ~/.clisprc.slip or such ...
;; respectively.
;; quicklisp does an entry automatically if you do:
(ql:add-to-init-file)
;; after installation do:
(quit)
;; If you then restart sbcl or clisp and try:
(ql:quickload :cl-ppcre)
;; it should work, - if not, you have to manually load
;; quicklisp first
(load "~/quicklisp/setup.lisp") ;; or wherever quicklisp's
;; setup.lisp file has been stored in your system!
;; and then you can do
(ql:quickload :cl-ppcre)
;; to install alexandria package then, do
(ql:quickload :alexandria) ;; or "alexandria"
;; ql:quickload installs the package from quicklisp repository,
;; if it cannot find package on your system.
;; learn more about quicklisp, since this is the package
;; manager of common lisp - like pip for python

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.

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 can I add a format specifier to `format-time-string`?

I have the following function definition:
(defun nth (n)
(format
(concat
"%d"
(if (memq n '(11 12 13)) "th"
(let ((last-digit (% n 10)))
(case last-digit
(1 "st")
(2 "nd")
(3 "rd")
(otherwise "th"))))) n))
and I'd like to be able to use it in format-time-string.
Normally, I would look at the source of the function, but this one is defined in the C source code. (I would presume this precludes hooking something onto it, but I stand to be corrected.)
How can I add another format specifier (say, %o) that will apply nth to the appropriate argument?
Desired usage:
(format-time-string "%A, %B %o, %T (%z)" (seconds-to-time 1250553600))
=> "Monday, August 17th, 20:00:00 (-0400)"
Here is what you want to do. Stefan and Drew already gave some important remarks (don't overwrite nth and look at the info-files of emacs-lisp/advising functions).
(defun ordinal (n)
"Special day of month format."
(format
(concat
"%d"
(if (memq n '(11 12 13)) "th"
(let ((last-digit (% n 10)))
(case last-digit
(1 "st")
(2 "nd")
(3 "rd")
(otherwise "th"))))) n))
(defadvice format-time-string (before ordinal activate)
"Add ordinal to %d."
(let ((day (nth 3 (decode-time (or time (current-time))))))
(setq format-string
(replace-regexp-in-string "%o"
(ordinal day)
format-string))))
Notes:
I did not handle the UNIVERSAL argument
The hack does not work when format-time-string is called from C (as you can read in the manual).
AFAIK you're out of luck: format-time-string does not offer any way to do that.
You might be able to work around this by using something like:
(let ((ti (seconds-to-time 1250553600)))
(format-time-string (concat "%A, %B " (my-nth (format-time-string "%d" ti)) ", %T (%z)") ti))
This said, I've always been told that "August 17th" is wrong: you're supposed to write "August 17" which is pronounced "August the seventheenth".
One more thing: nth is a predefined core function. Better not overwrite it with your own completely different definition.
To add to what Stefan said ("You're out of luck") --
format-time-string is a built-in, but you can advise built-ins too. However, since the kind of surgery you want to do would dig into the bowels of the definition (which you cannot do), you would need to in fact replace the definition of format-time-string in the defadvice, i.e., not use ad-do-it at all.
In other words, one way or the other (defun or defadvice) you would need to completely redefine the function, in Lisp. Which is about the same as saying "You're out of luck."

How to print blank character in the Lisp format function?

I hope there's someone to help me with this, because I can't find any useful answer, and I'm new with Lisp.
What I'm trying to do is to test a value of one element and to print something if its 1, otherwise to print blank character.
This works when all of the list arguments have the value 1:
(defun print-lst (list)
(format t "~%~a ~a ~a~%"
(if (= (nth 0 list) '1)
'¦)
(if (= (nth 1 list) '1)
'P)
(if (= (nth 2 list) '1)
'¦)))
so the output is ¦ P ¦. But, if the second element in list is 0, it prints NIL on that place ¦ NIL ¦ and I want it to print a space instead ¦ ¦(not just to skip that character¦¦, it is important to there is a blank character in that position in output line if the tested value is not 1).
Is there any way to return a blank character if the condition (if (= (nth 1 list) '1) 'P) is not fulfilled or is there any other way to perform this?
I hope I explained that nicely. Thank you.
If you want to make full use of the power of format, you can use a combination of format conditionals and format GOTO.
Like this:
[1]> (format nil "~#{~:[<nothing>~;~:*~A~]~^ ~}" 1 2 nil 4 nil 6)
"1 2 <nothing> 4 <nothing> 6"
In your case, this should work:
(format t "~&~#{~:[ ~;~:*~A~]~^ ~}"
...)
This works by doing the following:
~& inserts a newline unless we're already at the beginning of a line.
~#{...~} processes the arguments iteratively.
~:[...~;...~] chooses between the nil and non-nil case.
~:* unconsumes the argument that was consumed by ~:[...~].
~A outputs the item being processed.
~^ escapes from the loop on the last iteration (so as not to output an excessive space after the last item).
If takes three arguments: condition, then-form, else-form; the else-form is optional. Besides, I would use literal character syntax for literal characters.
(if (= (nth 0 list) 1)
#\P
#\Space)
Documentation:
Special form if
Character syntax
Character names
Counter question:
Do you really need output values that are identifiers ('something) or would also string literals work ("something")?
If the first is true: I suppose it is not possible to use space as an identifier.
If the second is true: use "|", "P" and " " as output values
Format is a beast waiting to devour the unwary.
That said, it looks like you may want to use some of its higher level directives here. Check out the Formatted Output section of the Lisp Hyperspec, and the format chapter of PCL (specifically, look at the section that deals with conditional formatting).