unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* Contribution to SES (resend)
@ 2010-04-22  6:52 Vincent Belaïche
  2010-04-22 21:54 ` Stefan Monnier
  0 siblings, 1 reply; 9+ messages in thread
From: Vincent Belaïche @ 2010-04-22  6:52 UTC (permalink / raw)
  To: emacs-devel

Dear all,

I would like to make a contribution to SES, a user of which I am.

Here is the Change log which I propose:


--8<-------------coupez ici--------------début-------------->8---
2010-04-22  Vincent Belaïche  <vincentb1@users.sourceforge.net>

	* ses.el (ses-list): Addition of the ses-list macro in order to
	have more flexibility for range building. This also makes `ses+'
	kind of obsolete as `(apply 'ses+ (ses-range A1 A5))' can be
	replaced by `(apply '+ (ses-list A1 A5 !))' which is more
	universal as you could have anything instead of `+'.
--8<-------------coupez ici---------------fin--------------->8---

And here is a diff -c old new of ses.el:


--8<-------------coupez ici--------------début-------------->8---
*** ses.el.old	Wed Apr 21 21:34:40 2010
--- ses.el	Thu Apr 22 06:47:27 2010
***************
*** 141,146 ****
--- 141,147 ----
  (defconst ses-mode-edit-map
    (let ((keys '("\C-c\C-r"    ses-insert-range
  		"\C-c\C-s"    ses-insert-ses-range
+ 		"\C-c\C-v"    ses-insert-ses-list
  		[S-mouse-3]   ses-insert-range-click
  		[C-S-mouse-3] ses-insert-ses-range-click
  		"\M-\C-i"     lisp-complete-symbol))
***************
*** 1085,1091 ****
         ((ses-sym-rowcol cur)
  	;;Save this reference
  	(add-to-list 'result-so-far cur))
!        ((eq (car-safe cur) 'ses-range)
  	;;All symbols in range are referenced
  	(dolist (x (cdr (macroexpand cur)))
  	  (add-to-list 'result-so-far x)))
--- 1086,1092 ----
         ((ses-sym-rowcol cur)
  	;;Save this reference
  	(add-to-list 'result-so-far cur))
!        ((memq (car-safe cur) '(ses-list ses-range))
  	;;All symbols in range are referenced
  	(dolist (x (cdr (macroexpand cur)))
  	  (add-to-list 'result-so-far x)))
***************
*** 1144,1150 ****
  	    ;;implies 'delete.
  	    (unless ses-relocate-return
  	      (setq ses-relocate-return 'delete))))
! 	 ((eq (car-safe cur) 'ses-range)
  	  (setq cur (ses-relocate-range cur startrow startcol rowincr colincr))
  	  (if cur
  	      (push cur result)))
--- 1145,1151 ----
  	    ;;implies 'delete.
  	    (unless ses-relocate-return
  	      (setq ses-relocate-return 'delete))))
! 	 ((memq (car-safe cur) '(ses-list ses-range))
  	  (setq cur (ses-relocate-range cur startrow startcol rowincr colincr))
  	  (if cur
  	      (push cur result)))
***************
*** 1159,1175 ****
        (nreverse result))))
  
  (defun ses-relocate-range (range startrow startcol rowincr colincr)
!   "Relocate one RANGE, of the form '(ses-range min max).  Cells starting
! at (STARTROW,STARTCOL) are being shifted by (ROWINCR,COLINCR).  Result is the
! new range, or nil if the entire range is deleted.  If new rows are being added
! just beyond the end of a row range, or new columns just beyond a column range,
! the new rows/columns will be added to the range.  Sets `ses-relocate-return'
! if the range was altered."
    (let* ((minorig   (cadr range))
  	 (minrowcol (ses-sym-rowcol minorig))
  	 (min       (ses-relocate-symbol minorig minrowcol
  					 startrow startcol
  					 rowincr colincr))
  	 (maxorig   (nth 2 range))
  	 (maxrowcol (ses-sym-rowcol maxorig))
  	 (max       (ses-relocate-symbol maxorig maxrowcol
--- 1160,1179 ----
        (nreverse result))))
  
  (defun ses-relocate-range (range startrow startcol rowincr colincr)
!   "Relocate one RANGE, of the form '(ses-range min max) or
! '(ses-list min max ...).  Cells starting at (STARTROW,STARTCOL)
! are being shifted by (ROWINCR,COLINCR).  Result is the new range,
! or nil if the entire range is deleted.  If new rows are being
! added just beyond the end of a row range, or new columns just
! beyond a column range, the new rows/columns will be added to the
! range.  Sets `ses-relocate-return' if the range was altered."
    (let* ((minorig   (cadr range))
  	 (minrowcol (ses-sym-rowcol minorig))
  	 (min       (ses-relocate-symbol minorig minrowcol
  					 startrow startcol
  					 rowincr colincr))
+ 	 (rest (cdddr range))
+ 	 (fun (car range))
  	 (maxorig   (nth 2 range))
  	 (maxrowcol (ses-sym-rowcol maxorig))
  	 (max       (ses-relocate-symbol maxorig maxrowcol
***************
*** 1228,1234 ****
  		 (funcall field (ses-sym-rowcol min))))
  	  ;;This range has changed size
  	  (setq ses-relocate-return 'range))
!       (list 'ses-range min max))))
  
  (defun ses-relocate-all (minrow mincol rowincr colincr)
    "Alter all cell values, symbols, formulas, and reference-lists to relocate
--- 1232,1238 ----
  		 (funcall field (ses-sym-rowcol min))))
  	  ;;This range has changed size
  	  (setq ses-relocate-return 'range))
!       `( ,fun ,min ,max @,rest))))
  
  (defun ses-relocate-all (minrow mincol rowincr colincr)
    "Alter all cell values, symbols, formulas, and reference-lists to relocate
***************
*** 2823,2841 ****
  					    ,(cdr ses--curcell))))))
      (insert (substring (prin1-to-string (nreverse x)) 1 -1))))
  
