Page 1 of 1

List context - performance

Posted: Tue Sep 29, 2009 7:09 pm
by Tim Johnson
The more I use newlisp the more I like it. Mostly
I find 'append to be an exception. I have found myself coding a lot of

Code: Select all

(set 'res(append res (list "blah" "blah1" "blah2"))) ;; untested 
This begs (IMHO) for a "reconstructive" (or "destructive", I like "reconstructive" better)
function or a context.
I'd like to do something like

Code: Select all

(set 'lst (new list))
(lst:cat "blah" "blah1" "blah2" "...")

and I can and would be happy to write such a context. I realize that there could
be a performance penalty. I would welcome comments, both on where the
performance penalities would be greatest and whether I may possibly be
"barking up the wrong tree".
Thanks, Keep up the good work Lutz

Posted: Tue Sep 29, 2009 7:55 pm
by Jeff
You could always write a function that does (push item lst -1) and returns lst again.

Posted: Tue Sep 29, 2009 9:36 pm
by TedWalther
Jeff wrote:You could always write a function that does (push item lst -1) and returns lst again.
Doesn't push return lst already?

Posted: Tue Sep 29, 2009 9:44 pm
by cormullion
Hi Tim - if I read you right, you want either a 'flat push' or a 'destructive append'?

Code: Select all

(set 'r (list "start"))
(push (list "this" "is" "a" "list" "of" "strings") r -1)
(println r)
;-> ("start" ("this" "is" "a" "list" "of" "strings")) ; want flat list

(set 'r (list "start"))
(append r (list "this" "is" "a" "list" "of" "strings")) ; want this result in r ...
(println r)
;-> ("start")
I've wondered about this too! Haven't discovered the solution yet... Sometimes I try 'join' hoping that it works on two or more lists... But it never does :)

As for performance, a function should be pretty quick - esp if pass by reference?

Posted: Tue Sep 29, 2009 10:29 pm
by Lutz
would it be called 'adjoin' ?

Posted: Tue Sep 29, 2009 10:37 pm
by Jeff
TedWalther wrote:Doesn't push return lst already?
Nope. It returns the item pushed. You would need to use a macro to prevent the funcall from copying the list, though.
Lutz wrote:would it be called 'adjoin' ?
Or nconc

Posted: Tue Sep 29, 2009 10:46 pm
by Tim Johnson
Lutz wrote:would it be called 'adjoin' ?
From your manual, I've played with "redefining" protected symbols in contexts,
works good - so append could be re-used with an "object". Which I really like.
thanks

Posted: Wed Sep 30, 2009 12:14 am
by Tim Johnson
Following code is my starting point:

Code: Select all

(context 'lst)
(set 
	'context-name "lst"     ## name of context
	'object-name  "[none]"  ## name of object
	'data '()               ## list - holds data
	)
(define(dbg)
	(println "Class: " context-name 
	         " Name: " object-name
					 " Data: " data)
	)
(define (lst:clear) (set 'data '()))
(define (lst:++)
	(set 'data (append data (args))))
(context 'MAIN)
(define (lst! )
	(new lst 'newlst)
	(set 'newlst:data (rest(args))
		   'newlst:object-name (first (args))
		)
	newlst) 
FYI: 'context-name, 'object-name and 'dbg are standard boiler-plate for me.
This allows me to use an 'inspect function for debugging.
And using MAIN:lst! as an initializer with the stringizing symbol lends itself
handily (for me) to an editor macro
Console session:

Code: Select all

> (load "/home/http/run/newlisp/list.lsp")
(lambda () (new lst 'newlst) (set 'newlst:data (rest (args)) 'newlst:object-name
  (first (args))) newlst)
> (set 'l (lst! "l" "one" "two"))
newlst
> (l:dbg)
Class: lst Name: l Data: ("one" "two")

Posted: Wed Sep 30, 2009 12:15 am
by Lutz
Nope. It returns the item pushed.
Nope. It returns the list ;-)

Code: Select all

> (set 'lst '(b c d))
(b c d)               "
> (push 'a lst)
(a b c d)
> lst
(a b c d)
>  
This was changed in 10.0. The return value now is also a reference, so you can do destructive queues and cycles:

Code: Select all

> (set 'lst '(1 2 3 4 5))
(1 2 3 4 5)
> (push (pop lst -1) lst)
(5 1 2 3 4)
> (push (pop lst -1) lst)
(4 5 1 2 3)
> (push (pop lst -1) lst)
(3 4 5 1 2)
> (push (pop lst -1) lst)
(2 3 4 5 1)
> (push (pop lst -1) lst)
(1 2 3 4 5)
> 

Posted: Wed Sep 30, 2009 1:31 am
by Kazimir Majorinc
I have this in my library at www.instprog.com

Code: Select all

(map (lambda()
          (letn ((old-function-name (first (args))))
                (set (sym (append "setq"(string old-function-name)))
                     (expand '(lambda-macro()
                                  (set (first (args))
                                       (apply old-function-name
                                              (map eval (args)))))
                                   'old-function-name))

                (set (sym (append "set" (string old-function-name)))
                     (expand '(lambda-macro()
                                   (set (eval (first (args)))
                                        (apply old-function-name
                                              (map eval
                                                  (cons (eval (first (args)))
                                                        (rest (args)))))))
                               'old-function-name))

                (set (sym (append "setf" (string old-function-name)))
                     (expand '(lambda-macro()
                                  (eval
                                    (letex((x (first (args))))
                                       '(setf x (apply old-function-name
                                                      (map eval (args)))))))
                               'old-function-name))))



     '( + - * / % add mul sub div mod append max min and or))


(set 'x '(1 2 3 4))
(setfappend x '(39))
(println x) ; => (1 2 3 4 39)

(setf x 3)
(setfmax x 6)
(setf+ x 4)
(println x) ;=> 10
(exit)
set and setq versions are also defined.

Posted: Wed Sep 30, 2009 1:31 am
by TedWalther
Lutz wrote:
Nope. It returns the item pushed.
Nope. It returns the list ;-)
So, what is the right way to do this?

Code: Select all

(constant 'mc lambda-macro)

Posted: Wed Sep 30, 2009 11:54 am
by Lutz
The words 'lambda','fn' and 'lambda-macro', 'fn-macro' macro are not normal symbols/keywords and cannot be re-assigned. They mark a list as a special type of list (a lambda list). This is why:

Code: Select all

(length (lambda )) => 0) ; not 1

; and

(first (lambda (x y z))) => (x y z)

Posted: Wed Sep 30, 2009 4:52 pm
by Kazimir Majorinc
TedWalther wrote: So, what is the right way to do this?

Code: Select all

(constant 'mc lambda-macro)
This is what I used for some time:

Code: Select all

(set 'macro
    (lambda-macro()
        (eval (append '(lambda-macro) (args)))))

Posted: Wed Sep 30, 2009 5:36 pm
by cormullion
Nice code, guys... Interesting comparing the styles.

I was thinking that perhaps this extend would be a useful addition: taking perhaps an existing symbol and a list:

Code: Select all

(define-macro (extend s lst)
   (set s (append (eval s) (eval lst))))
   
(set 'p (sequence 1 5))
(extend p (sequence 6 10))
p
;-> (1 2 3 4 5 6 7 8 9 10)
(pretty untested... )

It would also be neat if it created the symbol (like push) if necessary.

Posted: Wed Sep 30, 2009 5:57 pm
by Tim Johnson
This is turning out to be a great thread. Lots of ideas for a great list context.
tj

Posted: Wed Sep 30, 2009 6:18 pm
by Jeff
Performance-wise, something like this would be simpler and faster:

Code: Select all

(define-macro (extend)
  (push (eval (args 1)) (eval (args 0)) -1))

(setf lst '(1 2))
(extend lst 3) ; => (1 2 3)
lst ; => (1 2 3)
(extend lst 4) ; => (1 2 3 4)
lst ; => (1 2 3 4)

Posted: Wed Sep 30, 2009 7:08 pm
by cormullion

Code: Select all

(push (eval (args 1)) (eval (args 0)) -1)
Clever stuff! Looks simple, but only after someone else does it... :)

Posted: Thu Oct 01, 2009 10:27 pm
by Tim Johnson
Using the approach that I describe above, I wrote a series of vimscript
functions that initialize an object such as I've shown interest in and shown
an example of:

Code: Select all

" ---------------------------------------------------------------------------------------
"  Given the variable name typed in, expands to a general set statement
" --------------------------------------------------------------------------------------
function! NewlispQuickSet()
 	let wrd=expand("<cWORD>")
	exe "norm! bdwa(set '" . wrd . " )\<Left>"
endfunction
" -----------------------------------------------------------------------------
" Given the variable name typed in, expands to a global initializer
" expression containing an initializer function
" Example: foo => (set 'foo (List! "foo"))
" ----------------------------------------------------------------------------
function! NewlispInitGlobalObject(o)
 	let w=expand("<cWORD>")
	exe "norm! bdwa(set '" . w . "(" . a:o . "! \"" . w . "\" ))\<Left>\<Left>"
endfunction
" ----------------------------------------------------------------------------
" Given the variable name typed in, expands to a local initializer
" as would be contained in a let() initializer expression
" Example: foo => (foo (List! "foo"))
" ---------------------------------------------------------------------------
function! NewlispInitLocalObject(o)
 	let w=expand("<cWORD>")
	exe "norm! bdwa(" . w . "(" . a:o . "! \"" . w . "\" ))\<Left>\<Left>"
endfunction
" --------------------------------------------------------------------
Note: The last two functions expand to a particular coding style, so
if you have stumbled across this, make sure to read my posts in this thread.
Also, for you vimmers, these functions are in turn called from functions which
are agnostic to the programming language.
so if you call them directly, then you'll need to add "a" to get back into
insert mode at the right place.
Key mapping examples:

Code: Select all

inoremap <T-Space>      <Esc>:call StdInitializeVariable()<CR>a
inoremap <F2>l      <Esc>:call StdInitGlobalList()<CR>a
inoremap <F2>m      <Esc>:call StdInitLocalList()<CR>a
Note <T-Space> That is the vimscript notation for the "Super" modifier" following
by "Space"
Thanks again for this thread. I'm going to rip off a whole lot of the examples
submitted for my List! context.
cheers
tim