I'm sure this is a very basic question, but how to output delimited values?
(defun q (n)
(if (<= n 2)
1
(+
(q (- n (q (- n 1))))
(q (- n (q (- n 2)))))))
(loop for x from 1 to 25
do (
write (q x)))
The above outputs the first 25 terms of the Hofstadter Q-sequence, but concatenated:
11233455666888109101111121212121614
Can be comma-, space- or tab-delimited. I tried playing with the format function, but it's way over my head for a Lisp newbie like me.
You can write the delimiter yourself, e. g. (write ", "). You can also write the (platform dependent) line separator with (terpri).
As for format, you can get by with some basic usage at first:
(format <stream> <template> <args…>)
<stream> is where the output should go. For standard output, use t. In order to write to a file, you would use the stream created by with-open-file here.
<template> is a template string. That's just a string, but the ~ character is special. For starters, just use ~a wherever you want to insert an argument.
<args…> are exactly as many further arguments as you used ~a above.
Using this simple toolbox, you could do: (format t "~a, " (q x)) for each item.
Format has a lot of other possibilities, e. g. it can iterate a list by itself, do different output formats and escaping, or even be extended by user functions. Look that up in the hyperspec (e. g. at clhs.lisp.se).
use write-char or, indeed, format:
(format t "~D: ~:D~%" x (q x))
Related
I'm learning Clojure. I wrote a first-attempt at calculating a Fibonacci number. Here's my code and the subsequent error message.
I have NO CLUE what to correct. My question is: WHAT is the error message trying to say?
(defn fibon
(fn [n]
(loop [loops n acc 1N acc2 0N]
(if (<= loops 0)
acc ;; Return the summed F number.
(recur (dec loops) (+ acc acc2) acc)))))
Syntax error macroexpanding clojure.core/defn at
(form-init1248982153229513778.clj:1:1). fn - failed: vector? at:
[:fn-tail :arity-n :bodies :params] spec:
:clojure.core.specs.alpha/param-list (fn [n] (loop [loops n acc 1N
acc2 0N] (if (<= loops 0) acc (recur (dec loops) (+ acc acc2) acc)))) failed: vector? at: [:fn-tail :arity-1 :params] spec: :clojure.core.specs.alpha/param-list
In general, could someone please point me to some documentation on Clojure in Cursive so I can decipher these error messages myself, if there is such a beast. Thank you.
The error message you see is a clojure.spec error. It is telling you that your code violates the specification of defn.
The error message is cryptic but if you unpack the error message you can see that the param-list clojure.spec failed because (fn [n] (loop ... is not a vector?
This is trying to tell you that defn expected to see a vector after fibon, not (fn [n] (loop ... It is not the most intuitive error message.
There is the clojure spec guide but it is targeted to developers of specifications.
There are other clojure projects that provide more intuitive spec error messages. I've used expound at the command line and it provides much nicer error messages, however I don't think you can use expound with cursive, but that might be worth exploring.
When I saw your code, I first looked at what the definiation of the defn macro is by doing a ctrl-mouse-over on the defn, or you can look at the online defn documentation. That information along with the spec error let me understand how to interpret the error message.
As for your code, when using defn you don't use (fn. So your code should look like:
(defn fibon [n]
(loop [loops n acc 1N acc2 0N]
(if (<= loops 0)
acc ;; Return the summed F number.
(recur (dec loops) (+ acc acc2) acc))))
The above answer is good. One suggestion to a question you didn't ask: you may wish to adjust your IDEA settings so it only indents 2 spaces each line, instead of 8 spaces (1 tab char?).
If necessary, uncheck the box "Use tab character". Here is a screenshot:
Then it will look like this:
(defn fibon
[n]
(loop [loops n
acc 1N
acc2 0N]
(if (<= loops 0)
acc ;; Return the summed F number.
(recur (dec loops) (+ acc acc2) acc))))
For the loop statement, I like to keep each loop variable and its initial value on a separate line. In this way it looks similar to the Clojure let expression.
Enjoy!
I want to read multiple data files (10 in total) in Ansys Fluent. I wrote a journal file which uses scheme language
(Do ((count 11.100 (+ count 0.100))) ((>= count 12.000))
(ti-menu-load-string (format #f "file read-data data-~a.dat" count)))
The format of the file name is like data-11.200.dat, but the program reads it as data-11.2.dat. How I can force it to read the floating point numbers after the decimal point?
Of course I can rename the data files, but that is not useful for I have to use the code many times.
I have tried data-~03d.dat, but that didn't work!
Try this:
(do ((count 111/10 (+ count 1/10))) ((>= count 12))
(ti-menu-load-string
(format #f "file read-data data-~2,3F.dat" count)))
I assume format is from SRFI-48 Intermediate Format Strings. I've changed the numbers to rational numbers because adding 0.1 gives you rounding errors in floating point.
I think I have figured that out:
data-~.3f.dat
I sometimes put examples of function calls and their output in the documentation string of a function definition.
(defun js-[] (&rest args)
"Javascript array literal statement.
(js-[] 1 2 3)
> \"[1, 2, 3]\"
"
(format nil "[~{~A~^, ~}]" (mapcar #'js-expr args)))
But sometimes the output of the function is a string. So I have to escape the double quotes in the example output. This becomes tedious very quickly.
Is there a way to change the docstring delimiter from double quotes to something else so I don't have to keep escaping them?
Please note that sometimes it's worse than just escaping once:
(defun js-~ (str)
"Javascript string statement. This is needed so that double quotes are inserted.
(js-~ \"string\")
> \"\\\"string\\\"\"
"
(format nil "\"~A\"" str))
Here there is an additional problem. Reading the docstring is difficult.
TL;DR
Yes, you can, no, you do not want to do it.
No, CL has just one syntax for strings
The only way to represent a string in Common Lisp is to use
Double-Quote ".
Yes, you can modify the reader so that something else denotes a string
E.g., suppose you want to a string to be started and stopped by, say, #.
(This is an ordinary character rarely used in symbol names,
in contrast to % and $ which are often used in implementation-internal symbols.)
Set the properties of # from ":
(multiple-value-bind (function non-terminating-p)
(get-macro-character #\")
(set-macro-character #\# function non-terminating-p))
Now:
(read-from-string "#123#")
==> "123" ; 5
(read-from-string #"123"#)
==> "123" ; 5
Do not forget to restore the input syntax to standard Common Lisp syntax:
(setq *readtable* (copy-readtable nil))
See Reader.
You might be able to modify the printer
The standard does not require that the printing of standard objects
(such as a string) to be
used-modifiable.
You can try defining a print-object method:
(defmethod print-object ((o string) (d stream))
...)
however,
implementing this correctly is not easy
this is non-conforming code (defining a method for a standardized generic function which is applicable when all of the arguments are direct instances of standardized classes)
thus many implementations will signal errors on this code,
even if you disable package locks &c, the implementation is free to ignore your method.
No, you do not want to do that
The code exists for people to read it.
Changing Lisp syntax will make it harder for others to read your code.
It will also confuse various tools you use (editor &c).
CL has many warts, but this is not one of them ;-)
PS. See also documentation and describe, as well as comment syntax Sharpsign Vertical-Bar and Semicolon.
You could make a reader macro that slurps in a multi line string like this:
(defun hash-slash-reader (stream slash arg)
(declare (ignore slash arg))
(loop :with s := (make-string-output-stream)
:for c := (read-char stream)
:if (and (eql #\/ c) (eql #\# (peek-char nil stream)))
:do (read-char stream) (return (get-output-stream-string s))
:if (eql #\Newline c)
:do (peek-char t stream)
:do (princ c s)))
(set-dispatch-macro-character #\# #\/ #'hash-slash-reader)
Now you can do:
(defun js-~ (str)
#/ --------------------------
Javascript string statement.
This is needed so that double quotes are inserted.
(js-~ "string")
> "\"string\""
-------------------------- /#
(format nil "\"~A\"" str))
The documentation string will be added just as if you'd written it with double quotes. This is effectively the same as changing the delimiter for strings!. In fact, it is an additional way to delimit strings.
Which is why you can use it (not recommended though) in regular lisp code, and not just for documentation purposes.
Using / as the sub-character of the dispatch macro, helps keep it conceptually close to the multiline comment, but avoids being ignored by the reader altogether.
Another idea. Write your docstrings as usual, without examples.
(defun js-~ (str)
"Javascript array literal statement."
...)
Define tests. That can be as simple as:
(defparameter *tests*
'(((js-~ "string") . "\"string\"")
...))
Use that list to perform tests:
(loop for (form . expected) in *tests*
for (fn . args) = form
for actual = (apply fn args)
do (assert (equalp actual expected)))
... and to update the documentation. Be careful, this appends to the existing documentation string, so don't run it twice.
(loop for (form . expected) in *tests*
for (fn . args) = form
do (setf (documentation fn 'function)
(format nil
"~a~%~% ~S~% => ~S"
(documentation fn 'function)
form
expected)))
You can (ab)use cl-interpol. Although the purpose of the library is to enable string interpolation it also allows custom string delimiters, if you don't mind preprending the string with #?. e.j.
CL-USER> (cl-interpol:enable-interpol-syntax)
; No values
CL-USER> #?'foo'
"foo"
CL-USER> #?/foo/
"foo"
CL-USER> #?{foo}
"foo"
CL-USER>
so after enabling the interpol reader macro you could write
(defun js-[] (&rest args)
#?'Javascript array literal statement.
(js-[] 1 2 3)
> "[1, 2, 3]"
'
In Common Lisp, I need to capture user input in the form of a list of reals. This list is terminated by two zeros in a row. For example, 5.0 0 6.0 3 2.0 5 1.0 7 13.0 8 0 0 should return the list (5.0 0 6.0 3 2.0 5 1.0 7 13.0 8).
I've come across the function read-delimited-list, which takes a single character as an ending point. I can stop at a single zero, but I'm not sure how to expand this function, and I don't know of another function that takes a delimited string instead of a char.
EDIT Thanks to the accepted answer, I've developed the following:
(butlast (loop for y = -1 then x for x = (read stream) until (and (= 0 x) (= 0 y))
collect x)))
It seems a bit more readable to me (and at this point I'm openly admiting that my Lisp eyes are only 3 days old), and I'm not sure about performance implications (does collect append or reverse the list after the loop exits scope? is there an easier way to chop off the last element, or simply not append it?).
For such simple case you can just use read in a loop, collect the results read so far and stop, when the last two are zeros.
(defun read-double-zero-terminated-list (stream)
(do* ((prev -1 val)
(val (read stream) (read stream))
list)
((and (zerop prev) (zerop val)) (reverse (cdr list)))
(push val list)))
read-delimited-list is intended for the cases of creating specialized syntax, so it's probably overkill here.
The best way to parse numbers in Common Lisp is to use the library parse-number. If your user input can be read line by line, you can simply split the lines on whitespace and use parse-number on the results.
I'm learning Lisp and have written the following function to collect a list of results.
(defun collect (func args num)
(if (= 0 num)
()
(cons (apply func args)
(collect func args (- num 1)))))
It produced similar output to the built in loop function.
CL-USER> (collect #'random '(5) 10)
(4 0 3 0 1 4 2 1 0 0)
CL-USER> (loop repeat 10 collect (random 5))
(3 3 4 0 3 2 4 0 0 0)
However my collect function blows the stack when I try to generate a list 100,000 elements long
CL-USER> (length (collect #'random '(5) 100000))
Control stack guard page temporarily disabled: proceed with caution
Whereas the loop version doesn't
CL-USER> (length (loop repeat 100000 collect (random 5)))
100000
How can I make my version more space efficient, are there alternatives to consing? I think it's tail recursive. I'm using sbcl. Any help would be great.
No, it is not tail recursive. Neither ANSI Common Lisp says anything about it nor your code:
(defun collect (func args num)
(if (= 0 num)
()
(cons (apply func args)
(collect func args (- num 1)))))
If you look at your code, there is a CONS around your call to COLLECT. This CONS receives the value of the recursive call to COLLECT. So COLLECT can't be tail recursive. It's relatively simple to rewrite your function to something that looks tail recursive by introducing an accumulator variable. The various Lisp or Scheme literature should describe that.
In Common Lisp the default way to program an iterative computation is by using one of the several iterative constructs: DO, DOTIMES, DOLIST, LOOP, MAP, MAPCAR, ...
The Common Lisp standard does not provide tail call optimization (TCO). It would have to be specified what TCO should do in the presence of several other language features. For example dynamic binding and special variables have an effect on TCO. But the Common Lisp standard says simply nothing about TCO in general and about possible effects of TCO. TCO is not a part of the ANSI Common Lisp standard.
Several Common Lisp implementations have a way to enable various tail call optimizations with compiler switches. Note that both the way to enable those and the limitations are implementation specific.
Summary: In Common Lisp use iteration constructs and not recursion.
(defun collect (func args num)
(loop repeat num
collect (apply #'func args)))
Added bonus: it is easier to read.
Common Lisp implementations are not required by the ANSI standard to do tail call optimization; however, most that worth their salt (including SBCL) do optimize.
Your function, on the other hand, is not tail recursive. It can be turned into one by using the common trick of introducing an extra parameter for accumulating the intermediate result:
(defun collect (func args num)
(labels ((frob (n acc)
(if (= 0 n)
acc
(frob (1- n) (cons (apply func args) acc)))))
(frob num nil)))
(The original parameters FUNC and ARGS are eliminated in the local function since they are constant with recpect to it).
Well, the alternative to recursion is iteration.
You should know that Common Lisp does not require tail recursion from its implementors, unlike Scheme.
(defun mycollect (func args num)
(let ((accumulator '())) ; it's a null list.
(loop for i from 1 to num
do
;;destructively cons up the accumulator with the new result + the old accumulator
(setf accumulator
(cons (apply func args) accumulator)))
accumulator)) ; and return the accumulator