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
(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
(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
You could always write a function that does (push item lst -1) and returns lst again.
Quote from: "Jeff"
You could always write a function that does (push item lst -1) and returns lst again.
Doesn't push return lst already?
Hi Tim - if I read you right, you want either a 'flat push' or a 'destructive append'?
(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?
would it be called 'adjoin' ?
Quote from: "TedWalther"
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.
Quote from: "Lutz"
would it be called 'adjoin' ?
Or nconc
Quote from: "Lutz"
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
Following code is my starting point:
(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:
> (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")
Quote
Nope. It returns the item pushed.
Nope. It returns the list ;-)
> (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:
> (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)
>
I have this in my library at www.instprog.com
(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.
Quote from: "Lutz"
Quote
Nope. It returns the item pushed.
Nope. It returns the list ;-)
So, what is the right way to do this?
(constant 'mc lambda-macro)
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:
(length (lambda )) => 0) ; not 1
; and
(first (lambda (x y z))) => (x y z)
Quote from: "TedWalther"
So, what is the right way to do this?
(constant 'mc lambda-macro)
This is what I used for some time:
(set 'macro
(lambda-macro()
(eval (append '(lambda-macro) (args)))))
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:
(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.
This is turning out to be a great thread. Lots of ideas for a great list context.
tj
Performance-wise, something like this would be simpler and faster:
(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)
Quote
(push (eval (args 1)) (eval (args 0)) -1)
Clever stuff! Looks simple, but only after someone else does it... :)
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:
" ---------------------------------------------------------------------------------------
" 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:
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