alternative indexing in nth

Started by cormullion, December 03, 2006, 09:18:22 AM

Previous topic - Next topic

cormullion

I'm getting confused again. If you have an 'index vector' reference to an element in a nested list:


(set 'lst (list (list 1 2 3) (list 'a 'b 'c)))
(set 'a-ref (ref 'a lst))

; a-ref is (1 0)


I know you can use implicit slicing with a-ref, which is sometimes what you want:


(lst a-ref)
;-> a


But can you use a-ref with nth (which is also sometimes what you want to do)?


(nth '''a-ref?''' lst)

apart from like this, of course:


(nth (first a-ref) (last a-ref) lst)
;-> a

Lutz

#1
Instead of:


(set 'lst (list (list 1 2 3) (list 'a 'b 'c)))


I would write:


(set 'lst '((1 2 3) (a b c)))

much easier to type and read and 3 times faster in execution.



Only 'push' and 'pop' and implicit indexing can take indices in a list. In the long run I want to eliminate 'nth' and the old syntax forms of set-nth and set-nth completely which don't use implicit indexing . This will eliminate confusion and streamline the implementation too.



Lutz



ps: I edited the title of this thread to indexing instead of slicing

cormullion

#2
Hi Lutz...



(btw I sometimes prefer the (list syntax) because it balances better in my editor! And sometimes newLISP is much faster than I need it to be so I don't worry about speed... :-))



But as to the implicit indexing: although I do use it, I have to say that sometimes that syntax doesn't quite satisfy me - perhaps i'm the only one(1) who thinks it can be harder to read than a clearer (func arg arg ...) syntax... I'd generally prefer the 'nth' syntax, and would prefer the nth syntax to be enhanced to take lists rather than disappear altogether!



But is there a way to do:


(nth (first a-ref) (last a-ref) lst)

more easily with every member of a-ref?



thanks!



(1) I seem to remember a comment from you Lutz about implicit indexing being harder to read... But i can't find it now!

Lutz

#3
... deleted my previoys post. I am trying to piggyback 'nth' on 'set-nth/nth-set', which already support the old and new list syntax, and even may save some code and gain speed. Possibly we may have the cake and eat it too ;). Not quite like you wanted but close, more details tomorrow.



Lutz

Lutz

#4
These are the additional syntax forms, all old forms still work:


(set 'L '((1 2 3) (a b c)))
(set 'aref (ref 'c L)) => (1 2)

; new for nth
(nth (L 1 2)) => c
(nth (L aref)) => c

; new for set-nth, nth-set
(set-nth (L aref) 99)  => ((1 2 3) (a b 99))
(nth-set (L aref) 99) => c


Leveraging exisiting code in 'set-nth/nth-set' the additional functionality was implemented by reducing code at the same time.



Lutz



ps: I am still thinking of eliminating the completely flat forms sometimes in the future.

cormullion

#5
Quote from: "Lutz"These are the additional syntax forms, all old forms still work:


Cool! Great work, thanks! Nearly as cool as (nth L aref) or (nth aref L)  :-)!


Quote from: "Lutz"ps: I am still thinking of eliminating the completely flat forms sometimes in the future.


I hope this is right at the bottom of your to-do list! I don't want to have to go through all my old code and use less readable syntax. More readable, I could cope with, perhaps! :-)



Personally I would prefer that implicit indexing always be an option for those who want extra speed and more compact code. I just don't find the way you can do this very pleasing - of course, other might think it's extra neat:


(set 'f '((a b d (1 2 3 ( x y z)))))
(f 1 2 3)
;-> d
(define (f x y z)
  (println (+ x y z)))
(f 1 2 3)
;-> 6


As Columbo used to say - "it's just one little thing that bothers me..."!

Lutz

#6
QuoteI hope this is right at the bottom of your to-do list!


If it happens at all, it would follow these steps:



(1) Discourage use in "Deprecated functions" chapter

(2) Stop documenting it

(3) Take it out.



newLISP went through many changes and deletions of functions or function names and I believe and hope nobody was hurt ;-). Wee need this mechanism to keep newLISP slim and agile. I will not take any action for the next one or two releases, if at all.



Let's just see how old and new useres understand and apply the different options.



Lutz

newdep

#7
Hooking on to set-nth nth-set...





Is it possible to make nth-set do this ->

(Im realy missing nested list sets via nth-set)



