Fun with MAP

Started by Jeremy Dunn, July 03, 2006, 05:15:14 PM

Previous topic - Next topic

cormullion

#15
My 3 euros-worth:



1: it would be great to have lots of cool new functions in newLISP, particularly general purpose ones that could be used anywhere and that save us having to write them ourselves.



2: newLISP should continue to be small and concise, without having a proliferation of functions that are rarely used...



3: newLISP should continue to run extremely quickly and launch instantaneously, and mustn't get much larger - don't want it to be larger than 300Kbytes or so... :-)



But to be serious - i can see that the three pillars of newLISP - expressive power, speed, and size - are related, but I don't know how important each one is or how the balance might change in the future. Only Lutz can tell us that.



Perhaps more modules or libraries would be helpful, so that there's a standard set of functions available on all installations that individuals could modify if they wanted to but rely on being there.



Or perhaps new functions should be added to the main system only if they prove to be sufficiently general purpose, or that are otherwise difficult to write in newLISP. I suppose 'unify' was in the latter category...



Another good thing about having more functions of the type described here is that they'll get more widely used if they're built in. And that could also promote good programming. (At my level, I'm all in favour of that!)



Is the compact size of newLISP an advantage in the days of 200GB disks and broadband internet? Or does size still mean speed?

rickyboy

#16
Cormullion,



I like your presentation of the three pillars -- so much that I would consider it worth more than a mere 3 Euros.  (I can barely get a good Frape in Athens for 3 Euro. :-)  By the way, I thought you were dealing in Pounds anyway -- are you not on the Island?



Curious,

--Rick
(λx. x x) (λx. x x)

cormullion

#17
(yes, officially we use the pound sterling, even in rural england, but we're in europe too, so a nodding familiarity with the euro is useful, expecially if we go on holiday!)

Fanda

#18
Feel free to contribute more functions and examples (and some theory) to FP library:

http://newlisp-on-noodles.org/wiki/index.php/Fp">http://newlisp-on-noodles.org/wiki/index.php/Fp



Fanda

rickyboy

#19
Quote from: "Fanda"Feel free to contribute more functions and examples (and some theory) to FP library:

http://newlisp-on-noodles.org/wiki/index.php/Fp">http://newlisp-on-noodles.org/wiki/index.php/Fp

Hey Fanda,

Check out the new composer I added there.  It pre-builds the lambda expression like your imperative version.

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

nikus80

#20
maybe this should go on the wiki, but a negator could be useful too. given a function, it returns a function which applies not to the result. And for example there is no need to define (elem?) and (not-elem?). Also useful for mapping, filtering, etc.



sketch:
(define (negate fun)
  (letex (fun fun)
    (fn () (not (apply fun (args))))))


example:
> (map number? '(1 2 3 "hi"))
(true true true nil)
> (map (negate number?) '( 1 2 3 "lol"))
(nil nil nil true)


EXTRA EDIT:

I've been playing around and after trying a lil bit to make an loop/iter macro for newLISP, I came to a better idea, I hope you like it!



It's the collector idea. In common lisp



(loop for e in lst collect (+ e 1))



does exactly what it seems to. It conses a all the elements in the list plus one. Identic to



(map (fn (e) (+ e 1) lst)



The cool thing about the loop macro is that you can mix thing a lil bit. Instead of iterating over a list you could iterate numbers. And write



(loop for e from 1 to 10 collect (+ e 1))



To do that you would have to use a sequence and map, build a list and throw it away, like this:



(map (fn (e) (+ e 1) (sequence 1 10))



But this way you have to replicate in sequence everything you could do with a normal for. And not to mention that besides collecting you can append, sum, etc. and you can insert ifs and then do filtering, everything with loop only

Now, instead of a overly complicated loop macro, I present you to the simple newLisp collector!


(collector
(dolist (e lst)
  (if (and (number? e) (> e 1))
(build (+ 1 e)))))

It does what it looks likes. Every call to build is macroexpanded to a call to (set), accumulating a list and then returning it.



for example, if lst would have been (1 2 3 "a b" k 13)) it would have evaluated to (3 4 14).

The cool thing here is that unlike map, you can iterate over anything.


> [cmd]
 (collector
  (for (e 1 10)
  (if (> e 3)
(build (+ 1 e)))))
[/cmd]

(5 6 7 8 9 10 11)

Now, the real thing here is that you can easily make you own builders.

(custom-builder) is a function that receives the base case and a function that receives the building value and the total count symbol, and returns a list of code so you can make you own builders. And (builder) is a simple macro that allows to make simple builders on-the-fly, instead of of the more general (custom-builder), it receives a function with is to be applied to the total and current value and the total is set to the value returned. E.G.


> (builder * 1 (for (i 1 4) (build i)))
24




Maybe I'm reinventing the wheel, but it seems fun!





Oh, I almost forgot!


(define-macro (collector)
(let (collector-list '())
(eval
(cons 'begin
(expand (args)
  '((build
'(lambda (element)
(push element collector-list -1)))))))
collector-list))
(define (custom-builder)
   (expand
'(let (building basecase)
(eval
(cons 'begin
(expand (args)
'((build
(fn (element)
(build-function element 'building)))))))
building)
(list (list 'build-function (args 0)) (list 'basecase (args 1)))))
(define-macro (builder fun base)
(letex (fun fun base base)
(eval (custom-builder
(fn (num total) (set total (fun num (eval total))))
base))))


(btw, I think they're not very hygenic and I'm not sure how nested builder works, besides maybe a "builder collector" would be good if I want to build on the outer collector, but that would be very rare I think.)

Jeremy Dunn

#21
I ran into a situation where I wanted to map to individual items of sublists of a list. For instance, I wanted to be able to write something like



(mymap abs '(-1 -2 '(-3 -4)))



and get back (1 2 (3 4)) where ALL subitems are processed and the nesting is preserved in the answer. Anyone have an easy way to do this? If the regular MAP function operated like this would it cause unexpected problems?

Fanda

#22
Let's try this simple "recursive map":


;; recursive map
;;
(define (rmap f lst)
  (let (result '())
    (dolist (l lst)
      (if (list? l)
        (push (rmap f l) result -1)
        (push (f l) result -1)))
    result))


> (rmap abs '(-1 -2 (-3 -4)))
(1 2 (3 4))

> (define (twice x) (* 2 x))
(lambda (x) (* 2 x))
> (rmap twice '(-1 -2 (-3 -4)))
(-2 -4 (-6 -8))

> (rmap twice (rmap abs '(-1 -2 (-3 -4))))
(2 4 (6 8))


Fanda

jopython

#23
I didn't know there were so many variations of map.

Mindblowing, even though this thread is 6 years old.