How to properly tell FORMAT to discard input - common-lisp

I want a dynamic way of telling FORMAT to discard output depending an a certain global variable set before the actual call. I figured that changing t to nil should do the deal, but I am not satisfied as I will then not be able to use those FORMAT calls at any point where the returned string could be confused for an actual return value.
E.g:
Telling FORMAT to output on TERMINAL-IO (works fine)
(let ((*the-var* t))
(FORMAT *the-var* "some text")
#|do some other stuff|#)
->"some-text"
->'return-value'
Telling FORMAT to discard output (works fine)
(let ((*the-var* nil))
(FORMAT *the-var* "some text")
#|do some other stuff|#)
->'return-value'
Telling FORMAT to discard output (does not work fine as the returned string of FORMAT might get confused with a possible return value)
(let ((*the-var* nil)) ;no return value intended//nil expected
#|do some stuff|#
(FORMAT *the-var* "some text"))
->"some text"
Therefore I wonder if there is any way of telling FORMAT to discard output without to much fuss, like setting the *the-var* variable to a "/dev/null"-stream or putting a condition-clause around it?

A broadcast stream with no component streams is the Common Lisp way to discard output. You can create one with make-broadcast-stream.

FORMAT does not discard output.
If you pass NIL to FORMAT as output direction, then it will return the output as a string and will not print to a stream.
The best way to not print anything is to not call FORMAT.
It makes very little sense to use FORMAT to generate output and not use that output for display. Just check if you want output or not.
(let ((output-p nil)) ;no return value intended//nil expected
#|do some stuff|#
(when output-p
(FORMAT stream "some text")))

Related

How do I save an image to the database using caveman and sxql?

I am trying to build a website that takes an uploaded image and saves it in the PostgreSQL database.
From caveman I can do:
(caveman2:request-raw-body caveman2:*request*)
Which gives me a circular stream: CIRCULAR-STREAMS:CIRCULAR-INPUT-STREAM.
I suppose I can then use a read-sequence to put the contents into a byte array
(let ((buffer (make-array 5 :adjustable t :fill-pointer 5)))
(read-sequence buffer (caveman2:request-raw-body caveman2:*request*))
(add-picture-to-db buffer))
The problem occurs when I try to save this byte array into the database using sxql.
(defun add-picture-to-db picture
(with-connection (db)
(datafly:execute
(sxql:update :testpictures
(sxql:set= :picture picture)
(sxql:where (:= :id 1))))))
I guess the reason why it is failing might be because ultimately, sxql will generate a string which won't work well with binary data. Is there something here that I'm missing? How can I make this work?
Ideally, the way to verify the solution would be to retrieve the saved image from the db, serve it as the response of a http request and see if the client gets the image.
It would be much better to use Postmorden for this as it supports the handling of byte data with PostgreSQL
However, it is possible to work around the limitations of sxql. The first thing to understand is that sxql will ultimately generate an SQL query string, which will cause problems if you insert byte data directly into it.
It is necessary to convert the bytes of the file you want to store into HEX so that it can be used in sxql.
(format nil "~{~2,'0X~}" list-of-bytes-from-file)
Running this function through all the bytes of the file will give you a string composed of two digit HEX for each byte. This is important because other methods of converting bytes to HEX may not maintain the two digit padding, leading to an odd number of HEX.
For example:
(write-to-string 0 :base 16)
This will return a single digit HEX.
Next, you store the resulting string as you normally would into a bytea type column in the db using sxql.
When retrieving the file from the database, you get a byte array that represents the HEX string.
Using this function you can convert it back to a HEX string.
(flexi-streams:octets-to-string byte-array :external-format :utf-8)
Next step is to split the resulting string into pairs of HEX, e.g: ("FF" "00" "A2")
Then convert the pair back into a byte using this function on each pair:
(parse-integer pair :radix 16)
Store those bytes into an array of type unsigned byte, and finally return that array as the body of the response in caveman2 (not forgetting to also set the corresponding content-type header).

How would I print out a list with spaces in between elements

So I'm trying to print out a list that looks a little bit something like this (setq lst (list '- '- '- '- '-)) and in the past I used the print command to print out the whole list, however, when printing the whole list there is parenthesis on each side which I do not want to see. I want to use something like (format t) to print every bit of my list and I have something like this set up.
(loop for item from 0 to 4
do (progn
(format t "~X" (nth item lst))
)
)
This code prints out the list perfectly fine like this, ----- but as a mentioned, I want it to print spaces between each element so that it is output like this - - - - -. I used the conditional "~X" because I looked up how to output spaces with the format command and you are apparently supposed to use "~X" but it does not work so if anybody knows how I could put spaces between elements that would be greatly appreciated.
Why not just use the features provided by format:
CL-USER> (defvar *my-list* '(- - - -))
*MY-LIST*
CL-USER> (format nil "~{~A~^ ~}" *my-list*)
"- - - -"
CL-USER> (format t "~{~A~^ ~}" *my-list*)
- - - -
NIL
Here the first call to format outputs to a string to show where the spaces are placed. ~{ is an iteration directive that takes a list as its argument. The directives between the opening ~{ and closing ~} are used repeatedly as a format string for the elements of the input list. The ~^ directive causes an early escape from the iteration context when there are no more arguments; this prevents a trailing space from being added.
The second call to format just outputs to *standard-output*.
Regarding your update, that you posted in the answers to your own post:
First of all, you should edit your post to show us that you found a solution, rather than having us look through all the answers to see how much progress you made on your initial problem.
As it was already mentioned in another answer, you can iterate through the elements of a list using format built-in syntax with ~{~} and ~^ (see the documentation !)
In your own solution, when you iterate over the list using loop, you can put a space at the end of the format string rather than calling format twice ...
You can use loop for <elt> in <list> rather than iterating with the indices, and calling nth at each step - which is slower, and also more verbose.
The loop ... do <stuff> already wraps the <stuff> in what we call an implicit progn, i.e. you do not need to wrap yourself all your instructions in a progn, the loop macro does that for you.
There also exists the macro dolist, which is (arguably) simpler to use in those case when you simply want to iterate over a list.
To be fair, it looks like you are a Common Lisp beginner. In this case, I suggest you read the excellent Practical Common Lisp book, which covers in details the loop macro, the format function, and a lot of basic principles. It is available for free online, and is often recommended to beginners, for good reasons !
Ok I came up with an ingenius solution to my problem which I definitely should've seen before.
(loop for item from 0 to 4
do (progn
(format t "~X" (nth item lst))
(format t " ")
)
)
I didn't realize I could print a space like that but it works perfectly fine. Sorry for wasting you all's time but hopefully someone else can see this if they are having a brain fart like me and thanks to everyone who tried to help.

How obtain in Erlang with fread a string with no " "

I have a fread in my program:
{ok, [S]} = io:fread("entry: \n", "~s")
But I get {ok, "string"}
I want to get just the string and not the quotation marks.
So I can use it in:
digraph:add_vertex(G, S)
And receive a vertex string and not "string"
How can I do that?
It's an illusion. The quotation marks aren't really there. The shell, or other display mechanisms may show them when rendered with certain contexts in order to represent the data you are displaying, but the quotes in this case are really just meta data:
Here's your case:
1> {ok, [S]} = io:fread("entry: \n", "~s").
entry:
foo
{ok,["foo"]}
If you display S strictly though, you will see that it is a list with only 3 characters:
2> io:format("~w~n", [S]).
[102,111,111]
ok
If you ask io:format/2 to display the data generically, using it's best representation of the interpretation of the data though, it thinks 'ahha, this is a string, I shall display it as a string':
3> io:format("~p~n", [S]).
"foo"
ok
4>
Strings are obviously just lists, so in this that case a decision has to be made to display as a string, or as a list, and the decision to display as a string is made because the list bytes all represent printable characters. Adding a non printable character will change the behaviour therefore, like this:
5> io:format("~p~n", [[2|S]]).
[2,102,111,111]
ok
6>

Newline state after reading a line with a prompt seems not be updated

I am using GNU CLISP and getting crazy because this program:
(read-line)
(format t "~&<prompt RESPONSE")
Outputs something like:
my input...
<prompt RESPONSE
But if I print a prompt before (read-line) I get a spurious empty line:
(format t "~&prompt> ")
(read-line)
(format t "~&<prompt RESPONSE")
E.g.:
prompt> my input...
<prompt RESPONSE
I have tried using (finish-output) both before and after read-line, but it didn't help. I do not understand where that empty line come from. I suspect there is a bug in CLISP.
For those who don't know, ~& in a format command is a conditional newline, which means "print a newline if need be". That is, only print a newline if the last thing lisp printed wasn't already a newline.
The format function (at least on your machine!) ignores user input when deciding whether to issue a newline. This may not be the case on all systems. I really don't remember.
Let's focus on the ~& that immediately precedes <prompt RESPONSE. In your first case, format sees that it hasn't printed anything yet and thus does not need to print a newline. In the second case format sees that the last thing it printed was not a newline and therefore it needs to print a newline.
The solution: Knowing that the user will always provide the newline, don't include it in your format statement. You can even remove it from your initial prompt if you wish:
(format t "prompt> ")
(read-line)
(format t "<prompt RESPONSE")
So, then the question arises, "Then what is ~& for anyhow?" And, indeed, there are other uses for it. For example, to separate 2 consecutive lines of output:
(format t "prompt> ")
(read-line)
(format t "<prompt RESPONSE 1~&<prompt RESPONSE 2")

in R, can I stop print(cat("")) from returning NULL? and why does cat("foo") return foo>

If I enter
print(cat(""))
I get
NULL
I want to use cat() to print out the progress of an R script, but I don't understand why it is returning NULL at the end of all of my concatenated strings, and more importantly, how to get it to stop?
All your answers are in the documentation for ?cat. The portions that answer your specific question are:
Arguments:
fill: a logical or (positive) numeric controlling how the output is
broken into successive lines. If ‘FALSE’ (default), only
newlines created explicitly by ‘"\n"’ are printed.
Otherwise, the output is broken into lines with print width
equal to the option ‘width’ if ‘fill’ is ‘TRUE’, or the value
of ‘fill’ if this is numeric. Non-positive ‘fill’ values
are ignored, with a warning.
... and ...
Value:
None (invisible ‘NULL’).
So you can't stop print(cat(...)) from returning NULL because that's what cat returns. And you need to explicitly add newlines like cat("foo\n").
NULL is the return value of "cat()". If you omit the outer "print()" you won't see the NULL.
I have had the exact same problem. In a nutshell, cat() is a little wonky under R. You didn't go into great detail about how you are trying to use cat() but I would suggest looking at paste().
?paste
I think it may be what you are looking for.
I do not see the need to use print(cat()). To printing a message cat() is already sufficient. This may be what you are looking for:
for (j in 1:n) {
cat("Running loop", j, "of", n, "\n")
}
For this, I often use writeLines(), in combination with strwrap(), and paste() to combine say the loop value if I'm printing out info on the current iteration. strwrap() handles wrapping long lines as required, and writeLines() means I don't have to remember to add a "\n" on the end of my cat() calls.
> writeLines(strwrap("a very very very very long long long long long long long long string, that is too wide for the current pager width"))
a very very very very long long long long long long long long string,
that is too wide for the current pager width
Here is an example using it to print out an iteration indicator:
for(i in 1:1000) {
if(isTRUE(all.equal(i %% 100, 0)))
writeLines(strwrap(paste("Iteration", i)))
## do something
}
Gives:
> for(i in 1:1000) {
+ if(isTRUE(all.equal(i %% 100, 0)))
+ writeLines(strwrap(paste("Iteration", i)))
+ ## do something
+ }
Iteration 100
Iteration 200
Iteration 300
Iteration 400
Iteration 500
Iteration 600
Iteration 700
Iteration 800
Iteration 900
Iteration 1000
If you want to assign it to a variable, for use in a LOOP of *apply or function (x), try this:
x<-eval(paste0(name,".y"))
The name is the variable, the ".y" adds a string to it, paste says to print in, eval evaluates the print, <- assigns it to a variable, and ax is that variable.
I had a little bit of a different issue in that I wanted to concatenate some html text to wrap long strings in my Rmarkdown and was getting that same NULL from the cat(). Simply wrapping in HTML() from the shiny package solved the problem.
```{r, results = "asis"}
HTML(cat("<span style='white-space: pre-wrap; word-break: break-all;'>",comments,"</span>"))

Resources