From: Tamas Papp
Subject: copy and coerce sequence
Date: 
Message-ID: <87ps31k3z8.fsf@pu100877.student.princeton.edu>
Hi,

I have a function which takes arguments which can either be lists or
vectors of numbers.  These need to be converted to a simple-array
vector of given type, and also copied, because they are used to
initialize slots in an object and I don't want to share structure.

I came up with this:

(defun copy-into-simple-array (sequence element-type)
  "Copy object, coercing into simple array with given
element-type if necessary."
  (let ((type (list 'vector element-type)))
    (if (typep sequence type)
	(copy-seq sequence)
	(coerce sequence type))))

but it doesn't work in some cases:

(describe (copy-into-simple-array '(1 2 3) 't))            ; works
(describe (copy-into-simple-array '(1 2 3) 'fixnum))       ; works
(describe (copy-into-simple-array #(1 2 3) 'double-float)) ; error: can't coerce
(describe (copy-into-simple-array '(1 2 3) 'double-float)) ; error: can't coerce

Could someone please help me figure out a solution?

Thanks,

Tamas

From: Pillsy
Subject: Re: copy and coerce sequence
Date: 
Message-ID: <1183996613.516394.132000@57g2000hsv.googlegroups.com>
On Jul 9, 11:10 am, Tamas Papp <······@gmail.com> wrote:

> Could someone please help me figure out a solution?

Yup. COERCE on the entire sequence isn't really what you want; you may
have figured out that it doesn't work on the actual elements of the
sequence, just the sequence as a whole. If they aren't the right type
going in, the whole thing will probably go blooey on you. Also, you
probably want to be using the UPGRADED-ARRAY-ELEMENT-TYPE of ELEMENT-
TYPE to avoid strange surprises.

If you need to fill a vector using a function (in this case, coercing
the elements into the right type), MAP-INTO is the function for you.
The following should do the trick for you. It omits some possible
optimizations that you can probably add back in if you need them.

HTH:

(defun make-simple-array (length &optional (element-type t))
  "Makes a 1D array of length LENGTH and element-type ELEMENT-TYPE,
with no fill-pointer, adjustability or displacement. According to the
CLHS, this is guaranteed to be a simple array."
  (make-array length
	      :element-type element-type
	      :adjustable nil :fill-pointer nil :displaced-to nil))

(defun copy-into-simple-array (sequence element-type)
  (let* ((elt-type (upgraded-array-element-type element-type))
	 (vec (make-simple-array (length sequence) element-type)))
    (map-into vec #'(lambda (e) (coerce e elt-type))
	      sequence)))

(defun test-copy-into-simple-array (&rest test-cases)
  (map nil
       #'(lambda (tc)
	   (destructuring-bind (s et) tc
	     (format t "~&;; ~a =>~%#| ~a |#~%"
		     `(copy-into-simple-array ,@tc)
		     (with-output-to-string (desc)
		       (describe (copy-into-simple-array s et) desc)))))
       test-cases))

*> (test-copy-into-simple-array
    '((1 2 3)  t)
    '((1 2 3)  fixnum)
    '((1 2 3)  double-float)
    '(#(1 2 3) double-float))

;; (COPY-INTO-SIMPLE-ARRAY (1 2 3) T) =>
#| #(1 2 3) is a vector with 3 elements.
 |#
;; (COPY-INTO-SIMPLE-ARRAY (1 2 3) FIXNUM) =>
#| #(1 2 3) is a vector with 3 elements.
Its element type is specialized to FIXNUM.
 |#
;; (COPY-INTO-SIMPLE-ARRAY (1 2 3) DOUBLE-FLOAT) =>
#| #(1.0d0 2.0d0 3.0d0) is a vector with 3 elements.
Its element type is specialized to DOUBLE-FLOAT.
 |#
;; (COPY-INTO-SIMPLE-ARRAY #(1 2 3) DOUBLE-FLOAT) =>
#| #(1.0d0 2.0d0 3.0d0) is a vector with 3 elements.
Its element type is specialized to DOUBLE-FLOAT.
 |#
NIL
From: Alan Crowe
Subject: Re: copy and coerce sequence
Date: 
Message-ID: <86wsx9zi1k.fsf@cawtech.freeserve.co.uk>
Tamas Papp <······@gmail.com> writes:

> Hi,
> 
> I have a function which takes arguments which can either be lists or
> vectors of numbers.  These need to be converted to a simple-array
> vector of given type, and also copied, because they are used to
> initialize slots in an object and I don't want to share structure.
> 
> I came up with this:
> 
> (defun copy-into-simple-array (sequence element-type)
>   "Copy object, coercing into simple array with given
> element-type if necessary."
>   (let ((type (list 'vector element-type)))
>     (if (typep sequence type)
> 	(copy-seq sequence)
> 	(coerce sequence type))))
> 
> but it doesn't work in some cases:
> 
> (describe (copy-into-simple-array '(1 2 3) 't))            ; works
> (describe (copy-into-simple-array '(1 2 3) 'fixnum))       ; works
> (describe (copy-into-simple-array #(1 2 3) 'double-float)) ; error: can't coerce
> (describe (copy-into-simple-array '(1 2 3) 'double-float)) ; error: can't coerce
> 

How about this

CL-USER> (defun copy-into-simple-array (sequence element-type)
           (map (list 'simple-array element-type (list (length sequence)))
                (lambda(x)
                  (coerce x element-type))
                sequence))

which seems to do the trick

CL-USER> (describe (copy-into-simple-array #(1 2 3) 'double-float))
#(1.0d0 2.0d0 3.0d0) is a vector of length 3.
It has no fill pointer.
Its element type is specialized to DOUBLE-FLOAT.

CL-USER> (describe (copy-into-simple-array '(1 2 3) 'double-float))
#(1.0d0 2.0d0 3.0d0) is a vector of length 3.
It has no fill pointer.
Its element type is specialized to DOUBLE-FLOAT.

I think the problem you are bumping into is that COERCE has
been specified as a one-thing-at-a-time kind of
operation. It knows how to turn lists into vectors and reals
into double floats. It is specified that if it is turning a
list into a vector it fills the vector with the actual
objects in the list. So it doesn't attempt a second level of
coercion on the data.

Alan Crowe
Edinburgh
Scotland
From: Tamas Papp
Subject: Re: copy and coerce sequence
Date: 
Message-ID: <87hcodk2pf.fsf@pu100877.student.princeton.edu>
Tamas Papp <······@gmail.com> writes:

> Hi,
>
> I have a function which takes arguments which can either be lists or
> vectors of numbers.  These need to be converted to a simple-array
> vector of given type, and also copied, because they are used to
> initialize slots in an object and I don't want to share structure.
>
> I came up with this:
>
> (defun copy-into-simple-array (sequence element-type)
>   "Copy object, coercing into simple array with given
> element-type if necessary."
>   (let ((type (list 'vector element-type)))
>     (if (typep sequence type)
> 	(copy-seq sequence)
> 	(coerce sequence type))))
>
> but it doesn't work in some cases:
>
> (describe (copy-into-simple-array '(1 2 3) 't))            ; works
> (describe (copy-into-simple-array '(1 2 3) 'fixnum))       ; works
> (describe (copy-into-simple-array #(1 2 3) 'double-float)) ; error: can't coerce
> (describe (copy-into-simple-array '(1 2 3) 'double-float)) ; error: can't coerce
>
> Could someone please help me figure out a solution?

This seems to work:

(defun copy-into-simple-array (sequence element-type)
  "Copy object, coercing into simple array with given
element-type if necessary."
  (if (typep sequence (list 'vector element-type))
      (copy-seq sequence)
      (map (list 'vector element-type)
	   (lambda (x) (coerce x element-type)) sequence)))

but I still need to understand Lisp types.  What is a good place to
start?

Tamas