newLISP Fan Club

Forum => newLISP newS => Topic started by: cormullion on November 03, 2006, 06:42:36 AM

Title: how to return an association list
Post by: cormullion on November 03, 2006, 06:42:36 AM
Is it possible to return an association list from a function? Here's a test:


(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... :-)
Title:
Post by: Lutz on November 03, 2006, 07:03:58 AM
Yes, a small change does it:



(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
Title:
Post by: cormullion on November 03, 2006, 08:13:39 AM
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?


(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).
Title:
Post by: Lutz on November 03, 2006, 08:58:06 AM
Like this?


(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
Title:
Post by: cormullion on November 03, 2006, 10:54:53 AM
yes, that looks better .... ;-)



thanks





PS quiet round here isn't it?
Title:
Post by: Fanda on November 03, 2006, 01:45:42 PM
Lutz wrote:
(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'  :-)


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


Fanda
Title:
Post by: Fanda on November 03, 2006, 01:53:41 PM
Another solution:
(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
Title:
Post by: cormullion on November 04, 2006, 12:00:54 AM
thanks Fanda. I think this is the one I shall use:


(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... ;-)
Title:
Post by: m i c h a e l on November 04, 2006, 08:27:42 AM
cormullion!



With the addition of the pair function:
(constant (global 'pair) (fn (lst)
  (array-list (array (/ (length lst) 2) 2 lst))))


You can bum it even more:
(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
Title:
Post by: cormullion on November 04, 2006, 09:10:37 AM
Welcome back, mm. :-) But what does pair do? - why is it using arrays?
Title:
Post by: m i c h a e l on November 04, 2006, 09:24:16 AM
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
Title:
Post by: cormullion on November 04, 2006, 10:25:21 AM
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.
Title:
Post by: Fanda on November 04, 2006, 11:02:37 AM
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])


(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
Title:
Post by: Lutz on November 04, 2006, 12:47:14 PM
The 'array' function was used because it has pairing/grouping already built into it, and it can take a flat list for initialization:


(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:


(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
Title:
Post by: cormullion on November 04, 2006, 01:52:08 PM
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.
Title:
Post by: Lutz on November 04, 2006, 03:01:30 PM
QuoteEase 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
Title:
Post by: lisp on November 04, 2006, 03:50:16 PM
Quote from: "Lutz"
QuoteEase 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.
Title:
Post by: rickyboy on November 04, 2006, 08:41:06 PM
Yet another:
(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
Title:
Post by: cormullion on November 05, 2006, 12:39:28 AM
That's neat! And inline:


(transpose (list '(a b c sum) (list a b c sum)))

works for me, and is shorter than:


(list (list "a" a) (list "b" b) (list "c" c) (list "sum" sum))

thanks for all the ideas!
Title:
Post by: Lutz on November 05, 2006, 01:31:57 AM
Very nice, rickyboy ... and works for n-way zips too:


(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
Title:
Post by: rickyboy on November 05, 2006, 04:12:42 PM
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
Title:
Post by: nigelbrown on November 05, 2006, 04:31:47 PM
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))

>
Title:
Post by: Fanda on November 05, 2006, 06:28:35 PM
Quote from: "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


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


Quote
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
Title:
Post by: lisp on November 05, 2006, 06:37:25 PM
Quote from: "Fanda"So, credit goes to Nigel!


I call it, if Nigel doesn't want it.
Title:
Post by: nigelbrown on November 05, 2006, 08:23:15 PM
I'd completely forgotten dispose.

You can see from my contribution re test above I like using (args)



Nigel