the problem is: i've a list of lists of lists like this:
(((1 2) (3 4) (5 6)) ((7 8) (9 0)))
i've to write it in a file, where numbers in every list of lists is printed in a line like this:
.......
1 2 3 4 5 6
7 8 9 0
......
...... means that i can have more list of lists. I wonder how can I implement this without using loop and using with-open-file, format and recursion. between each number there's a space or tab and every list of sublist starts a new line.
Thanks
EDIT:
I've managed to print a sublist of (a b) on the same line with this code:
(defun write_pfs (filename point)
(with-open-file (str filename
:direction :output
:if-exists :append
:if-does-not-exist :create)
(format str (format nil "~~{~~a~~^~C~~}~T" #\Tab) point)))
(defun write_points (filename points)
(mapcar #'(lambda (x) (write_point filename x)) points))
but then i have no way to print each sublist of (((a b) (b c)) ((c d) (d e))) to a different line.
I would imagine you can make a helper function using labels inside the body of with-open-file so it has access to stream.
(with-open-file (stream path :direction :output)
(labels ((recursive-print (lst)
...)
(flatten (lst acc)
...)
...)
(recursive-print lst))))
Since this looks like homework I won't elaborate any more, however making several functions with labels that does separate things, like flatten, print-lines and print-elements makes the code easier to read and alter.
Related
Exercise 6.36 of David Touretzky's Common Lisp book asks for a function swap-first-last that swaps the first and last argument of any list. I feel really stupid right now, but I am unable to solve this with destructuring-bind.
How can I do what in Python would be first, *rest, last = (1,2,3,4) (iterable unpacking) in Common Lisp/with destructuring-bind?
After all trying out, and with some comments by #WillNess (thanks!) I came up with this idea:
macro bind
The idea is trying to subdivide the list and use the &rest functionality of the lambda list in destructuring-bind, however, using the shorter . notation - and using butlast and the car-last combination.
(defmacro bind ((first _rest last) expr &body body)
`(destructuring-bind ((,first . ,_rest) ,last)
`(,,(butlast expr) ,,(car (last expr)))
,#body)))
usage:
(bind (f _rest l) (list 1 2 3 4)
(list f _rest l))
;; => (1 (2 3) 4)
My original answer
There is no so elegant possibility like for Python.
destructuring-bind cannot bind more differently than lambda can: lambda-lists take only the entire rest as &rest <name-for-rest>.
No way there to take the last element out directly.
(Of course, no way, except you write a macro extra for this kind of problems).
(destructuring-bind (first &rest rest) (list 1 2 3 4)
(let* ((last (car (last rest)))
(*rest (butlast rest)))
(list first *rest last)))
;;=> (1 (2 3) 4)
;; or:
(destructuring-bind (first . rest) (list 1 2 3 4)
(let* ((last (car (last rest)))
(*rest (butlast rest)))
(list first *rest last)))
But of course, you are in lisp, you could theoretically write macros to
destructuring-bind in a more sophisticated way ...
But then, destructuring-bind does not lead to much more clarity than:
(defparameter *l* '(1 2 3 4))
(let ((first (car *l*))
(*rest (butlast (cdr *l*)))
(last (car (last *l*))))
(list first *rest last))
;;=> (1 (2 3) 4)
The macro first-*rest-last
To show you, how quickly in common lisp such a macro is generated:
;; first-*rest-last is a macro which destructures list for their
;; first, middle and last elements.
;; I guess more skilled lisp programmers could write you
;; kind of a more generalized `destructuring-bind` with some extra syntax ;; that can distinguish the middle pieces like `*rest` from `&rest rest`.
;; But I don't know reader macros that well yet.
(ql:quickload :alexandria)
(defmacro first-*rest-last ((first *rest last) expr &body body)
(let ((rest))
(alexandria:once-only (rest)
`(destructuring-bind (,first . ,rest) ,expr
(destructuring-bind (,last . ,*rest) (nreverse ,rest)
(let ((,*rest (nreverse ,*rest)))
,#body))))))
;; or an easier definition:
(defmacro first-*rest-last ((first *rest last) expr &body body)
(alexandria:once-only (expr)
`(let ((,first (car ,expr))
(,*rest (butlast (cdr ,expr)))
(,last (car (last ,expr))))
,#body))))
Usage:
;; you give in the list after `first-*rest-last` the name of the variables
;; which should capture the first, middle and last part of your list-giving expression
;; which you then can use in the body.
(first-*rest-last (a b c) (list 1 2 3 4)
(list a b c))
;;=> (1 (2 3) 4)
This macro allows you to give any name for the first, *rest and last part of the list, which you can process further in the body of the macro,
hopefully contributing to more readability in your code.
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
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 " ")
I have a list of lists as follows in Common Lisp of the form
((1 2) (3 4) (5 6))
and which is the value of the variable list, and I want to have three new variables whose values are the elements of the list. For instance:
list-1 (1 2)
list-2 (3 4)
list-3 (5 6)
Is there any function which does this operation?
Use setq, first (or nth and elt) to set:
(setq list-1 (first list)
list-2 (second list)
list-3 (third list))
Or destructuring-bind to bind:
(destructuring-bind (list-1 list-2 list-3) list
...)
Again, destructuring-bind binds the variables instead of assigning them (i.e., it is like let, not like setq).
The notion of binding elements of a list to names of the form list-# can be generalized.
You can create a function to generate a lambda with the ordinal list names as arguments, and a given body:
(defun make-list-lambda (n body)
(let ((list-names (loop for index from 1 to n
collect (intern (format nil "LIST-~D" index)))))
`(lambda ,list-names
(declare (ignorable ,#list-names))
,#body)))
And then create a macro to create the lambda, compile it, and apply it to the list:
(defmacro letlist (list &body body)
(let ((assignments (gensym)))
`(let ((,assignments ,list))
(apply (compile nil (make-list-lambda (length ,assignments) ',body))
,assignments))))
In this way, the assignments are localized to the lambda body:
CL-USER> (letlist '(a b c d e f)
(format t "list-1: ~A~%" list-1)
(format t "list-3: ~A~%" list-3))
list-1: A
list-3: C
NIL
Note: The forms will be compiled every time the macro is invoked, since it will not be known how many list-# arguments will be present until the list is presented!
First set your list to a variable, for instance mylist. Then spit out the required
output using the function format. I'm using CLISP. Hope this helps. This is the actual REPL output.
(setf mylist '((1 2) (3 4) (5 6)) )
((1 2) (3 4) (5 6))
(format t "list-1 ~d~%list-2 ~d~%list-3 ~d" (car mylist)
(second mylist) (last mylist))
list-1 (1 2)
list-2 (3 4)
list-3 ((5 6))
NIL
[142]>
Can someone show me how to get rid of "NIL' in the above output?
I'm new to Lisp. Just learning for fun.
If I write a file using
(with-open-file (s "~/example.sexp" :direction :output)
(write '(1 2 3) :stream s)
(write '(4 5 6) :stream s)
(write '(7 8 9) :stream s))
A file is created containing
(1 2 3)(4 5 6)(7 8 9)
But when I attempt to open and read it using
(setf f (open "~/example.sexp"))
(read :input-stream f)
I get an ":INPUT-STREAM is not of type STREAM" error.
(type-of f)
returns STREAM::LATIN-1-FILE-STREAM which looks like it is at least close to what I need. What is the difference?
How can I read the lists I've written to the file?
You got the arguments to READ wrong. It should be simply (read f), not (read :input-stream f).
You can also use with-open-file:
(with-open-file (s "~/example.sexp")
(read s))
Or even:
(with-open-file (*standard-input* "~/example.sexp")
(read))
:input is the default direction.