Is there a clever way in SKILL to do somthing which sort of mixes the functionality of (foreach map....) with exists? I want the test applied to the cons cell, not to the car of the cons cell. As (foreach .... ) is to (exists ...) (foreach map ...) is to what? The exists function does not take an optional mapping function similar to foreach, but IF IT DID this is what i'd like to do. (exists map sub '(1 2 3 4 5 6 7) ((cadr map) > 3)) ---> (3 4 5 6 7) What's the most efficient/fastest way to do this? -jim
Probably: (prog () (foreach map sub '(1 2 3 4 5 6 7) (when (greaterp (cadr map) 3) (return sub)) ) ) I expect you can convert that into a macro yourself ;-> but here it is anyway: (defmacro abExistsExtend (mapFunc var lst @rest body) `(prog () (foreach ,mapFunc ,var ,lst (when ,(if (cdr body) `(progn ,@body) (car body)) (return ,var) ) ) ) e.g. (abExistsExtend map sub '(1 2 3 4 5 6 7) ((cadr sub)>3)) Regards, Andrew.
I also just found this example that I wrote in 1999 - Jim, I suspect it was you that asked me this then, because I can't imagine anyone else asking it! /* exists_map.il Author A.D.Beckett Group Custom IC (UK), Cadence Design Systems Ltd. Language SKILL Date Nov 02, 1999 Modified By A version of exists, which assigns the loop variable to the cdr of the list each time (like map). *************************************************** SCCS Info: @(#) exists_map.il 11/02/99.22:35:08 1.3 */ (defmacro exists_map (loop lst expr) `(let ((,loop ,lst)) (while (and ,loop (null ,expr)) (setq ,loop (cdr ,loop)) ) ,loop ) ) (defmacro exists_map2 (loop lst expr) `(prog () (map (lambda (,loop) (when ,expr return(,loop))) ,lst) ) ) /* this one doesn't work... (defmacro exists_map4 (loop lst expr) `(let (_ret) (map (lambda (,loop) (when ,expr (setq _ret (cons (car ,loop) (cdr ,loop))) (rplacd ,loop nil) )) ,lst) _ret ) ) */ ; when seems slightly faster in the loop - and and outside is faster! ; this version throws an error when it's done, which is caught for ; the return value (defmacro exists_map3 (loop lst expr) `(car (errset (and (map (lambda (,loop) (when ,expr (err ,loop))) ,lst) nil))) ) (defun test_map () (let (data) (for i 1 3000 (setq data (cons i data))) (profile 'time) ;(for i 1 1000 (exists_map3 x data car(x)<30)) (for i 1 4000 (exists_map2 x data nil)) (profileSummary) (profileReset) ) ) ; 3000 list, 4000 times, nil condition ; exists_map3 23.43 ; exists 6.08 ; exists_map 45.37 ; exists_map2 23.39 So looks like I did a fair bit of profiling at the time. Andrew. Andrew Beckett Principal European Technology Leader Cadence Design Systems, UK.
yes these are good solutions but the use of prog/return is not supported in scheme mode unfortunately... not sure why not but it is documented so. otherwise the other solutions seem to require that the entire list be traversed... or am i misreading it?
can the prog/return be replaced with some sort of goto? i know that go is supported in SKILL but i've never used it? Perhaps the macro could generate a label/go pair using gensym????
Hi Jim, No, the other solutions I posted don't traverse the whole list - one uses a while/cdr loop - and stops when it reaches the match. The other uses errset/err to jump out. Andrew. Andrew Beckett Principal European Technology Leader Cadence Design Systems, UK.
go() (yuck, I feel dirty even mentioning it) only works within a prog(), so that doesn't really help you.. BTW, I tried the first solution (using prog/return) in SKILL++, and it worked. Perhaps prog() doesn't give all the lexical scoping advantages that let() does, so perhaps that's why it's not "supported" in SKILL++? Andrew. Andrew Beckett Principal European Technology Leader Cadence Design Systems, UK.