Re: mapeach

2015-07-18 Thread Alexander Burger
Hi Erik,

 I came across a cute little Common Lisp macro, mapeach
 http://malisper.me/2015/06/14/mapeach/. Naturally, I wanted it to play
 with it in PicoLisp. The most straightforward translation (for me) of the
 code in the post was:
 
 [de mapeach E# expression
(let [(@Var @List . @Body)  E]
   (macro
  (mapcar
 '((@Var) . @Body)
 @List ]

Yes, that's fine.


An alternative could be

   (de mapeach Args
  (mapcar
 (cons (cons (car Args)) (cddr Args))
 (eval (cadr Args)) ) )

The 'cons'es are a little less expensive than the full macro.


 What are some other ways this could be written? I'm thinking it might be in
 the spirit of do*, as defined in the FAQ

A way in the spirit of do* would be

   (de mapeach Args
  (mapcar
 '((E)
(bind (car Args)
   (set (car Args) E)
   (run (cddr Args)) ) )
 (eval (cadr Args)) ) )

This is a bit longer, but needs no consing at all.



 It works great for single variable expressions.
 
 : (mapeach N (1 2 3) (* N N))
 - (1 4 9)
 
 Multiple vars will make it angry (return NIL).

That's right. But if we define this syntax for multiple variables:

   (mapeach (X Y) '(a b c) '(d e f) (foo ...

we can write

   (de mapeach Args
  (let Vars (pop 'Args)
 (apply mapcar
(mapcar eval (cut (length Vars) 'Args))
(cons Vars Args) ) ) )

   : (mapeach (X Y) (1 2 3) (4 5 6)
  (* X Y) )
   - (4 10 18)

♪♫ Alex
-- 
UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe


Re: mapeach

2015-07-18 Thread Erik Gustafson
Alex,

Thanks for the write-up! It's fun to dissect the different versions with
'debug' and mess around at the repl.


 An alternative could be

(de mapeach Args
   (mapcar
  (cons (cons (car Args)) (cddr Args))
  (eval (cadr Args)) ) )

 The 'cons'es are a little less expensive than the full macro.


Yes, makes sense. If I understand correctly, you're explicitly stating what
my call to 'macro' eventually builds, but by skipping 'macro' you bypass
the associated calls to 'pat?', 'fill', and 'run'.


A way in the spirit of do* would be

(de mapeach Args
   (mapcar
  '((E)
 (bind (car Args)
(set (car Args) E)
(run (cddr Args)) ) )
  (eval (cadr Args)) ) )

 This is a bit longer, but needs no consing at all.


Awesome! I'm starting to grasp the 'bind', 'set', 'run' combo. This style
makes a lot more sense now that I see it with a simpler function. I'm not a
fluent 'do*'er.


That's right. But if we define this syntax for multiple variables:

(mapeach (X Y) '(a b c) '(d e f) (foo ...

 we can write

(de mapeach Args
   (let Vars (pop 'Args)
  (apply mapcar
 (mapcar eval (cut (length Vars) 'Args))
 (cons Vars Args) ) ) )

: (mapeach (X Y) (1 2 3) (4 5 6)
   (* X Y) )
- (4 10 18)


Now you're just showing off :) Seriously cool, though.