Lisp - string concat - lisp

I am trying to concat strings in lisp, using clisp on linux.
I run following code:
(defun bingo ()
(strcat "Correct! You guessed " (itoa *count*) " times."))
but, get following error:
EVAL: undefined function STRCAT
EVAL: undefined function ITOA
Any suggestion?

CL-USER 1 > (format nil "This is too easy. ~a day I'll learn Lisp." 1)
"This is too easy. 1 day I'll learn Lisp."

Related

How to convert a list into a string in lisp

How do you convert a list into a string? I am trying to use parse-int to take a list of numbers and convert them to decimal, but i end up getting an error saying "The control-string must be a string, not (contents)".
I'm using format, but I'm not sure if I'm using it incorrectly.
Here's my code:
(princ "Enter a or list of hexadecimal numbers: ")
(setq numList (read-from-string (concatenate 'string "(" (read-line) ")")))
(defun hextodec(nums)
(setq numString (format "%s" nums))
(setq newNum (parse-integer numString :radix 16))
(write nums)
(princ " = ")
(write newNum)
) ;This will format the number that the user enters
(hextodec numList)
Since you're using read-from-string anyway, you can just tell Lisp's reader to read base 16 integers:
;; CLISP session
[1]> (let ((*read-base* 16)) (read-from-string "(9 A B C F 10)"))
(9 10 11 12 15 16) ;
14
read-from-string is a potential security hole if the contents of the string are untrusted input, because of the hash-dot evaluation notation.
When using the Lisp reader on untrusted data, be sure bind *read-eval* to nil.
[2]> (read-from-string "(#.(+ 2 2))")
(4) ;
11
Note how the #. notation causes the + function specified in the string data to be executed. That could be any function, such as something that whacks files in your filesystem, or sends sensitive data to a remote server.
Format's first argument is the stream to print to. You seem to intend to return the string instead of printing, so you should put nil there: (format nil "~s" nums)
The format control string "%s" does not contain any format directives. The entire format form does not make much sense here, as you seem to intend to loop over the given nums instead. You should employ some looping construct for that, e. g. loop, do, map, mapcar ….

How to trim after splitting a string to list in Lisp

Following code from https://www.rosettacode.org/wiki/Tokenize_a_string#Common_Lisp splits a string at commas and send a list.
(defun comma-split (string)
(loop for start = 0 then (1+ finish)
for finish = (position #\, string :start start)
collecting (subseq string start finish)
until (null finish)
)
)
However, the substrings will have blank spaces around them if they are there in original string.
> (comma-split " a, b ,c , d , e")
(" a" " b " "c " " d " " e")
How can I add string-trim function to remove these spaces here. I cannot see a string variable that is being returned in the function.
I tried to have a local variable but it does not work:
(defun comma-split2 (string)
(let* ( (onestr "")
)
(loop for start = 0 then (1+ finish)
for finish = (position #\, string :start start)
(onestr (subseq string start finish))
(onestr (string-trim onestr))
collecting onestr
until (null finish)
)
))
Error on loading file:
*** - LOOP: illegal syntax near (ONESTR (SUBSEQ STRING START FINISH)) in
(LOOP FOR START = 0 THEN (1+ FINISH) FOR FINISH = (POSITION #\, STRING :START START) (ONESTR (SUBSEQ STRING START FINISH))
(ONESTR (STRING-TRIM ONESTR)) COLLECTING ONESTR UNTIL (NULL FINISH))
The following restarts are available:
Even trimming the outlist in a second function is not working:
(defun comma-split2 (string)
(let ( (outlist (list))
(setf outlist (comma-split string))
(dolist (str outlist)
(push (string-trim str) outlist)
)
(nreverse outlist)
)))
> (comma-split2 " a, b ,c , d , e")
*** - LET: illegal variable specification (SETF OUTLIST (COMMA-SPLIT STRING))
The following restarts are available:
The COLLECTING-statement is what is creating the list. So you need to put the call to STRING-TRIM around what is being collected.
(defun comma-split (string)
(loop for start = 0 then (1+ finish)
for finish = (position #\, string :start start)
collecting (string-trim " " (subseq string start finish))
until (null finish)))
You shouldn't put the closing parentheses on their own line.
Without proper indenting Lisp code you won't get very far.
Don't:
(defun foo (a)
(let ((b )
b
))
)
Write
(defun foo (a)
(let (b)
b))
Additionally: trying to write Lisp code without understanding Lisp syntax is also not a good idea.
Trying to use a complex language by googling random code, trying to randomly modify the code and then posting the error messages to Stackoverflow isn't a very promising approach.
Read one or more of the basic Lisp books:
COMMON LISP: A Gentle Introduction to Symbolic Computation
Practical Common Lisp
Use a Lisp reference: Common Lisp Hyperspec
LOOP: illegal syntax near
Read about LOOP, first.
LET: illegal variable specification
Caused by lack of indentation and violation of Lisp syntax. Check the syntax of LET.
How can I add string-trim function to remove these spaces here
How do you add functions at all?
Given this expression:
(sin 3.0)
How do you add a function to compute the square root?
Solution:
(sqrt (sin 3.0))
You call the function on the result of the the first one.
Simple as that. Why would you need additional variables?
Your code is not valid LOOP syntax.
Either you use the simple syntax, which is like a PROGN but loops, or you use LOOP keywords, in which case you need to prefix statements with DO:
(loop
for i in list
do
(print i)
(sleep 1))
You probably only need to do:
(loop for start = 0 then (1+ finish)
for finish = (position #\, string :start start)
collect (string-trim " "
(subseq string
start
finish))
until (null finish))
Alternatively, with regular expressions (see http://weitz.de/cl-ppcre/):
(ppcre:split " *, *" string)
You can use the method string-trim .
For example
(string-trim '(#\Space #\Tab #\Newline) " Test Test") => "Test Test" .
For more information you can go here.
I hope this will help you! :)

Lisp string formatting with named parameters

Is there a way in Lisp to format a string using named parameters?
Perhaps something with association lists like
(format t "All for ~(who)a and ~(who)a for all!~%" ((who . "one")))
in order to print "All for one and one for all".
Similar to this python question, or this scala one, or even c++, but in Lisp.
If this functionality isn't in the language, does anyone have any cool functions or macros that could accomplish the same thing?
Use CL-INTERPOL.
(cl-interpol:enable-interpol-syntax)
String interpolation
For simple cases, you don't need FORMAT:
(lambda (who) #?"All for $(who) and $(who) for all!")
Then:
(funcall * "one")
=> "All for one and one for all!"
Interpret format directives
If you need to format, you can do:
(setf cl-interpol:*interpolate-format-directives* t)
For example, this expression:
(let ((who "one"))
(princ #?"All for ~A(who) and ~S(who) for all!~%"))
... prints:
All for one and "one" for all!
If you are curious, the above reads as:
(LET ((WHO "one"))
(PRINC
(WITH-OUTPUT-TO-STRING (#:G1177)
(WRITE-STRING "All for " #:G1177)
(FORMAT #:G1177 "~A" (PROGN WHO))
(WRITE-STRING " and " #:G1177)
(FORMAT #:G1177 "~S" (PROGN WHO))
(WRITE-STRING " for all!" #:G1177))))
Alternate reader function
Previously, I globally set *interpolate-format-directives*, which interprets format directive in all interpolated strings.
If you want to control precisely when format directives are interpolated, you can't just bind the variable temporarily in your code, because the magic happens at read-time. Instead, you have to use a custom reader function.
(set-dispatch-macro-character
#\#
#\F
(lambda (&rest args)
(let ((cl-interpol:*interpolate-format-directives* t))
(apply #'cl-interpol:interpol-reader args))))
If I reset the special variable to its default value NIL, then strings where directives are formatted are prefixed with #F, whereas normal interpolated ones use the #? syntax. If you want to change readtables, have a look at named readtables.

How to read user input in Lisp

I'm very new to Lisp and am trying to write a program that simply asks a user to enter 3 numbers and then sums them and prints the output.
I've read that you can you a function like:
(defvar a)
(setq a (read))
To set a variable in Lisp, but when I try to compile my code using LispWorks I get the following error:
End of file while reading stream #<Concatenated Stream, Streams = ()>
I feel like this should be relatively simple and have no idea where I'm going wrong.
I've not worked with LispWorks, so it's only a guess.
When compiler traverses your code it gets to the line (setq a (read)), it tries to read input, but there is no input stream while compiling, thus you get an error.
Write a function:
(defvar a)
(defun my-function ()
(setq a (read))
It should work.
This should evaluate properly in your Lisp:
(defun read-3-numbers-&-format-sum ()
(flet ((prompt (string)
(format t "~&~a: " string)
(finish-output)
(read nil 'eof nil)))
(let ((x (prompt "first number"))
(y (prompt "second number"))
(z (prompt "third number")))
(format t "~&the sum of ~a, ~a, & ~a is:~%~%~a~%"
x y z (+ x y z)))))
Simply evaluate the above function definition, then run the form:
(read-3-numbers-&-format-sum)
at your LispWorks interpreter.

Define my own read macro

There are some read macros in Common Lisp such as ' #' #P, but how can I write a read macro?
Like this:
#T"hello world"
====================>
(gettext "hello world")
You can use set-macro-character and set-dispatch-macro-character, for example after:
(set-dispatch-macro-character #\# #\T
(lambda (s c n)
`(gettext ,(read s t nil t))))
==> T
you can use the installed read syntax
(read-from-string "#T\"this is a test\"")
==> (GETTEXT "this is a test")