From: ················@gmail.com
Subject: a macro to like mapcar
Date: 
Message-ID: <609bd90c-50d4-44cf-91ac-a471aa07afd1@k36g2000pri.googlegroups.com>
Hello,
 I am trying to write a macro like mapcar but it is slightly
different.
 The goal
 If we have N sequences (could be lists or vectors)  of size
(l,m,n,...) then there will be l*m*n*... tuples. I want to apply a
function f on all the tuples.


Here is what I have got till now. It has some problems..

(defgeneric loop-keyword-for (seq))
(defmethod loop-keyword-for ((seq list)) 'in)
(defmethod loop-keyword-for ((seq vector)) 'across)
(defmethod loop-keyword-for (seq) 'unknown)
(defmacro map-permute-macro (oper &rest args)
  (let* ((seq-symbols (mapcar (lambda (x) (list (gensym "permute-
seqs") x)) args))
	 (itervar-seq-pairs (mapcar (lambda (x)
				      (list (gensym "permute-iterator") (car x)))
				    seq-symbols))
	 (tuple (mapcar (lambda (x) (car x)) itervar-seq-pairs)))
    `(let (,@seq-symbols)
      ,(reduce (lambda (x y)
		 (let* ((var (car x))
			(seq (cadr x))
			(loop-keyword (loop-keyword-for seq)))
		   (list 'loop 'for var loop-keyword seq  'do y)))
	       itervar-seq-pairs
	       :from-end t
	       :initial-value (list 'apply oper tuple)))))



(macroexpand-1 (map-permute-macro #'(lambda (x y z) (list x y z)) '(1
2 3 4 5) #(1 2 3 4) "hellow"))


Firstly it is not seeing the generic function (loop-keyword-for)  I
have declared. secondly , I am not able to quote the list input arg.
Can anybody please help me with this. This is just a exercise I am
doing to learn lisp
Thanks in advance.
Regards,
Sunil

From: Rainer Joswig
Subject: Re: a macro to like mapcar
Date: 
Message-ID: <joswig-69ECE4.09051606112008@news-europe.giganews.com>
In article 
<····································@k36g2000pri.googlegroups.com>,
 ·················@gmail.com" <················@gmail.com> wrote:

> Hello,
>  I am trying to write a macro like mapcar but it is slightly
> different.
>  The goal
>  If we have N sequences (could be lists or vectors)  of size
> (l,m,n,...) then there will be l*m*n*... tuples. I want to apply a
> function f on all the tuples.

The obvious question:

MAPCAR is a function. Why would you want to write a
macro? Better write it as a function.



> 
> 
> Here is what I have got till now. It has some problems..
> 
> (defgeneric loop-keyword-for (seq))
> (defmethod loop-keyword-for ((seq list)) 'in)
> (defmethod loop-keyword-for ((seq vector)) 'across)
> (defmethod loop-keyword-for (seq) 'unknown)
> (defmacro map-permute-macro (oper &rest args)
>   (let* ((seq-symbols (mapcar (lambda (x) (list (gensym "permute-
> seqs") x)) args))
> 	 (itervar-seq-pairs (mapcar (lambda (x)
> 				      (list (gensym "permute-iterator") (car x)))
> 				    seq-symbols))
> 	 (tuple (mapcar (lambda (x) (car x)) itervar-seq-pairs)))
>     `(let (,@seq-symbols)
>       ,(reduce (lambda (x y)
> 		 (let* ((var (car x))
> 			(seq (cadr x))
> 			(loop-keyword (loop-keyword-for seq)))
> 		   (list 'loop 'for var loop-keyword seq  'do y)))
> 	       itervar-seq-pairs
> 	       :from-end t
> 	       :initial-value (list 'apply oper tuple)))))

You are posting code, but no explanation how above
code should work - sometimes called 'documentaton'.

You want different code to be generated for different
types of sequences. That won't work in the general
case.

(let ((foo #(1 2 3)))
  (your-macro foo))

In above case one just passes a variable. The macro
sees a symbol. It can not determine what kind
of sequence will be bound to that variable.
Your code only may work for the case that a sequence
is literally in source code as argument to your macro.

I would think it is best to get the general idea right
and then deal with special cases. But, anyway,
write it as a function - not a macro.

If you want to learn how to write macros in this case,
you need to TRACE the functions your are using.
You also should have an idea into what code
the macro expands source to. It is not a good idea
to write a macro without knowing what the generated
code should look like. For macros I often try
to figure out what the code should look like and then
try to write code that generates that code and then
wrap that code up into a macro.

But then, this really should be a function. ;-)

> 
> 
> 
> (macroexpand-1 (map-permute-macro #'(lambda (x y z) (list x y z)) '(1
> 2 3 4 5) #(1 2 3 4) "hellow"))
> 
> 
> Firstly it is not seeing the generic function (loop-keyword-for)  I
> have declared.

What does this mean 'seeing'? Your macro calls them.
Try tracing the function to see what it does.


> secondly , I am not able to quote the list input arg.
> Can anybody please help me with this. This is just a exercise I am
> doing to learn lisp
> Thanks in advance.
> Regards,
> Sunil

-- 
http://lispm.dyndns.org/
From: Pascal J. Bourguignon
Subject: Re: a macro to like mapcar
Date: 
Message-ID: <7ciqr1ksvw.fsf@pbourguignon.anevia.com>
·················@gmail.com" <················@gmail.com> writes:

> Hello,
>  I am trying to write a macro like mapcar but it is slightly
> different.
>  The goal
>  If we have N sequences (could be lists or vectors)  of size
> (l,m,n,...) then there will be l*m*n*... tuples. I want to apply a
> function f on all the tuples.

Building all these tuples has nothing to do with permutations.  So you
should not call it *-permute-*.  Also it can be done with a function,
so you don't need a macro here.

> Here is what I have got till now. It has some problems..

(defgeneric emptyp (self)
  (:method ((self null))   t)
  (:method ((self cons))   nil)
  (:method ((self vector)) (zerop (length self))))

(defun sequence-product (sequences)
  "Takes a list of sequences, and returns a list of all the tuples."
  (cond
    ((null sequences)                   ; no list -> {}
     '())
    ((emptyp (first sequences))         ; {} x E = {}
     '())
    ((rest sequences)                   ; A x B x C = A x (B x C)
     (let ((sub-product (sequence-product (rest sequences))))
       (when sub-product
         (mapcan (lambda (item)
                   (mapcar (lambda (rest) (cons item rest)) sub-product))
                 (coerce (first sequences) 'list)))))
    (t                         ; one sequence (a b c) -> ((a) (b) (c))
     (map 'list (function list) (first sequences)))))



Then the function you want is trivial:

(defun apply-on-tuples (fun sequences)
   (mapcar fun (sequence-product sequences)))


(apply-on-tuples (lambda (tuple) (apply (function +) tuple))
                 '((1 2 3) #(100 200 300 400) (-1)))
--> (100 200 300 400 101 201 301 401 102 202 302 402)



-- 
__Pascal Bourguignon__
From: William James
Subject: Re: a macro to like mapcar
Date: 
Message-ID: <gevjhv$l4p$1@aioe.org>
Pascal J. Bourguignon wrote:

> ·················@gmail.com" <················@gmail.com> writes:
> 
> > Hello,
> >  I am trying to write a macro like mapcar but it is slightly
> > different.
> >  The goal
> >  If we have N sequences (could be lists or vectors)  of size
> > (l,m,n,...) then there will be l*m*n*... tuples. I want to apply a
> > function f on all the tuples.
> 
> Building all these tuples has nothing to do with permutations.  So you
> should not call it *-permute-*.  Also it can be done with a function,
> so you don't need a macro here.
> 
> > Here is what I have got till now. It has some problems..
> 
> (defgeneric emptyp (self)
>   (:method ((self null))   t)
>   (:method ((self cons))   nil)
>   (:method ((self vector)) (zerop (length self))))
> 
> (defun sequence-product (sequences)
>   "Takes a list of sequences, and returns a list of all the tuples."
>   (cond
>     ((null sequences)                   ; no list -> {}
>      '())
>     ((emptyp (first sequences))         ; {} x E = {}
>      '())
>     ((rest sequences)                   ; A x B x C = A x (B x C)
>      (let ((sub-product (sequence-product (rest sequences))))
>        (when sub-product
>          (mapcan (lambda (item)
>                    (mapcar (lambda (rest) (cons item rest))
> sub-product))                  (coerce (first sequences) 'list)))))
>     (t                         ; one sequence (a b c) -> ((a) (b) (c))
>      (map 'list (function list) (first sequences)))))
> 
> 
> 
> Then the function you want is trivial:
> 
> (defun apply-on-tuples (fun sequences)
>    (mapcar fun (sequence-product sequences)))
> 
> 
> (apply-on-tuples (lambda (tuple) (apply (function +) tuple))
>                  '((1 2 3) #(100 200 300 400) (-1)))
> --> (100 200 300 400 101 201 301 401 102 202 302 402)

Let's do it without recursion and without Blub (Commune Lisp).


def sequence_product lists
  lists.inject([[]]){|old,lst|
    lst.inject([]){|new,e| new + old.map{|c| c + [ e ] }}}
end

def apply_on_tuples lists
  sequence_product( lists ).map{|list| yield list }
end 

p apply_on_tuples( [[1,2,3],[100,200,300,400],[-1]] ){|list|
    list.inject{|sum,x| sum + x } }

--- output ---
[100, 101, 102, 200, 201, 202, 300, 301, 302, 400, 401, 402]
From: Kaz Kylheku
Subject: Re: a macro to like mapcar
Date: 
Message-ID: <20081106083016.383@gmail.com>
On 2008-11-06, ················@gmail.com <················@gmail.com> wrote:
> Hello,
>  I am trying to write a macro like mapcar but it is slightly
> different.

MAPCAR isn't a macro, so if you mean ``a macro like the mapcar macro'' you are
wrong, and if you mean ``macro like the mapcar function'' you are silly.

MAPCAR is sometimes indirected upon, which you cannot do with a macro:

  ;; "matrix" transpose:

  (apply #'mapcar #'list '((1 2 3) (4 5 6)) 
  
  -> ((1 4) (2 5) (3 6))

>  The goal
>  If we have N sequences (could be lists or vectors)  of size
> (l,m,n,...) then there will be l*m*n*... tuples. I want to apply a
> function f on all the tuples.

There is no macro required for this.

Also, your approach of trying to select among LOOP FOR keywords is flawed.
You're trying to make a decision at macro-expansion time based on the run-time
type of inputs. This will work only if the inputs are literal objects.
What if one of the args is simply FOO, which is a variable that holds a
sequence? The SEQ variable will end up holding the symbol FOO, 
which calls for this method:

  (loop-keyword-for ((seq symbol)) ...)

But you don't have this one, so control goes to this one:

  (defmethod loop-keyword-for (seq) 'unknown)

The above is a silly, by the way, because all you are doing is turning a nice,
understandable error situation (``method not found'') to bad loop syntax: (loop
for var unknown ...).

Only define default methods when they do something reasonable that allows the
program to work correctly, or at least handle the situation in a better way.

> Can anybody please help me with this. This is just a exercise I am
> doing to learn lisp

Try something easier for now.