How to convert a string to list using clisp? - lisp

How can i convert the string "1 2 3 4 5 6 7" into the list (1 2 3 4 5 6 7) elegantly? I am using CLISP.

Here is a recursive solution.
;Turns a string into a stream so it can be read into a list
(defun string-to-list (str)
(if (not (streamp str))
(string-to-list (make-string-input-stream str))
(if (listen str)
(cons (read str) (string-to-list str))
nil)))

You should use parse-integer in a loop.
For example, using loop:
(let ((string "1 2 3"))
(loop :for (integer position) := (multiple-value-list
(parse-integer string
:start (or position 0)
:junk-allowed t))
:while integer
:collect integer))
⇒ (1 2 3)
If you need better control about the splitting, use the split-sequence or cl-ppcre library.
If you need to parse more general number formats, use the parse-number library.
Libraries are available from Quicklisp.

Hint: Take a look at with-input-from-string.

(with-input-from-string (s "1 2 3 4 5 6 7" :index i :start 0 :end 13)
(list (read s) (read s) (read s) (read s) (read s) (read s)))
(1 2 3 4 5 6 7)
it works however i feel it is not so elegant as there are many read call .
thanks again!

I think this might work:
(setf s "1 2 3 4 5 6 7")
(setf L-temp (coerce s 'list))
This makes a list with spaces as elements. Remove spaces:
(setf L-final (remove #\Space L-temp))

I see that Svante is right. My previous attempt did not work. Here is another attempt. I use concatenate to change the string into a list representation. Then I use read-from-string to convert the string (s-2) into an actual list.
(setf s-0 "1 2 3 4 5 6 7")
(setf s-1 (concatenate 'string "(" s ")" ))
(setf s-2 (read-from-string s-1))
I roll it into a function like this:
(defun from-string-to-list (s)
(let ((L (read-from-string
(concatenate 'string "(" s ")"))))
L))
The only purpose of "let" and "L" is to make the function from-string-to-list return only the list and not return multiple values. read-from-string returns two values: The list and the size of the string, I think.

That would do,
(with-input-from-string (s "1 2 3 4 5")
(let ((r nil))
(do ((line (read s nil 'eof)
(read s nil 'eof)))
((eql line 'eof))
(push line r))
(reverse r)))

Related

Non destructive subsequence-except in lisp

I know subseq in lisp return a subsequence through a range. Is there anything which will return the subsequence except that range and should be non-destructive? Any help is appreciated.
You can do it for any sequence with concatenate and subseq:
(defun sequence-except (sequence start end)
(concatenate (sequence-type sequence)
(subseq sequence 0 start)
(subseq sequence end)))
The following should be enough to determine the type of the input sequence for bit-vectors, strings, etc:
(defun sequence-type (sequence)
(etypecase sequence
(list 'list)
(array `(array ,(array-element-type sequence) (*)))))
Tests:
(loop for test in (list
#*10101001
"abcd"
'(0 3 2)
nil
#(1 2 3 4)
(make-array 4
:adjustable t
:fill-pointer T
:initial-contents
'(a b c d)))
collect (concatenate (sequence-type test) test))
can't you just:
(defun seq-drop-subseq (SEQ START &optional END)
(if END
(nconc (seq-take START) (seq-drop END))
(seq-take START)))
edit: had to go look. remove does it.

Store list from file input stream, in a variable in LISP

I have lets say the following list in a .txt file
(5 3 1)
All i am trying with following source code is to store the above list in a variable in LISP. Until the first format everything seems right. But then i realize that *originalStateVar* is not getting treated as a list with 3 atoms but as a list with 1 atom. Source code follows:
(defvar *originalStateVar*)
(defun fileInput ()
(let ((i 1)(in (open *originalStateLocation* :if-does-not-exist nil)))
(when in
(loop
for line = (read-line in nil)
while line do
(format t "~a~%" line) ;debug line
(format t "i is <~a>~%" i) ;debug line
(setf *originalStateVar* (list line)) ;storing list in variable
(setf i (+ i 1))) ;debug line
(close in))
(format t "originalStateVar is <~a>" (car *originalStateVar*))
(format t "second element originalStateVar is <~a>~%" (cadr *originalStateVar*))
(format t "third element originalStateVar is <~a>~%" (caddr *originalStateVar*))))
The output of the above code though is:
(5 3 1)
i is <1>
first element originalStateVar is <(5 3 1)>
second element originalStateVar is <NIL>
third element originalStateVar is <NIL>
All i can tell is that it stores the (5 3 1) as a single atom in a list, so it becomes something like ((5 3 1)) and that's why cadr returns NIL.
Any help on how to make *originalStateVar* get treated that way, would be greatly appreciated!
use WITH-OPEN-FILE instead of OPEN
use READ instead of READ-LINE
Example:
CL-USER 11 > (let ((*read-eval* nil))
(with-open-file (in "/tmp/test.data")
(read in)))
(1 2 3)
CL-USER 12 > (let ((*read-eval* nil))
(with-open-file (in "/tmp/test.data")
(describe (read in))))
(1 2 3) is a LIST
0 1
1 2
2 3

Can a Lisp read procedure read this and how?

I'm writing a grammar which I intend to implement in a Lisp read procedure, i.e. reading one expression at a time from an input source which is i.e. mutable. Most of the grammar is just like Lisp, but the two pertinent changes are:
Whitespace is read and is part of the resulting syntax. Contiguous whitespace is grouped together like contiguous non-whitespace characters are grouped as identifiers, and the result of reading such a string is a "whitespace object", which stores the exact sequence of characters read. The evaluator ignores whitespace objects when they appear in a list (in other words, if foo is a whitespace object then (eval '(+ 3 foo 4)) is equivalent to (eval '(+ 3 4))), and if it is asked to evaluate one directly, it is self-evaluating.
Secondly, if several tokens other than whitespace tokens appear on the same line, those tokens are collected into a list and that list is the result of the read.
e.g.,
+ 3 4 5
(+ 3 4 5)
+ 3 4 (+ 1 4)
(+ 3 4 (+ 1 4))
all produce the value 12.
Is it possible to implement this reader as a Lisp read procedure that follows the typical expectations of a read procedure? If so, how? (I'm at a loss.)
Edit: Clarification on whitespace:
If we say that a "whitespace object" is simply a string and read, then reading the following segment:
(foo bar baz)
produces a syntax object like:
'(foo " " bar " " baz)
In other words, the whitespace between tokens is stored in the resultant syntax object.
Suppose I write a macro named ->, which takes a syntax object (scheme style macro), and whitespace? is a predicate identifying whitespace syntax objects
(define-macro (-> stx)
(let* ((stxl (syntax-object->list stx))
(obj (car stxl))
(let proc ((res empty))
(lst (cdr stxl)))
(let ((method (car lst)))
(if (whitespace? method)
; skip whitespace, recur immediately
(proc res (cdr lst))
; Insert obj as the second element in method
(let ((modified-method (cons (car method)
(cons obj (cdr method)))))
; recur
(proc (cons res modified-method) (cdr lst))))))))
The reading part of this is pretty easy. You just need a whitespace test, and then your reading function will install a custom reader character macro that detects whitespace and reads consecutive sequences of whitespace into a single object. First, the whitespace test and a whitespace object; these are pretty simple:
(defparameter *whitespace*
#(#\space #\tab #\return #\newline)
"A vector of whitespace characters.")
(defun whitespace-p (char)
"Returns true if CHAR is in *WHITESPACE*."
(find char *whitespace* :test 'char=))
(defstruct whitespace-object
characters)
Now the macro character function:
(defun whitespace-macro-char (stream char)
"A macro character function that consumes characters from
stream (including CHAR), until a non-whitespace character (or end of
file) is encountered. Returns a whitespace-object whose characters
slot contains a string of the whitespace characters."
(let ((chars (loop for c = (peek-char nil stream nil #\a)
while (whitespace-p c)
collect (read-char stream))))
(make-whitespace-object
:characters (coerce (list* char chars) 'string))))
Now the read function just has the same signature as the normal read, but copies the readtable, then installs the macro function, and calls read. The result from read is returned, and the readtable is restored:
(defun xread (&optional (stream *standard-input*) (eof-error-p t) eof-value recursive-p)
"Like READ, but called with *READTABLE* bound to a readtable in
which each whitespace characters (that is, each character in
*WHITESPACE*) is a macro characters whose macro function is
WHITESPACE-MACRO-CHAR."
(let ((rt (copy-readtable)))
(map nil (lambda (wchar)
(set-macro-character wchar #'whitespace-macro-char))
*whitespace*)
(unwind-protect (read stream eof-error-p eof-value recursive-p)
(setf *readtable* rt))))
Example:
(with-input-from-string (in "(+ 1 2 (* 3
4))")
(xread in))
(+ #S(WHITESPACE-OBJECT :CHARACTERS " ") 1
#S(WHITESPACE-OBJECT :CHARACTERS " ") 2
#S(WHITESPACE-OBJECT :CHARACTERS " ")
(* #S(WHITESPACE-OBJECT :CHARACTERS " ") 3
#S(WHITESPACE-OBJECT
:CHARACTERS "
")
4))
Now, to implement the eval counterpart that you want, you need to be able to remove whitespace objects from lists. This isn't too hard, and we can write a slightly more general utility function to do it for us:
(defun remove-element-if (predicate tree)
"Returns a new tree like TREE, but which contains no elements in an
element position which ssatisfy PREDICATE. An element is in element
position if it is the car of some cons cell in TREE."
(if (not (consp tree))
tree
(if (funcall predicate (car tree))
(remove-element-if predicate (cdr tree))
(cons (remove-element-if predicate (car tree))
(remove-element-if predicate (cdr tree))))))
CL-USER> (remove-element-if (lambda (x) (and (numberp x) (evenp x))) '(+ 1 2 3 4))
(+ 1 3)
CL-USER> (with-input-from-string (in "(+ 1 2 (* 3
4))")
(remove-element-if 'whitespace-object-p (xread in)))
(+ 1 2 (* 3 4))
So now the evaluation function is a simple wrapper around eval:
(defun xeval (form)
(eval (remove-element-if 'whitespace-object-p form)))
CL-USER> (with-input-from-string (in "(+ 1 2 (* 3
4))")
(xeval (xread in)))
15
Let's make sure that standalone whitespace objects still appear as expected:
CL-USER> (with-input-from-string (in " ")
(let* ((exp (xread in))
(val (xeval exp)))
(values exp val)))
#S(WHITESPACE-OBJECT :CHARACTERS " ")
#S(WHITESPACE-OBJECT :CHARACTERS " ")

reduce using cl-loop facility

CL library manual "map over sequences" says "All of these mapping operations can be expressed conveniently in terms of the cl-loop macro" but I don't see how cl-reduce can be expressed in terms of cl-loop
Not sure how "conveniently" expressed it is, but here's my take on it:
(defun loop-reduce (func sequence &rest initial-element)
(loop with result =
(or (car initial-element)
(prog1 (car sequence)
(setf sequence (cdr sequence))))
for x in sequence do (setf result (funcall func result x))
finally (return result)))
(loop-reduce '+ '(1 2 3 4 5))
;; 15
(loop-reduce '+ '(1 2 3 4 5) 10)
;; 25

Name of this function in built-in Emacs Lisp library?

The following Emacs Lisp function takes a list of lists and returns a list in which the items of the inner lists have been concatenated to one big list. It is pretty straight-forward and I am convinced something like this must already be part of the standard function library.
(defun flatten (LIST)
(if LIST
(append (car LIST) (flatten (cdr LIST)))
nil))
I am looking for a function that will take a single list of lists as its argument and then append all the inner lists.
(flatten '((a b) (c d)))
will give
(a b c d)
Does anyone know whether this function is already built in, and if so, under which name?
Thanks!
You're either looking for append:
(defun flatten (list-of-lists)
(apply #'append list-of-lists))
If (and only if) you know that you'll always have a list of lists.
Otherwise:
(defun flatten (list)
(mapcan (lambda (x) (if (listp x) x nil)) list))
Emacs 27.1 has flatten-tree:
(flatten-tree '((a b) (c d)))
(a b c d)
See: https://www.gnu.org/software/emacs/manual/html_node/elisp/Building-Lists.html
I stepped into this only recently whilst looking for something different; there is something that might not have been put into evidence by the test data utilized to check the function, depending on whether the original question was meant to refer to generic lists (i.e.: list of list of list of list of...) or just to two-level lists (as in the example).
The solution based on append works fine only with two-level lists, and there is a further issue with the solution based on mapcan.
Basically, the general solution has to be recursive both on car and cdr, as in the flatten defun below.
(setq l '((((1 2) 3) 4) (5 6 7)))
(defun flatten(x)
(cond ((null x) nil)
((listp x) (append (flatten (car x)) (flatten (cdr x))))
(t (list x))))
(defun flatten2(l)
(if l (append (car l) (flatten2 (cdr l))) nil))
(defun flatten3(l)
(mapcan (lambda(x) (if (listp x) x nil)) l))
(flatten l)
(1 2 3 4 5 6 7)
(apply #'append l)
(((1 2) 3) 4 5 6 7)
(flatten2 l)
(((1 2) 3) 4 5 6 7)
The further issue is with the usage of mapcan in flatten3: as mapcan hides an nconc inside, the user must remember that it alters its argument.
l
((((1 2) 3) 4) (5 6 7))
(flatten3 l)
(((1 2) 3) 4 5 6 7)
l
((((1 2) 3) 4 5 6 7) (5 6 7))
Dash is a modern list library for Emacs, and has flatten. It's the second most downloaded package on Melpa, after magit. From the readme:
-flatten (l): Takes a nested list l and returns its contents as a single, flat list.
(-flatten '((1))) ;; => '(1)
(-flatten '((1 (2 3) (((4 (5))))))) ;; => '(1 2 3 4 5)
(-flatten '(1 2 (3 . 4))) ;; => '(1 2 (3 . 4))
-flatten-n (num list): Flatten num levels of a nested list.
(-flatten-n 1 '((1 2) ((3 4) ((5 6))))) ;; => '(1 2 (3 4) ((5 6)))
(-flatten-n 2 '((1 2) ((3 4) ((5 6))))) ;; => '(1 2 3 4 (5 6))
(-flatten-n 3 '((1 2) ((3 4) ((5 6))))) ;; => '(1 2 3 4 5 6)
This package was started 2012-09.
I realize that the original question was "what is the built in function". It appears that there is none. The other solutions do not actually flatten all lists that I tested. This function appears to work. I'm posting it here because this was the first place Google hit when I did my search.
(defun flatten (LIST)
"flattens LIST"
(cond
((atom LIST) (list LIST))
((null (cdr LIST)) (flatten (car LIST)))
(t (append (flatten (car LIST)) (flatten (cdr LIST))))))
e.g.
(flatten (list "a" (list "b" "c" nil) (list (list "d" "e") "f")))
("a" "b" "c" nil "d" "e" "f")
Have a look at nconc