> (setq x '( ( a b c d e ) ( 1 2 3 4 5 )))

((a b c d e) (1 2 3 4 5))

> (nth-set 2 (flat x) "B")

c

> x

((a b c d e) (1 2 3 4 5))

>





The above only works is I would first set Y to (flat x) and then do the

nth-set to Y...But its far more charming to do the set in 1 step...isnt it ?





Why this request? because I often have nested lists but work on flat lists,

there is no index or order known... then nth-set / set-nth could simple

replace ...





Norman.
-- (define? (Cornflakes))

Lutz

#8
Not sure what you mean? You do have nested lists in 'nth-set' since many versions:


(setq x '( ( a b c d e ) ( 1 2 3 4 5 )))

(nth-set 0 2 x "B") => c
; or
(nth-set (x 0 2) "B") => c

; or starting in 9.0.6
(set 'aref (ref 'c x)) => (0 2)
(nth-set (x aref) "B") =>


Lutz

newdep

#9
Well... net-set and set-nth only work if you know which list-index you ought to be..



Im more refering to Single-indexing on nested lists. Like (nth-set 0 2 x "B") is a double-indexed function... here is a single indexed function -> (set-nth 0 (flat x) "B") , but that does not work...



nth-set and set-nth do not understand a referer to (flat x).. it only works if you set

x first to y and then do a straight (nth-set 0 y "b") instead of (nth-set 0 (flat x) B")





My point is acutaly that I expected (flat x) to be evaluated first , then set and then

evaluated back to the order of lists.. like ->





(setq x '( ( a b c ) ( 1 2 3 ) ( x y z))



(flat x) -> ( a b c 1 2 3 x y z )



(nth-set 0 (flat x) "B") -> ( "B" b c 1 2 3 x y z ) -> '( ( "B" b c ) ( 1 2 3 ) (x yz ))





Or do i mis someting from the fnuction list in newlisp? because there seems

not to be any quicker way to handle a single-indexed nested list set-nth...





Regards, Norman.
-- (define? (Cornflakes))

Lutz

#10
(flat x) is non-destructive and returns a new list on which set-nth will work. So you would have to do a (set 'x (flat x)) first.



But I don't understand why you would want to address a nested list with a single index? Then why not have the list flat in the first place?



Lutz

rickyboy

#11
Quote from: "Lutz"; new for nth
(nth (L 1 2)) => c
(nth (L aref)) => c

But that's the same as
(L 1 2) => c
(L aref) => c

So what does it buy us?



Also, this
Quote from: "Lutz"; new for set-nth, nth-set
(set-nth (L aref) 99)  => ((1 2 3) (a b 99))
(nth-set (L aref) 99) => c

looks like CL's SETF to me (barring the return values).  And actually the following makes more sense to me from a readability standpoint:
(setf (L aref) 99)

although again you don't have the option of return values which is the real cool feature of choosing between set-nth and nth-set (even though I always have to consult the manual over which does which).



And speaking of readability, I'm with cormullion (and Abelson and Sussman ("Programs must be written for people to read, and only incidentally for machines to execute.") and Perlis and Knuth, et cetera)-- I think it's a good idea to keep around the more readable forms of expression.  One of the strengths of newlisp is that, if you want, you can still write readable code.



--Rickyboy
(λx. x x) (λx. x x)

Lutz

#12
Yes, this:
; new for nth
(nth (L 1 2)) => c
(nth (L aref)) => c

and this:
(L 1 2) => c
(L aref) =>

offer the same functionality, and each one has some distinct advantages. The first one mirrors the syntax of 'set-nth' and 'nth-set' but without the  last new-value argument. The second is the shorter, faster implicit indexing.



And both forms have readability advantages depending on the situation and surrounding code used in.



The forms using and index-list 'aref' are specially usable in situations wher an index vector has been obtained from a previous: (ref <obj> <list>) expression. Previously only 'push' and 'pop' could make usage of index vectors, now all three in the 'nth' family can do it too.



Lutz

newdep

#13
Quote from: "Lutz"(flat x) is non-destructive and returns a new list on which set-nth will work. So you would have to do a (set 'x (flat x)) first.



But I don't understand why you would want to address a nested list with a single index? Then why not have the list flat in the first place?



Lutz




Well its more a matter of small code im my situation, newlisp is a language that unwillingly puts you into tighter code ;-)



I simply do it now with a destructive set, but is for me 1 step to much (another variable "set to dust" for only 1 cycle  ;-)



But no big deal Ill manage without the single indexed nested set-nth ;-)



Regards, Norman.
-- (define? (Cornflakes))

nikus80

#14
Mmm, I think you CAN single index a list. If we make a function which given a flat index returns a list that can be used with nth-set, we can easily write a macro as

(define-macro (nth-flat-set)

    (eval (append '(nth-set) (get-index (args 0) (eval (args 1))) (rest (args))))))....



the function we need to write is get-index, which given something like



(get-index 3 '(a b (c d e)))

returns the list (2 1).



We can write it recursively, walking down a list. if we hit an element which is also a list, we calculate its length. if this list can hold the rest of the index, we cons the current index with get-index called on the rest of the index and this list.



I tried writing such a function, but it doesn't work. I need some help...

(define (get-index ind lst , current)
   (set 'current 0)
   (catch
    (dolist (e lst)
     (cond
      (= current ind)
        (throw (list current)
      (list? (car e))
      (let (len (get-flat-lenght (car e)))
       (if (> (- ind current) len)
        (set 'current (+ len current))
        (throw (cons current (get-index (- ind current) (car e))))))
      (set 'current (+ current 1)))))))


(define (get-flat-length lst)
  (length (flat lst)))