how to return an association list

Notices and updates
Locked
cormullion
Posts: 2038
Joined: Tue Nov 29, 2005 8:28 pm
Location: latiitude 50N longitude 3W
Contact:

how to return an association list

Post by cormullion »

Is it possible to return an association list from a function? Here's a test:

Code: Select all

(define (test)
	(local (a b c)
	(set 'a 1)
	(set 'b 2)
	(set 'c 3)
	(set 'sum (+ a b c))
       '(("a" a) ("b" b) ("c" c) ("sum" sum))
	))

(println (lookup "sum" (test)))
I think this is a newbie question... :-)

Lutz
Posts: 5289
Joined: Thu Sep 26, 2002 4:45 pm
Location: Pasadena, California
Contact:

Post by Lutz »

Yes, a small change does it:

Code: Select all

(define (test)
 (letex (a 1 b 2 c 3)
    (letex (sum (+ a b c)) 
     '(("a" a) ("b" b) ("c" c) ("sum" sum)) )
   ) )

(test) -> (("a" 1) ("b" 2) ("c" 3) ("sum" 6))
Lutz

cormullion
Posts: 2038
Joined: Tue Nov 29, 2005 8:28 pm
Location: latiitude 50N longitude 3W
Contact:

Post by cormullion »

Thanks, Lutz. I think i get it - the symbols need expanding before their values are lost?

But I'd like to use the (local) construction, and avoid those two nested letexes which are too unintuitive for me to remember... :-) Can I use expand while building an assoc list?

Code: Select all

(define (test)
	(local (a b c)
	(set 'a 1)
	(set 'b 2)
	(set 'c 3)
	(set 'sum (+ a b c))
	(expand (list a b c))))
	
will return (1 2 3).

Lutz
Posts: 5289
Joined: Thu Sep 26, 2002 4:45 pm
Location: Pasadena, California
Contact:

Post by Lutz »

Like this?

Code: Select all

(define (test)
   (letn (a 1 b 2 c 3 sum (+ a b c))
    (expand '(("a" a) ("b" b) ("c" c) ("sum" sum)) 'a 'b 'c 'sum)))

(test)  -> (("a" 1) ("b" 2) ("c" 3) ("sum" 6))
Lutz

cormullion
Posts: 2038
Joined: Tue Nov 29, 2005 8:28 pm
Location: latiitude 50N longitude 3W
Contact:

Post by cormullion »

yes, that looks better .... ;-)

thanks


PS quiet round here isn't it?

Fanda
Posts: 253
Joined: Tue Aug 02, 2005 6:40 am
Contact:

Post by Fanda »

Lutz wrote:

Code: Select all

(define (test)
 (letex (a 1 b 2 c 3)
    (letex (sum (+ a b c)) 
     '(("a" a) ("b" b) ("c" c) ("sum" sum)) )
   ) )

(test) -> (("a" 1) ("b" 2) ("c" 3) ("sum" 6))
This makes me think - maybe we could create a new 'letexn' :-)

Code: Select all

(define (test)
 (letexn (a 1 b 2 c 3 sum (+ a b c))
   '(("a" a) ("b" b) ("c" c) ("sum" sum)) ))
Fanda

Fanda
Posts: 253
Joined: Tue Aug 02, 2005 6:40 am
Contact:

Post by Fanda »

Another solution:

Code: Select all

(define (test)
  (letn (a 1 b 2 c 3 sum (+ a b c))
    (list (list "a" a) (list "b" b) (list "c" c) (list "sum" sum))))
Fanda

cormullion
Posts: 2038
Joined: Tue Nov 29, 2005 8:28 pm
Location: latiitude 50N longitude 3W
Contact:

Post by cormullion »

thanks Fanda. I think this is the one I shall use:

Code: Select all

(define (test) 
   (local (a b c sum)
    (set 'a 1 'b 2 'c 3 'sum (+ a b c))
    (list (list "a" a) (list "b" b) (list "c" c) (list "sum" sum))))

(println (lookup "sum" (test)))
It reads nicely... ;-)

m i c h a e l
Posts: 394
Joined: Wed Apr 26, 2006 3:37 am
Location: Oregon, USA
Contact:

Post by m i c h a e l »

cormullion!

With the addition of the pair function:

Code: Select all

(constant (global 'pair) (fn (lst) 
  (array-list (array (/ (length lst) 2) 2 lst))))
You can bum it even more:

Code: Select all

(define (test) 
  (local (a b c sum) 
  (set 'a 1 'b 2 'c 3 'sum (+ a b c)) 
  (pair (list "a" a "b" b "c" c "sum" sum))))
pair. Never leave home without it ;-)

m i c h a e l

cormullion
Posts: 2038
Joined: Tue Nov 29, 2005 8:28 pm
Location: latiitude 50N longitude 3W
Contact:

Post by cormullion »

Welcome back, mm. :-) But what does pair do? - why is it using arrays?

m i c h a e l
Posts: 394
Joined: Wed Apr 26, 2006 3:37 am
Location: Oregon, USA
Contact:

Post by m i c h a e l »

I've never really been away. Just went back to my more natural wallflower mode ;-)

pair was taken from the Code Snippets page on newLISP.org.

pair turns this: (1 2 3 4 5 6 7 8 9 10) into this: ((1 2) (3 4) (5 6) (7 8) (9 10)).

As to "why the arrays," you'll have to ask the original author about that one :-)

m i c h a e l

cormullion
Posts: 2038
Joined: Tue Nov 29, 2005 8:28 pm
Location: latiitude 50N longitude 3W
Contact:

Post by cormullion »

It looks like the Hand of Fanda...

Probably using arrays for speed...

It's one of those situations where you kind of want the functionality to be already there - you don't want to define other functions just to get your existing functions to work the way you want them to. But you have to draw the line somewhere. And besides, we're supposed to be bending the language to suit our application, so perhaps it's a good thing to do.

Fanda
Posts: 253
Joined: Tue Aug 02, 2005 6:40 am
Contact:

Post by Fanda »

I am not sure, who made a 'pair' function, but lets guess... Lutz? ;-)

Be careful - pair is losing it's elements, if they are not even:
> (pair '(1 2 3 4))
((1 2) (3 4))
> (pair '(1 2 3))
((1 2))

I like group: (group lst [n] [keep-tail])

Code: Select all

(define (group lst (n 2) (keep-tail true))
  (set 'lst (map (lambda (i) (slice lst i n)) (sequence 0 (- (length lst) 1) n)))
  (if (and (not keep-tail) (!= n (length (last lst))))
    (pop lst -1))
  lst)
> (group '(1 2 3 4))
((1 2) (3 4))
> (group '(1 2 3))
((1 2) (3))

> (group '(1 2 3 4 5 6 7 8) 3)
((1 2 3) (4 5 6) (7 8))
> (group '(1 2 3 4 5 6 7 8) 3 nil)
((1 2 3) (4 5 6))

Fanda

Lutz
Posts: 5289
Joined: Thu Sep 26, 2002 4:45 pm
Location: Pasadena, California
Contact:

Post by Lutz »

The 'array' function was used because it has pairing/grouping already built into it, and it can take a flat list for initialization:

Code: Select all

(array 3 2) => ((nil nil) (nil nil) (nil nil))

; or with initialization

(array 3 2 '(1 2 3 4 5 6)) => ((1 2) (3 4) (5 6))
It also would work for more than 2 dimensions. Similar to Fanda's group function you could define:

Code: Select all

(define (group lst (n 2)) 
  (array-list (array (/ (length lst) n) n lst)))
Since version 9.0 the functions 'append, last, first, rest and slice' (and their implicit indexing forms) can also be used on arrays. This means that very often it is not necessary to convert the array back into a list using 'array-list'.

For shorter lists (rule of thumb: < 100 elements) arrays don't offer much of a speed advantage, but on longer lists and when accessing elements not in a sequential fashion, the speed advantage can be dramatic.

Lutz

cormullion
Posts: 2038
Joined: Tue Nov 29, 2005 8:28 pm
Location: latiitude 50N longitude 3W
Contact:

Post by cormullion »

Thanks Lutz. The idea was that I thought it would be a useful way to return a set of results from a function, by returning them in an association list. Speed isn't much of an issue, since there would be only 5 to 10 values to return. Ease of expression is more the thing - something that naturally flows out of the fingers once the hard work of defining the function body is completed, that doesn't require another piece of program code to achieve. That's why I'm currently leaning towards the (list (list approach.

Lutz
Posts: 5289
Joined: Thu Sep 26, 2002 4:45 pm
Location: Pasadena, California
Contact:

Post by Lutz »

Ease of expression is more the thing ... that doesn't require another piece of program code to achieve.
I wholeheartedly agree. Ease of expression and self sufficiency should always be the first priority, before efficiency considerations, when coding. Decisions in this area always have a subjective component, which is fine and how it should be.

Because of this I also reject 'standardized coding styles' or the notion that there is a 'right way' of doing things.

Much of the fun in programming stems from the freedom we can take to express (code) in our own individual way and a prgrammming language should allow this.

The best programmers are those who take the freedom to cultivate their own styles.

Lutz

lisp
Posts: 15
Joined: Tue Oct 10, 2006 1:01 pm
Location: Lispville, LSP
Contact:

Post by lisp »

Lutz wrote:
Ease of expression is more the thing ... that doesn't require another piece of program code to achieve.
I wholeheartedly agree. Ease of expression and self sufficiency should always be the first priority, before efficiency considerations, when coding. Decisions in this area always have a subjective component, which is fine and how it should be.

Because of this I also reject 'standardized coding styles' or the notion that there is a 'right way' of doing things.

Much of the fun in programming stems from the freedom we can take to express (code) in our own individual way and a prgrammming language should allow this.

The best programmers are those who take the freedom to cultivate their own styles.

Lutz
Quote book material.

rickyboy
Posts: 607
Joined: Fri Apr 08, 2005 7:13 pm
Location: Front Royal, Virginia

Post by rickyboy »

Yet another:

Code: Select all

(define (zip) (transpose (args)))

(define (test)
  (local (a b c sum)
    (set 'a 1)
    (set 'b 2)
    (set 'c 3)
    (set 'sum (+ a b c))
    (zip '(a b c sum) (list a b c sum))))

> (test)
((a 1) (b 2) (c 3) (sum 6))
To understand zip's meaning, think about what happens to two separate rows of teeth as they pass through a zipper.

Cheers, --Rick
(λx. x x) (λx. x x)

cormullion
Posts: 2038
Joined: Tue Nov 29, 2005 8:28 pm
Location: latiitude 50N longitude 3W
Contact:

Post by cormullion »

That's neat! And inline:

Code: Select all

(transpose (list '(a b c sum) (list a b c sum)))
works for me, and is shorter than:

Code: Select all

(list (list "a" a) (list "b" b) (list "c" c) (list "sum" sum))
thanks for all the ideas!

Lutz
Posts: 5289
Joined: Thu Sep 26, 2002 4:45 pm
Location: Pasadena, California
Contact:

Post by Lutz »

Very nice, rickyboy ... and works for n-way zips too:

Code: Select all

(zip '(1 2 3) '(a b c) '(x y z)) => ((1 a x) (2 b y) (3 c z))
I will put this into the http://newlisp.org/index.cgi?page=Code_Snippets page

Lutz

rickyboy
Posts: 607
Joined: Fri Apr 08, 2005 7:13 pm
Location: Front Royal, Virginia

Post by rickyboy »

Oops! You had better not give me credit for that. The idea and name of 'zip' is something taken from FP languages like Haskell or ML. The newlisp implementation of 'zip' I first saw in Fanda's function 'merge' in http://www.intricatevisions.com/source/newlisp/list.lsp. When I saw Fanda's 'merge', I thought "Hey that's zip and a very pithy definition at that." So, I vote that you strike my name from the Snippets credit and stick Fanda's name there. :-) Cheers, --Rick
Last edited by rickyboy on Mon Nov 06, 2006 12:41 am, edited 1 time in total.
(λx. x x) (λx. x x)

nigelbrown
Posts: 429
Joined: Tue Nov 11, 2003 2:11 am
Location: Brisbane, Australia

Post by nigelbrown »

For an unspecified number of arguments:

(define-macro (test )
(let ((s (map (lambda (x) (list (sym x) (eval x))) (args))))
(append s (list (list 'sum (apply '+ (map (lambda (x) (x 1)) s)))))))

Line 2 gathers the arguments into an assoc list
Line 3 sums the second elements and sticks it on the end
the local variable s is used so arguments are only evaluated once
so

> (setq a 1)
1
> (setq b 2)
2
> (setq c 3)
3
> (test a b c)
((a 1) (b 2) (c 3) (sum 6))
>

Nigel
PS to keep the original intent of strings in the list use name:

(define-macro (test )
(let ((s (map (lambda (x) (list (name x) (eval x))) (args))))
(append s (list (list "sum" (apply '+ (map (lambda (x) (x 1)) s)))))))

gives

> (test a b c)
(("a" 1) ("b" 2) ("c" 3) ("sum" 6))
>

Fanda
Posts: 253
Joined: Tue Aug 02, 2005 6:40 am
Contact:

Post by Fanda »

rickyboy wrote:Oops! You had better not give me credit for that. The idea and name of 'zip' is something taken from FP languages like Haskell or ML. The newlisp implementation of 'zip' I first saw in Fanda's function 'merge' in http://www.intricatevisions.com/source/newlisp/list.lsp. When I saw Fanda's 'merge', I thought "Hey that's zip and a very pithy definition at that." So, I vote that you strike my name from the Snippets credit and stick Fanda's name there. :-) Cheers, --Rick
Rick, I am glad to see that you read my code :-)

Just to be clear on who gets the credit: I first saw zip-merge-dispose from Nigel Brown and named it 'merge':
http://www.alh.net/newlisp/phpbb/viewtopic.php?p=4582
Here is a dispose that is just a wrapper around the builtin newLISP function transpose.
using args lets you accept any number of lists
viz

> (define (dispose) (transpose (args)))
(lambda () (transpose (args)))
> (dispose '(1 2 3) '(4 5 6))
((1 4) (2 5) (3 6))
> (dispose '(1 2 3) '(4 5 6) '(7 8 9))
((1 4 7) (2 5 8) (3 6 9))
> (setq m '(1 2 3 4 5 6 7))
(1 2 3 4 5 6 7)
> (setq n '(7 6 5 4 3 2 1))
(7 6 5 4 3 2 1)
> (dispose m n)
((1 7) (2 6) (3 5) (4 4) (5 3) (6 2) (7 1))
>

Nigel
So, credit goes to Nigel!

Fanda

PS: Code Snippets show old update time: last updated 2005-12-08

lisp
Posts: 15
Joined: Tue Oct 10, 2006 1:01 pm
Location: Lispville, LSP
Contact:

Post by lisp »

Fanda wrote:So, credit goes to Nigel!
I call it, if Nigel doesn't want it.

nigelbrown
Posts: 429
Joined: Tue Nov 11, 2003 2:11 am
Location: Brisbane, Australia

Post by nigelbrown »

I'd completely forgotten dispose.
You can see from my contribution re test above I like using (args)

Nigel

Locked