From: Tamas K Papp on 10 Apr 2010 05:45 Hi everyone, I wanted to define some syntactic sugar for array element access in an application. Fortunately CL is a Lisp2, so I can do something like (macrolet ((a (i) `(aref a ,i))) ...) but when I have this inside an ITER (an inner loop within an outer loop), ITERATE complains that it cannot walk the MACROLET. After reading the HS, I found a neat solution: (flet ((a (i) (aref a i)) ((setf a) (value i) (setf (aref a i) value))) ...) which works really nice. SBCL inlines the whole thing without further declarations. CL is indeed amazing. I can't think of any other language that would let me do this. I just have two questions: 1. if inside the body ... I have eg (incf (a (convoluted-index-calculation j))) is CONVOLUTED-INDEX-CALCULATION guaranteed to be called only once? When I macroexpand this form, I get (LET* ((#:TMP955 (CONVOLUTED-INDEX-CALCULATION J)) (#:G956 1) (#:NEW954 (+ (A #:TMP955) #:G956))) (FUNCALL #'(SETF A) #:NEW954 #:TMP955)) but is single evaluation guaranteed by the standard? Explanations and pointers to the relevant section in the HS would be appreciated (I know it is within 5.1, but could not find it). 2. If the elements of A (which is a vector) represent a matrix, arranged in a column-major order, I would use (flet ((a (i j) (aref a (+ (* j nrow) i))) ((setf a) (value i j) (setf (aref a (+ (* j nrow) i)) value))) ...) but then it is very likely that the (+ (* j nrow) i) calculation would happen twice. How can I avoid this without using local macros (which interfere with iterate and code walkers)? AFAIK SETF expanders can only be defined globally. Thanks, Tamas
From: Lieven Marchand on 10 Apr 2010 06:36 Tamas K Papp <tkpapp(a)gmail.com> writes: > I just have two questions: > > 1. if inside the body ... I have eg > > (incf (a (convoluted-index-calculation j))) > > is CONVOLUTED-INDEX-CALCULATION guaranteed to be called only once? > When I macroexpand this form, I get > > (LET* ((#:TMP955 (CONVOLUTED-INDEX-CALCULATION J)) > (#:G956 1) > (#:NEW954 (+ (A #:TMP955) #:G956))) > (FUNCALL #'(SETF A) #:NEW954 #:TMP955)) > > but is single evaluation guaranteed by the standard? Explanations and > pointers to the relevant section in the HS would be appreciated (I > know it is within 5.1, but could not find it). 5.1.1.1 2. For the macros that manipulate places (push, pushnew, remf, incf, decf, shiftf, rotatef, psetf, setf, pop, and those defined by define-modify-macro) the subforms of the macro call are evaluated exactly once in left-to-right order, with the subforms of the places evaluated in the order specified in (1).
From: Pascal J. Bourguignon on 10 Apr 2010 06:48 Tamas K Papp <tkpapp(a)gmail.com> writes: > Hi everyone, > > I wanted to define some syntactic sugar for array element access in an > application. Fortunately CL is a Lisp2, so I can do something like > > (macrolet ((a (i) > `(aref a ,i))) > ...) > > but when I have this inside an ITER (an inner loop within an outer > loop), ITERATE complains that it cannot walk the MACROLET. After > reading the HS, I found a neat solution: > > (flet ((a (i) > (aref a i)) > ((setf a) (value i) > (setf (aref a i) value))) > ...) > > which works really nice. SBCL inlines the whole thing without further > declarations. CL is indeed amazing. I can't think of any other > language that would let me do this. > > I just have two questions: > > 1. if inside the body ... I have eg > > (incf (a (convoluted-index-calculation j))) > > is CONVOLUTED-INDEX-CALCULATION guaranteed to be called only once? > When I macroexpand this form, I get > > (LET* ((#:TMP955 (CONVOLUTED-INDEX-CALCULATION J)) > (#:G956 1) > (#:NEW954 (+ (A #:TMP955) #:G956))) > (FUNCALL #'(SETF A) #:NEW954 #:TMP955)) > > but is single evaluation guaranteed by the standard? Explanations and > pointers to the relevant section in the HS would be appreciated (I > know it is within 5.1, but could not find it). Yes, it is specified that it should be evaluated only once. 5.1.1.1 says: 2. For the macros that manipulate places (push, pushnew, remf, incf, decf, shiftf, rotatef, psetf, setf, pop, and those defined by define-modify-macro) the subforms of the macro call are evaluated exactly once in left-to-right order, with the subforms of the places evaluated in the order specified in (1). > 2. If the elements of A (which is a vector) represent a matrix, arranged in > a column-major order, I would use > > (flet ((a (i j) > (aref a (+ (* j nrow) i))) > ((setf a) (value i j) > (setf (aref a (+ (* j nrow) i)) value))) > ...) > > but then it is very likely that the (+ (* j nrow) i) calculation would > happen twice. > AFAIK SETF expanders can only be defined globally. Indeed. > How can I avoid this without using local macros (which > interfere with iterate and code walkers)? (flet ((row-major-a (rm) (aref a rm)) ((setf row-major-a) (value rm) (setf (aref a rm) value)) (a-row-major-index (i j) (+ (* j nrow) i))) (incf (row-major-a (a-row-major-index i j)))) -- __Pascal Bourguignon__
From: Frode V. Fjeld on 10 Apr 2010 11:23 > Tamas K Papp <tkpapp(a)gmail.com> writes: > >> but is single evaluation guaranteed by the standard? Lieven Marchand <mal(a)wyrd.be> writes: > 5.1.1.1 2. For the macros that manipulate places (push, pushnew, remf, > incf, decf, shiftf, rotatef, psetf, setf, pop, and those defined by > define-modify-macro) the subforms of the macro call are evaluated > exactly once in left-to-right order, with the subforms of the places > evaluated in the order specified in (1). I believe also that much of the setf machinery is there to allow people to write setters that preserves left-to-right, single evaluation. I think that this aspect of CL is a great achievement in composability. -- Frode V. Fjeld
|
Pages: 1 Prev: blas, sgemm, cffi Next: celtk (+ Tcl/Tk Cells) now on github /and/ largely working on Linux |