! (defun ses-insert-ses-range ()
!   "Inserts \"(ses-range x y)\" in the minibuffer to represent the currently
! highlighted range in the spreadsheet."
!   (interactive "*")
    (let (x)
      (with-current-buffer (window-buffer minibuffer-scroll-window)
        (ses-command-hook)  ;For ses-coverage
        (ses-check-curcell 'needrange)
!       (setq x (format "(ses-range %S %S)"
  		      (car ses--curcell)
  		      (cdr ses--curcell))))
      (insert x)))
  
  (defun ses-insert-range-click (event)
    "Mouse version of `ses-insert-range'."
    (interactive "*e")
--- 2827,2859 ----
  					    ,(cdr ses--curcell))))))
      (insert (substring (prin1-to-string (nreverse x)) 1 -1))))
  
! (defun ses--insert-ses-range-or-ses-list (to-be-inserted)
!   "Insert \"(ses-range x y)\" or \"(ses-list x y)\" into the
!   minibuffer depending on TO-BE-INSERTED being equal to \"range\"
!   or to \"list\"."
    (let (x)
      (with-current-buffer (window-buffer minibuffer-scroll-window)
        (ses-command-hook)  ;For ses-coverage
        (ses-check-curcell 'needrange)
!       (setq x (format "(ses-%s %S %S)"
! 		      to-be-inserted
  		      (car ses--curcell)
  		      (cdr ses--curcell))))
      (insert x)))
  
+ (defun ses-insert-ses-range ()
+   "Inserts \"(ses-range x y)\" in the minibuffer to represent the currently
+ highlighted range in the spreadsheet."
+   (interactive "*")
+   (ses--insert-ses-range-or-ses-list "range"))
+ 
+ (defun ses-insert-ses-list ()
+   "Inserts \"(ses-list x y)\" in the minibuffer to represent the currently
+ highlighted range in the spreadsheet."
+   (interactive "*")
+   (ses--insert-ses-range-or-ses-list "list"))
+ 
+ 
  (defun ses-insert-range-click (event)
    "Mouse version of `ses-insert-range'."
    (interactive "*e")
***************
*** 2890,2901 ****
    "Expands to a list of cell-symbols for the range.  The range automatically
  expands to include any new row or column inserted into its middle.  The SES
  library code specifically looks for the symbol `ses-range', so don't create an
! alias for this macro!"
    (let (result)
      (ses-dorange (cons from to)
        (push (ses-cell-symbol row col) result))
      (cons 'list result)))
  
  (defun ses-delete-blanks (&rest args)
    "Return ARGS reversed, with the blank elements (nil and *skip*) removed."
    (let (result)
--- 2908,3030 ----
    "Expands to a list of cell-symbols for the range.  The range automatically
  expands to include any new row or column inserted into its middle.  The SES
  library code specifically looks for the symbol `ses-range', so don't create an
! alias for this macro!
! 
! Cells are listed in reverse order, that is to say from TO up to
! FROM, for instance `(ses-range A1 B2)' will produce (B2 B1 A2
! A1). This is important to know if you make a formula like `(apply
! '- (ses-range A1 A5))'."
    (let (result)
      (ses-dorange (cons from to)
        (push (ses-cell-symbol row col) result))
      (cons 'list result)))
  
+ (defun ses--clean-! (&rest x)
+   "Clean by delq list X from any occurrence of `nil' or `*skip*'"
+   (delq nil (delq '*skip* x)))
+ 
+ (defun ses--clean-!x (x y)
+   "Clean list X  by replacing by Y any occurrence of `nil' or `*skip*'.
+    This will change X by making setcar on its cons cells."
+   (let ((ret x) ret-elt)
+     (while ret
+       (setq ret-elt (car ret))
+       (when (memq ret-elt '(nil *skip*))
+ 	(setcar ret y))
+       (setq ret (cdr ret))))
+   x)
+ 
+ (defsubst ses--clean-!0 (&rest x) 
+   "Clean list X by replacing by 0  any occurrence of `nil' or `*skip*'.
+    This will change X by making setcar on its cons cells."
+   (ses--clean-!x x 0))
+ (defsubst ses--clean-!. (&rest x) 
+   "Clean list X by replacing by \"\"  any occurrence of `nil' or `*skip*'.
+    This will change X by making setcar on its cons cells."
+   (ses--clean-!x x ""))
+ 
+ (defmacro ses-list (from to &rest rest)
+   "Expands to a list of cell-symbols for the range groing from
+ FROM up to TO.  The range automatically expands to include any
+ new row or column inserted into its middle.  The SES library code
+ specifically looks for the symbol `ses-list', so don't create an
+ alias for this macro!
+ 
+ By passing in REST some flags one can configure the way the range
+ is read and how it is formatted. 
+ 
+ In the sequel we assume that cells A1, B1, A2 B2 have respective values
+ 1 2 3 and 4 for examplication.
+ 
+ A `>v' (default) `>^', `<v', `<^', `v>', `v<', `^>', `^<' flag
+ will configure the order of browsing through the range. This
+ way `(ses-list A1 B2 ^>)' will evaluate to `(1 3 2 4)',
+ while `(ses-list A1 B2 >^)' will evaluate to (3 4 1 2).
+ 
+ A `!' flag will remove all cells whose value is nil or `*skip*'
+ while `!0' will replace them by 0, and `!.' will replace them by
+ \"\".
+ 
+ A `*', `*1' or `*2' flag will vectorize the range in the sense of
+ Calc. See info node `(Calc) Top'. Flag `*' will output either a
+ vector or a matrix depending on the number of rows, `*1' will
+ flatten the result to a one row vector, and `*2' will make a
+ matrix whatever the number of rows. 
+ 
+ Warning: interaction with Calc is expermimental and may produce
+ confusing results if you are not aware of Calc data format. Use
+ `math-format-value' as a printer for Calc objects."
+   (let (result-row result (prev-row -1)
+ 		   reorient-x reorient-y transpose vectorize 
+ 		   (clean 'list))
+     (ses-dorange (cons from to)
+       (when (/= prev-row row)
+ 	(push result-row result)
+ 	(setq result-row nil))
+       (push (ses-cell-symbol row col) result-row)
+       (setq prev-row row))
+     (push result-row result)
+     (dolist (x rest)
+       (let ((s  (assq x `((>v setq transpose nil reorient-x nil reorient-y nil)
+ 			  (>^ setq transpose nil reorient-x nil reorient-y t) 
+ 			  (<^ setq transpose nil reorient-x t reorient-y t) 
+ 			  (<v setq transpose nil reorient-x t reorient-y nil)   
+ 			  (v> setq transpose t reorient-x nil reorient-y t)     
+ 			  (^> setq transpose t reorient-x nil reorient-y nil)   
+ 			  (^< setq transpose t reorient-x t reorient-y nil) 
+ 			  (v< setq transpose t reorient-x t reorient-y t)   
+ 			  (*  . #1=(setq vectorize x))
+ 			  (*2 . #1#)
+ 			  (*1 . #1#)
+ 			  (! setq clean 'ses--clean-!)
+ 			  (!0 setq clean 'ses--clean-!0)
+ 			  (!. setq clean 'ses--clean-!\.) ))))
+ 	(if s (eval (cdr s))
+ 	  (error "Unexpected flag `%S' in ses-list" x))))
+ 
+     (if reorient-y 
+ 	(setcdr (last result 2) nil)
+       (setq result (cdr (nreverse result))))
+     (unless reorient-x
+       (setq result (mapcar 'nreverse result)))
+     (when transpose
+       (let ((ret (mapcar (lambda (x) (list x)) (pop result))) iter)
+ 	(while result
+ 	  (setq iter ret)
+ 	  (dolist (elt (pop result))
+ 	    (setcar iter (cons elt (car iter)))
+ 	    (setq iter (cdr iter))))
+ 	(setq result ret)))
+ 
+     (eval (cdr (assq vectorize
+ 		     '((nil cons clean (apply 'append result))
+ 		       (*1 . #2=(cons clean (cons (quote 'vec) (apply 'append result))))
+ 		       (*2 . #3=(cons clean (cons (quote 'vec) (mapcar (lambda (x) 
+ 									 (cons  clean (cons (quote 'vec) x)))
+ 								       result))))
+ 		       (* if (cdr result) #3# #2#)))))))
+ 
+ 
  (defun ses-delete-blanks (&rest args)
    "Return ARGS reversed, with the blank elements (nil and *skip*) removed."
    (let (result)
***************
*** 2932,2938 ****
      (cons 'list result)))
  
  ;;All standard formulas are safe
! (dolist (x '(ses-cell-value ses-range ses-delete-blanks ses+ ses-average
  	     ses-select))
    (put x 'side-effect-free t))
  
--- 3061,3067 ----
      (cons 'list result)))
  
  ;;All standard formulas are safe
! (dolist (x '(ses-cell-value ses-range ses-list ses-delete-blanks ses+ ses-average
  	     ses-select))
    (put x 'side-effect-free t))
  

--8<-------------coupez ici---------------fin--------------->8---


Very best regards,

   Vincent.






^ permalink raw reply	[flat|nested] 9+ messages in thread

* RE: Contribution to SES (resend)
@ 2010-04-22  7:56 Vincent Belaïche
  0 siblings, 0 replies; 9+ messages in thread
From: Vincent Belaïche @ 2010-04-22  7:56 UTC (permalink / raw)
  To: emacs-devel


Just to add that I would make also an update to the manual in accordance
with this submission, after it is agreed/modified/corrected through this
list.

  Vincent.

> From: vincent.b.1@hotmail.fr
> To: emacs-devel@gnu.org
> Date: Thu, 22 Apr 2010 08:52:51 +0200
> Subject: Contribution to SES (resend)
>
> Dear all,
>
> I would like to make a contribution to SES, a user of which I am.
>
> Here is the Change log which I propose:
>

[...]







^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Contribution to SES (resend)
  2010-04-22  6:52 Vincent Belaïche
@ 2010-04-22 21:54 ` Stefan Monnier
  0 siblings, 0 replies; 9+ messages in thread
From: Stefan Monnier @ 2010-04-22 21:54 UTC (permalink / raw)
  To: Vincent Belaïche; +Cc: emacs-devel

> I would like to make a contribution to SES, a user of which I am.

I like it, but I have a few comments:
- What's the difference btw ses-range and ses-list?  I mean, ses-list
  seems like a superset, so why not extend ses-range instead?
- Hmmm.... #N= + #N# in source code ... I'd rather avoid it.
- Do we really need to distinguish ^> from >^ when the user can just
  (reverse ...) the result?  I guess it's OK.
- please use `case' rather than assq+eval (I usually dislike `eval').
- The !0 and !. should be replaced by a single flag that comes with
  the default value to use.
- I'm not convinced I like those special symbols (but I don't have
  a good counter-proposition either).


        Stefan




^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Contribution to SES (resend)
@ 2010-04-23  5:24 Vincent Belaïche
  2010-04-23  6:24 ` Stefan Monnier
  0 siblings, 1 reply; 9+ messages in thread
From: Vincent Belaïche @ 2010-04-23  5:24 UTC (permalink / raw)
  To: emacs-devel

Thanks for your kind feedback.

>> I would like to make a contribution to SES, a user of which I am.
>
>I like it, but I have a few comments:
>- What's the difference btw ses-range and ses-list?  I mean, ses-list
>  seems like a superset, so why not extend ses-range instead?

This was my orginal idea, but then I thought that ses-range being a
slightly faster implementation, it might be valuable to keep it. 

Actually the very main reason for both to coexist is that the default
orientation for ses-range is `<^', while the default for ses-list is
`>v'. I find it very convenient to have >v because this is the usual
orientation in the Western world (even though this is not universal, I
am a westerner after all). And all spreadsheets I know have cell (0,0)
in the top left corner, so it is good to have this orientation by
default.

On the other hand, some people might have already used ses-range with
`apply' of non commutative operators, so changing the orientation of
ses-range is not backward compatible. I don't think it would be a good
idea.

In a nutshell, this is why some ses-range + ses-list co-existance is
needed.

Maybe there could be some message like "ses-range" is deprecated, use
"ses-list", and some function to replaced all (ses-range X Y) by
(ses-list X Y <^). I don't know. Maybe some people want to keep the
speed and code simplicity of ses-range (but how faster is ses-range over
ses-list ?)

>- Hmmm.... #N= + #N# in source code ... I'd rather avoid it.

Does the compiler factorize code well ? If yes I am OK to make that
change, although duplication of code is *EVIL*, and too many defsubst
may not be a good idea either (for it creates an intern symbol memory
overhead).

On the other hand the only reason for those #N= #N# is to make `or''s,
so if I replace (see your next comment) `(eval (assq ...))' by `(cond
...)', I would just do or's or eq's.

>- Do we really need to distinguish ^> from >^ when the user can just
>  (reverse ...) the result?  I guess it's OK.

Well, we have to keep in mind that simple emacs speadsheet documents,
and spreadsheet documents in general, are often quick hacks, and should
remain so. A complex spreadsheet is very hard to maintain, when you
reach this complexity limit of ease of maintenance it is better to make
some small script program for the same purpose. This is one reason why I
like SES, it obliges you too make only simple spread sheets.

So, having said that, I frankly prefer to type `(ses-list X Y >^)' than
`(nreverse (ses-list X Y <v))'. BTW `^>' is not the reverse of
`>^'. Take the following example:

 | 1 | 2 |
 |---+---|
 | 3 | 4 |
 
^> readout is (3 1 4 2), and >^ readout is (3 4 1 2).


>- please use `case' rather than assq+eval (I usually dislike `eval').

Do you mean `cond', not `case' ? Please clarify.

Why do you dislike `eval' ? (I am a curious one).

The motivation for the assq was that I thought it was faster than a
cond, because the eq is done in C.

>- The !0 and !. should be replaced by a single flag that comes with
>  the default value to use.

OK, I like your idea. So `!' could be to remove nil and *skip* and `_ 0'
would replace them by 0, and, if `_' is last, default of default would
be 0. Would this be fine (notably `_' to mean blanking by some default).

>- I'm not convinced I like those special symbols (but I don't have
>  a good counter-proposition either).
>

Please feel free to make one. I was thinking first of taking the picture
orientation symbols > < ^ . / \ ' and `. But then I find that those I
proposed are easier to understand: you don't read a table in diagonal,
don't you (I don't know whether you can say that in English "lire en
diagonale", to mean "read without carefull attention").

Maybe we could also have those shorthands :

 | one letter symbol | meaning |
 |-------------------+---------|
 | >                 | >v      |
 | <                 | <v      |
 | v                 | v>      |
 | ^                 | ^>      |
 
Would this make sense (notably for one row, or one col tables where you
don't care the other direction) ?

>
>        Stefan
>
>

I will wait for your feedback, and that we converge one some conclusion
before making any updates (including texinfo manual).

  Vincent.

PS: I have not yet tested the rellocation is not broken, this was a
first disclosure to get feedback on the idea.






^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Contribution to SES (resend)
  2010-04-23  5:24 Vincent Belaïche
@ 2010-04-23  6:24 ` Stefan Monnier
  0 siblings, 0 replies; 9+ messages in thread
From: Stefan Monnier @ 2010-04-23  6:24 UTC (permalink / raw)
  To: Vincent Belaïche; +Cc: emacs-devel

> This was my orginal idea, but then I thought that ses-range being a
> slightly faster implementation, it might be valuable to keep it. 

I don't think the speed difference is significant enough to warrant
the duplication.

> Actually the very main reason for both to coexist is that the default
> orientation for ses-range is `<^', while the default for ses-list is
> `>v'. I find it very convenient to have >v because this is the usual
> orientation in the Western world (even though this is not universal, I
> am a westerner after all). And all spreadsheets I know have cell (0,0)
> in the top left corner, so it is good to have this orientation by
> default.

And a different default doesn't seem like a strong enough
justification either.  You can easily add >v to your uses if you prefer it.

Please just change the default of ses-list to be compatible with
ses-range and rename it to ses-range (a more informative name,
methinks).

>> - Hmmm.... #N= + #N# in source code ... I'd rather avoid it.
> Does the compiler factorize code well ?

It doesn't.  And if you use #N=...#N# to make cyclic code, it will
happily loop forever.

> BTW `^>' is not the reverse of `>^'.

Yes, the multi-dimensional case probably justifies the complexity.

>> - please use `case' rather than assq+eval (I usually dislike `eval').
> Do you mean `cond', not `case' ? Please clarify.

No, I mean `case'.  It's a CL macro.

> Why do you dislike `eval' ? (I am a curious one).

Because it hides code from the compiler.

>> - The !0 and !. should be replaced by a single flag that comes with
>> the default value to use.
> OK, I like your idea. So `!' could be to remove nil and *skip* and `_ 0'
> would replace them by 0, and, if `_' is last, default of default would
> be 0. Would this be fine (notably `_' to mean blanking by some default).

That sounds OK, yes.

>> - I'm not convinced I like those special symbols (but I don't have
>> a good counter-proposition either).
> Please feel free to make one. I was thinking first of taking the picture
> orientation symbols > < ^ . / \ ' and `. But then I find that those I
> proposed are easier to understand: you don't read a table in diagonal,
> don't you (I don't know whether you can say that in English "lire en
> diagonale", to mean "read without carefull attention").

> Maybe we could also have those shorthands :

>  | one letter symbol | meaning |
>  |-------------------+---------|
>  | >                 | >v      |
>  | <                 | <v      |
>  | v                 | v>      |
>  | ^                 | ^>      |
 
> Would this make sense (notably for one row, or one col tables where you
> don't care the other direction) ?

These are still special symbols, so they're not any better, in my opinion.


        Stefan




^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Contribution to SES (resend)
@ 2010-04-23 17:45 Vincent Belaïche
  2010-04-23 18:14 ` Stefan Monnier
  0 siblings, 1 reply; 9+ messages in thread
From: Vincent Belaïche @ 2010-04-23 17:45 UTC (permalink / raw)
  To: emacs-devel



[...]

>
>I don't think the speed difference is significant enough to warrant
>the duplication.
>
>> Actually the very main reason for both to coexist is that the default
>> orientation for ses-range is `<^', while the default for ses-list is

[...]

>
>And a different default doesn't seem like a strong enough
>justification either.  You can easily add >v to your uses if you prefer it.
>

OK, would you mind if there was some customizable variable
ses-range-default-flags to hold a list of flags to copy by default to
minibuffer when you insert a range. I really hate the <^ direction, and
I find it painful to type every time this >v flag as you suggest.

>> Does the compiler factorize code well ?
>
>It doesn't.  And if you use #N=...#N# to make cyclic code, it will
>happily loop forever.
>

I am not perverse enough (yet) to make any cyclic code for sure, just
code factorization to diminish memory footprint of functions. Saving
memory is not too bad an idea. Isn't it ? 

Or, in other words, what is the alternative proper way that you propose
to save the same amount of memory without the #N= & #N# constructs.

[...]

>>> - please use `case' rather than assq+eval (I usually dislike `eval').
>> Do you mean `cond', not `case' ? Please clarify.
>
>No, I mean `case'.  It's a CL macro.
>

OK I will learn that. Thanks for the tip.

>> Why do you dislike `eval' ? (I am a curious one).
>
>Because it hides code from the compiler.
>

OK, I didn't know that: this is a a very good reason not to use
it. Thank you for teaching me this one. One has to be kind with those
little things that compilers are.

>>> - The !0 and !. should be replaced by a single flag that comes with
>>> the default value to use.
>> OK, I like your idea. So `!' could be to remove nil and *skip* and `_ 0'
>> would replace them by 0, and, if `_' is last, default of default would
>> be 0. Would this be fine (notably `_' to mean blanking by some default).
>
>That sounds OK, yes.
>
Fine. 
>
>> Maybe we could also have those shorthands :
>
>>  | one letter symbol | meaning |
>>  |-------------------+---------|
>>  | >                 | >v      |

[...]

>
>These are still special symbols, so they're not any better, in my opinion.
>

Yes, I did not expect that you would find them any better. My question
was rather whether adding them would be any worse ? I think that having
said that matrix reduction (to speak Calc-ese) is most often in one
single dimension, having those symbols also does not make things worse,
on the contrary.

>
>        Stefan

I will prepare another post with the following corrections:

1. use ses-range only (no separate function)

2. use case instead of eval+assq

For the other discussion items (#N=&#N#, flag symbols, default flags), I
am waiting for more feedback (sorry to be hard to convince sometimes).

  Vincent.






^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Contribution to SES (resend)
  2010-04-23 17:45 Contribution to SES (resend) Vincent Belaïche
@ 2010-04-23 18:14 ` Stefan Monnier
  0 siblings, 0 replies; 9+ messages in thread
From: Stefan Monnier @ 2010-04-23 18:14 UTC (permalink / raw)
  To: Vincent Belaïche; +Cc: emacs-devel

>> And a different default doesn't seem like a strong enough
>> justification either.  You can easily add >v to your uses if you prefer it.

> OK, would you mind if there was some customizable variable
> ses-range-default-flags to hold a list of flags to copy by default to
> minibuffer when you insert a range. I really hate the <^ direction, and
> I find it painful to type every time this >v flag as you suggest.

Fine by me, as long as it only affects the function that inserts the
"(ses-range ...)" string.
Of course, maybe we could change the default ordering of ses-range.
IIUC it was chosen arbitrarily (the result of the implementation rather
than of design, AFAICT) and I expect that very few users of ses-range
depend on this ordering.

>>> Does the compiler factorize code well ?
>> It doesn't.  And if you use #N=...#N# to make cyclic code, it will
>> happily loop forever.
> I am not perverse enough (yet) to make any cyclic code for sure, just
> code factorization to diminish memory footprint of functions. Saving
> memory is not too bad an idea. Isn't it ? 

> Or, in other words, what is the alternative proper way that you propose
> to save the same amount of memory without the #N= & #N# constructs.

Using #N=..#N# in code won't save memory because the byte-compiler will
treat each #N# as a separate copy.  In your case, you used it inside
data rather than inside code, so it's less harmful and it does
save memory.  But in your particular situation, the use of `case' lets
you share the code just as easily.

> Yes, I did not expect that you would find them any better.  My question
> was rather whether adding them would be any worse ?

No, it'd be OK.


        Stefan





^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Contribution to SES (resend)
@ 2010-04-24 19:35 Vincent Belaïche
  0 siblings, 0 replies; 9+ messages in thread
From: Vincent Belaïche @ 2010-04-24 19:35 UTC (permalink / raw)
  To: emacs-devel, Stefan Monnier, Jay P Belanger

[-- Attachment #1: Type: text/plain, Size: 2668 bytes --]

Hello Stef & al.

[...]

>
>Fine by me, as long as it only affects the function that inserts the
>"(ses-range ...)" string.

That was my intention.

>Of course, maybe we could change the default ordering of ses-range.
>IIUC it was chosen arbitrarily (the result of the implementation rather
>than of design, AFAICT) and I expect that very few users of ses-range
>depend on this ordering.
>

This would be acceptable to me, but we should ensure backward
compatibility: we could raise `SES file format' to 3, and if the file
format is < 3, then all (ses-range X Y) in the sheet would be replaced
by (ses-range X Y <^). I can correct this submission in that respect if
this principle is agreed.

>
>Using #N=..#N# in code won't save memory because the byte-compiler will
>treat each #N# as a separate copy. 


[...]

I removed most of them, but for some I did not find a proper way to
factorise code without those constructs.
>
>No, it'd be OK.
>
>
>        Stefan

Thanks,

Here is a corrected ses.el + proposed Changelog with the following
changes:

1. no co-existance ses-range + ses-list, but extension of ses-range
   instead.

2. (eval (cdr (assq ...))) replaced by (case ...)

3. shorthand flags > < v ^ for one-dimensional ranges

4. _ flag to replace empty cells, with next item specifying the
   replacement value.

Please note the following:

1. There are still some #N= ... #N# construct (any idea welcome, how to
   remove them with keeping factorization and w/o using eval ---
   duplication of code seems to me more evil than using those construct.

2. I did not implemented the defcustom for flags to auto-insert at range
   insertion, I will do this in a subsequent submission.

3. How to change ses-range default readout direction is still open.

4. For this subsequent submission, I think it may be good to go even
   further with Calc interworking. Jay: your opinion is welcome. We
   could have in addition of vectorization some more of Calc packing,
   like building complex numbers from two cells. You could have for
   instance A1 -- D2 like this:

   | 1 | 2 | 3 | 4 |
   | 5 | 6 | 7 | 8 |

   and (ses-range A1 D2 >v ** cx) would yield 

   [[ (1, 2), (3, 4)][(5, 6), (7, 8)]]

   flag **, **1 and **2 would mean vectorization+packing, flag *- would
   mean packing only, so that (ses-range A1 D2 >v *- cx) would yield:

   ( (cplx 1 2) (cplx 3 4) (cplx 5 6) (cplx 7 8))

   packing type would be identified by some flag following **, **1, **2
   or *- like this:

   - cplx, cx or 1 => cartesian complex number

   - polar, pr, or 2 => polar complex number

   - hms, hs, or 3 => hms forms

   - etc...

   
Any feedback welcome.

   Vincent.


[-- Attachment #2: Contribution to ses (ses-range) --]
[-- Type: application/octet-stream, Size: 2200 bytes --]

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Contribution to SES (resend)
@ 2010-06-20 17:34 Vincent Belaïche
  0 siblings, 0 replies; 9+ messages in thread
From: Vincent Belaïche @ 2010-06-20 17:34 UTC (permalink / raw)
  To: emacs-devel, Stefan Monnier, Jonathan Yavner

[-- Attachment #1: Type: text/plain, Size: 811 bytes --]

Hello,

I just wanted to know what the status of my contribution is.

To my recollection we had agreed that it was not an issue to change the
default order of cells returned by ses-range, because this order was not
documented, so anyhow it was not safe to rely on any specific order.

There was also that Stefan did not wanted the #N= ... #N# construct, I
had removed most of them. Here is attached an update with *all* of them
removed by using an flet --- so SES will need cl. Hopefully this will
not make the code less efficient

Now the only remaining open point was that Jonathan did not like the
`v>' kind of unevaluated symbols, I proposed to replace `v>' by `:v>',
sorry if there was an answer, I missed it.

I would be happy if we could conclude on this, and have this
contribution agreed.

  Vincent.


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: Updated contribution with removal of #N= ... #N# constructs --]
[-- Type: text/x-patch, Size: 6531 bytes --]

*** ses.el.old	Wed Apr 21 21:34:40 2010
--- ses.el	Sun Jun 20 17:17:06 2010
***************
*** 1,4 ****
! ;;; ses.el -- Simple Emacs Spreadsheet  -*- coding: utf-8 -*-
  
  ;; Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
  ;;   Free Software Foundation, Inc.
--- 1,4 ----
! ;; ses.el -- Simple Emacs Spreadsheet  -*- coding: utf-8 -*-
  
  ;; Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
  ;;   Free Software Foundation, Inc.
***************
*** 41,47 ****
  ;;; Code:
  
  (require 'unsafep)
! 
  
  ;;----------------------------------------------------------------------------
  ;; User-customizable variables
--- 41,47 ----
  ;;; Code:
  
  (require 'unsafep)
! (eval-when-compile (require 'cl))
  
  ;;----------------------------------------------------------------------------
  ;; User-customizable variables
***************
*** 2886,2900 ****
  ;; Standard formulas
  ;;----------------------------------------------------------------------------
  
! (defmacro ses-range (from to)
!   "Expands to a list of cell-symbols for the range.  The range automatically
! expands to include any new row or column inserted into its middle.  The SES
! library code specifically looks for the symbol `ses-range', so don't create an
! alias for this macro!"
!   (let (result)
      (ses-dorange (cons from to)
!       (push (ses-cell-symbol row col) result))
!     (cons 'list result)))
  
  (defun ses-delete-blanks (&rest args)
    "Return ARGS reversed, with the blank elements (nil and *skip*) removed."
--- 2886,3015 ----
  ;; Standard formulas
  ;;----------------------------------------------------------------------------
  
! (defun ses--clean-! (&rest x)
!   "Clean by delq list X from any occurrence of `nil' or `*skip*'"
!   (delq nil (delq '*skip* x)))
! 
! (defun ses--clean-_ (x y)
!   "Clean list X  by replacing by Y any occurrence of `nil' or `*skip*'.
!    This will change X by making setcar on its cons cells."
!   (let ((ret x) ret-elt)
!     (while ret
!       (setq ret-elt (car ret))
!       (when (memq ret-elt '(nil *skip*))
! 	(setcar ret y))
!       (setq ret (cdr ret))))
!   x)
! 
! (defmacro ses-range (from to &rest rest)
!   "Expands to a list of cell-symbols for the range groing from
! FROM up to TO.  The range automatically expands to include any
! new row or column inserted into its middle.  The SES library code
! specifically looks for the symbol `ses-range', so don't create an
! alias for this macro!
! 
! By passing in REST some flags one can configure the way the range
! is read and how it is formatted. 
! 
! In the sequel we assume that cells A1, B1, A2 B2 have respective values
! 1 2 3 and 4 for examplication.
! 
! Readout direction is specified by a `>v', '`>^', `<v', `<^',
! `v>', `v<', `^>', `^<' flag. For historical reasons, in absence
! of such a flag, a default direction of `^<' is assumed. This
! way `(ses-range A1 B2 ^>)' will evaluate to `(1 3 2 4)',
! while `(ses-range A1 B2 >^)' will evaluate to (3 4 1 2).
! 
! If the range is one row, then `>' can be used as a shorthand to
! `>v' or `>^', and `<' to `<v' or `<^'.
! 
! If the range is one column, then `v' can be used as a shorthand to
! `v>' or `v<', and `^' to `^>' or `v<'.
! 
! A `!' flag will remove all cells whose value is nil or `*skip*'.
! 
! A `_' flag will replace nil or `*skip*' by the value following
! the `_' flag. If the `_' flag is the last argument, then they are
! replaced by integer 0.
! 
! A `*', `*1' or `*2' flag will vectorize the range in the sense of
! Calc. See info node `(Calc) Top'. Flag `*' will output either a
! vector or a matrix depending on the number of rows, `*1' will
! flatten the result to a one row vector, and `*2' will make a
! matrix whatever the number of rows. 
! 
! Warning: interaction with Calc is expermimental and may produce
! confusing results if you are not aware of Calc data format. Use
! `math-format-value' as a printer for Calc objects."
!   (let (result-row 
! 	result 
! 	(prev-row -1)
! 	(reorient-x t) 
! 	(reorient-y t) 
! 	transpose vectorize 
! 	(clean 'list))
      (ses-dorange (cons from to)
!       (when (/= prev-row row)
! 	(push result-row result)
! 	(setq result-row nil))
!       (push (ses-cell-symbol row col) result-row)
!       (setq prev-row row))
!     (push result-row result)
!     (while rest
!       (let ((x (pop rest)))
! 	(case x
! 	  ((>v) (setq transpose nil reorient-x nil reorient-y nil))
! 	  ((>^)(setq transpose nil reorient-x nil reorient-y t))
! 	  ((<^)(setq transpose nil reorient-x t reorient-y t))
! 	  ((<v)(setq transpose nil reorient-x t reorient-y nil))
! 	  ((v>)(setq transpose t reorient-x nil reorient-y t))
! 	  ((^>)(setq transpose t reorient-x nil reorient-y nil))
! 	  ((^<)(setq transpose t reorient-x t reorient-y nil))
! 	  ((v<)(setq transpose t reorient-x t reorient-y t))
! 	  ((* *2 *1) (setq vectorize x))
! 	  ((!) (setq clean 'ses--clean-!))
! 	  ((_) (setq clean `(lambda (&rest x) (ses--clean-_  x ,(if rest (pop rest) 0)))))
! 	  (t
! 	   (cond
! 					; shorthands one row 
! 	    ((and (null (cddr result)) (memq x '(> <))) 
! 	     (push (intern (concat (symbol-name x) "v")) rest))
! 					; shorthands one col
! 	    ((and (null (cdar result)) (memq x '(v ^))) 
! 	     (push (intern (concat (symbol-name x) ">")) rest))
! 	    (t (error "Unexpected flag `%S' in ses-range" x)))))))
!     (if reorient-y 
! 	(setcdr (last result 2) nil)
!       (setq result (cdr (nreverse result))))
!     (unless reorient-x
!       (setq result (mapcar 'nreverse result)))
!     (when transpose
!       (let ((ret (mapcar (lambda (x) (list x)) (pop result))) iter)
! 	(while result
! 	  (setq iter ret)
! 	  (dolist (elt (pop result))
! 	    (setcar iter (cons elt (car iter)))
! 	    (setq iter (cdr iter))))
! 	(setq result ret)))
! 
!     (flet ((vectorize-*1 
! 	    (clean result) 
! 	    (cons clean (cons (quote 'vec) (apply 'append result))))
! 	   (vectorize-*2
! 	    (clean result) 
! 	    (cons clean (cons (quote 'vec) (mapcar (lambda (x) 
! 						     (cons  clean (cons (quote 'vec) x)))
! 						   result)))))
!       (cons clean (cons (quote 'vec) (apply 'append result)))
!       (case vectorize
! 	(nil (cons clean (apply 'append result)))
! 	(*1 (vectorize-*1 clean result))
! 	(*2 (vectorize-*2 clean result))
! 	(* (if (cdr result)  
! 	       (vectorize-*2 clean result)
! 	     (vectorize-*1 clean result)))))))
! 
! 
  
  (defun ses-delete-blanks (&rest args)
    "Return ARGS reversed, with the blank elements (nil and *skip*) removed."

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2010-06-20 17:34 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-04-23 17:45 Contribution to SES (resend) Vincent Belaïche
2010-04-23 18:14 ` Stefan Monnier
  -- strict thread matches above, loose matches on Subject: below --
2010-06-20 17:34 Vincent Belaïche
2010-04-24 19:35 Vincent Belaïche
2010-04-23  5:24 Vincent Belaïche
2010-04-23  6:24 ` Stefan Monnier
2010-04-22  7:56 Vincent Belaïche
2010-04-22  6:52 Vincent Belaïche
2010-04-22 21:54 ` Stefan Monnier

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).