Commit 7f877d62 authored by Marco Antoniotti's avatar Marco Antoniotti

Changed doc string in order to leverage the newest HELambdaP documentation generator.

parent 0850dbc1
......@@ -20,8 +20,34 @@
(:method ((x array-table-enumeration)) t))
(defmethod enumerate ((x array) &key (start 0) end &allow-other-keys)
(make-instance 'array-table-enumeration :object x :start start :end end))
(defmethod enumerate ((A array) &key (start 0) end &allow-other-keys)
"Calling ENUMERATE on an ARRAY returns an ARRAY-ENUMERATION instance.
START must be either an integer between 0 and (array-total-size a), or
a LIST of indices between 0 and the appropriate limit on the
array-dimension. end must be an integer between 0 and
(array-total-size A), or a LIST of indices between 0 and the
appropriate limit on the array-dimension, or NIL. If END is NIL then
it is set to (array-total-size A).
The enumeration of a multidimensional array follows the row-major
order of Common Lisp Arrays.
Examples:
;;; The following example uses ENUM:FOREACH.
cl-prompt> (foreach (e #3A(((1 2 3) (4 5 6)) ((7 8 9) (10 11 12)))
:start (list 1 0 1))
(print e))
8
9
10
11
12
NIL
"
(make-instance 'array-table-enumeration :object a :start start :end end))
(defmethod initialize-instance :after ((x array-table-enumeration)
......
......@@ -15,10 +15,25 @@
"CL.EXTENSIONS.DACF.ENUMERATIONS"
"CL.EXT.DACF.ENUMERATIONS"
"COMMON-LISP.EXTENSIONS.DATA-AND-CONTROL-FLOW.ENUMERATIONS")
(:documentation "The CL Extensions Enemeration Package.
(:documentation "The CL Extensions Enumeration Package.
The package containing the API for a generic enumeration protocol in
Common Lisp.")
Common Lisp.
Notes:
The package name is long because it indicates how to position the
library functionality within the breakdown in chapters of the ANSI
specification.
The lower-case \"enum\" package nickname is provided in order to appease
ACL Modern mode.
The \"CL.EXT...\" nicknames are provided as a suggestion about how to
'standardize' package names according to a meaninguful scheme.
")
(:export
#:enumeration
#:enumerationp
......
......@@ -48,22 +48,82 @@
&allow-other-keys)
(:documentation
"Creates a (specialized) ENUMERATION object.
If applicable START and END delimit the range of the actual enumeration."))
If applicable START and END delimit the range of the actual enumeration.
The generic function ENUMERATE is the main entry point in the
ENUMERATIONS machinery. It takes a CL object (ENUMERABLE-ITEM) and
some additional parameters, which may or may not be used depending on
the type of the object to be enumerated.
Arguments and Values:
ENUMERABLE-ITEM : an Common Lisp object
RESULT : an ENUMERATION instance
START : an object (usually a non-negative integer)
END : an object or NIL
Exceptional Situations:
ENUMERATE calls MAKE-INSTANCE on the appropriate ENUMERATION
sub-class. The instance initialization machinery may signal various
errors. See the documentation for each ENUMERATION sub-class for
details.
"))
(defgeneric has-more-elements-p (x)
(:method ((x enumeration)) nil)
#|
(:documentation
"Checks whether the enumeration has more elements. Obsolete."))
"Checks whether the enumeration has more elements. Obsolete.")|#)
(defgeneric has-next-p (x)
(:method ((x enumeration)) nil)
(:method ((e enumeration)) nil)
(:documentation
"Checks whether the enumeration has more elements. Obsolete."))
"The generic function HAS-NEXT-P checks whether the enumeration
enumeration has another element that follows the current one in the
traversal order. If so it returns a non-NIL result, otherwise, result
is NIL.
Examples:
cl-prompt> (defvar ve (enumerate (vector 1 2 3)))
VE
cl-prompt> (has-next-p ve)
T
cl-prompt> (loop repeat 3 do (print (next ve)))
1
2
3
NIL
cl-prompt> (has-next-p ve)
NIL
"
))
(defgeneric next (e &optional default)
(:documentation
"The generic function NEXT returns the \"next\" object in the
enumeration enumeration if there is one, as determined by calling
HAS-NEXT-P. If HAS-NEXT-P returns NIL and DEFAULT is supplied, then
DEFAULT is returned. Otherwise the condition NO-SUCH-ELEMENT is
signaled.
Arguments and Values:
E : an ENUMERATION instance.
DEFAULT : a T
(defgeneric next (x &optional default))
Exceptional Situations:
NEXT signals the NO-SUCH-ELEMENT condition when there are no more
elements in the enumeration and no default was supplied."))
(defgeneric current (enum &optional errorp default)
......@@ -74,15 +134,57 @@ If applicable START and END delimit the range of the actual enumeration."))
default)
(:documentation
"Returns the \"current\" element in the enumeration ENUM.
Each ENUMERATION instance maintains a reference to its \"current\"
element (if within \"range\"). Given an ENUMERATION instance
enumeration, the generic function CURRENT returns the object in such
reference.
If ERRORP is non-NIL and no \"current\" element is available, then
CURRENT signals an error: either NO-SUCH-ELEMENT or a continuable
error. If ERRORP is NIL and no \"current\" element is available then
DEFAULT is returned."))
DEFAULT is returned.
Exceptional Situations:
CURRENT may signal a continuable error or NO-SUCH-ELEMENT. See above
for an explanation."
))
(defgeneric reset (enum)
(:documentation
"Resets the enumeration ENUM to the \"initial\" element."))
"Resets the enumeration ENUM internal state to its \"initial\" element.
The \"initial\" element of the enumeration ENUM obviously depends on
the actual enumerate object.
Examples:
cl-prompt> (defvar *se* (enumerate \"foobar\" :start 2))
*SE*
cl-prompt> (loop repeat 3 do (print (next *se*)))
#\o
#\b
#\a
NIL
cl-prompt> (current *se*)
#\r
cl-prompt> (reset *se*)
2
cl-prompt> (current *se*)
#\o
cl-prompt> (loop repeat 3 do (print (next *se*)))
#\o
#\b
#\a
NIL
"))
(defgeneric element-type (x)
......@@ -111,7 +213,7 @@ DEFAULT is returned."))
;;; Enumerating an enumeration is an identity operation.
;;; Notes:
;;; Maybe we could copy the enumeration and provide vways to "modify" it.
;;; Maybe we could copy the enumeration and provide ways to "modify" it.
(defmethod enumerate ((x enumeration)
&key start end
......
......@@ -13,6 +13,7 @@
(defmacro foreach ((var object &rest keys) &body forms-and-clauses)
"Simplified iteration construct over an `enumerable' object.
FOREACH is a thin macro over LOOP and it mixes, in a hybrid, and maybe
not so beautiful, style the DOTIMES/DOLIST shape with LOOP clauses.
......@@ -32,6 +33,51 @@ followed.
FOREACH returns whatever is returned by FORMS-AND-CLAUSES according to
standard LOOP semantics.
Examples:
;;; Here are some examples of FOREACH.
cl-prompt> (setf le (enumerate '(1 2 3)))
#<CONS enumeration ...>
cl-prompt> (foreach (i le) (print i))
1
2
3
NIL
;;; Of course, FOREACH is smarter than that:
cl-prompt> (foreach (i (vector 'a 's 'd))
(declare (type symbol i))
(print i))
A
S
D
NIL
;;; Apart from declarations, FOREACH is just a macro built on top of
;;; LOOP, therefore you can leverage all the LOOP functionality.
cl-prompt> (foreach (i (vector 1 2 3 4))
(declare (type fixnum i))
when (evenp i)
collect i)
(2 4)
;;; While this creates an admittedly strange hybrid between the
;;; standard DO... operators and LOOP, it does serve the purpose. The
;;; right thing would be to have a standardized way of extending LOOP.
;;; Alas, there is no such luxury.
;;; Finally an example of a reverse enumeration:
cl-prompt> (foreach (i (vector 1 2 3 4 5 6 7 8) :reverse t :start 4)
when (evenp i)
collect i)
(4 2)
"
(flet ((decl-form-p (form)
(and (consp form) (eq (first form) 'declare)))
......
......@@ -59,6 +59,17 @@
(values t)
key-value-pairs
&allow-other-keys)
"Calling ENUMERATE on a HASH-TABLE returns a HASH-TABLE-ENUMERATION instance.
If KEYS is true, the HASH-TABLE-ENUMERATION scans the keys of the
underlying HASH-TABLE. If VALUES is true (the default), the
HASH-TABLE-ENUMERATION scans the values of the underlying HASH-TABLE.
If KEY-VALUE-PAIRS is true, then the HASH-TABLE-ENUMERATION yields
key-values dotted pairs.
Note that it makes no sense to set \"bounds\" on a
HASH-TABLE-ENUMERATION, as an HASH-TABLE is an unordered data
structure. START and END are ignored."
(declare (ignore start end))
(make-instance 'hash-table-enumeration
:object x
......
......@@ -34,8 +34,15 @@
)))
(defmethod enumerate ((x list) &key (start 0) end &allow-other-keys)
(make-instance 'list-enumeration :object x :start start :end end))
(defmethod enumerate ((l list) &key (start 0) end &allow-other-keys)
"Calling ENUMERATE on a LIST returns a LIST-ENUMERATION instance.
L should be a proper list. The behavior of ENUMERATE when passed a non
proper list is undefined.
START must be an integer between 0 and (length l). END must be an
integer between 0 and (length L) or NIL. The usual CL semantics
regarding sequence traversals applies."
(make-instance 'list-enumeration :object l :start start :end end))
(defmethod has-more-elements-p ((x list-enumeration))
......
......@@ -35,21 +35,54 @@
(defmethod print-object ((ne number-enumeration) s)
(print-unreadable-object (ne s :identity t :type nil)
(format s "Number enumeration [~S ~:[...~;~:*~S~]) at ~S~:[~; by ~S~]"
(enumeration-start ne)
(enumeration-end ne)
(enumeration-cursor ne)
(not (eq (number-enumeration-increment ne) #'1+))
(number-enumeration-increment ne))))
(defmethod enumerate ((x (eql 'number)) &key (start 0) end (by #'1+) &allow-other-keys)
(with-accessors ((start enumeration-start)
(end enumeration-end)
(cursor enumeration-cursor)
(incr number-enumeration-increment)
)
ne
(print-unreadable-object (ne s :identity t :type nil)
(format s "Number enumeration [~S ~:[...~;~:*~S~]) at ~S~:[~; by ~A~]"
start
end
cursor
(not (eq incr #'1+))
(typecase incr
(number incr)
(symbol incr)
(function "#<INCR Function>"))))
))
(defmethod enumerate ((x (eql 'number))
&key
(start 0)
end
(by #'1+)
&allow-other-keys)
"Calling ENUMERATE on a the symbol NUMBER returns a NUMBER-ENUMERATION instance.
NUMBER-ENUMERATIONs are not real enumerations per se, but they have a
nice interface and serve to render things like Python xrange type.
START must be a number, while END can be a number or NIL. The next (or
previous) element is obtained by changing the current element by BY.
BY can be a function (#'1+ is the default) or a number, in which case
it is always summed to the current element.
A NUMBER-ENUMERATION can also enumerate COMPLEX numbers, but in this
case the actual enumeration properties are completely determined by
the value of BY."
(when (or (complexp start) (complexp end))
(warn "Making an enumeration of complex numbers is not guaranteed to have any \"correct\" mathematical properties."))
(warn "Making an enumeration of complex numbers is not guaranteed~
to have any \"correct\" mathematical properties."))
(etypecase by
(function (make-instance 'number-enumeration :object x :start start :end end :by by))
(number (make-instance 'number-enumeration :object x :start start :end end :by (lambda (x) (+ by x))))))
(function (make-instance 'number-enumeration
:object x :start start :end end
:by by))
(number (make-instance 'number-enumeration
:object x :start start :end end
:by #'(lambda (x) (+ by x))))))
(defmethod has-more-elements-p ((x number-enumeration))
......@@ -107,6 +140,30 @@
(defun range (start end &optional (incr #'1+))
"The function RANGE is a utility function the produce a \"stream\"
(quote mandatory) of numbers. It is almost equivalent to the APL/J
iota operator and to Python xrange type.
The main use of RANGE is in conjunction with FOREACH and other
iteration constructs.
Arguments and Values:
START : a NUMBER
END : a NUMBER or NIL
INCR : a NUMBER or a function of one argument (default is #'1+)
result : a NUMBER-ENUMERATION
Examples:
;;;; The two calls below are equivalent:
cl-prompt> (range 2 10 3)
#<Number enumeration [2 10) at 2 by #<FUNCTION> XXXXXX>
cl-prompt> (enumerate 'number :start 2 :end 10 :by 3)
#<Number enumeration [2 10) at 2 by #<FUNCTION> XXXXXX>
"
(enumerate 'number :start start :end end :by incr))
......
......@@ -17,8 +17,15 @@
(:method ((x t)) nil)
(:method ((x string-enumeration)) t))
(defmethod enumerate ((x string) &key (start 0) end &allow-other-keys)
(make-instance 'string-enumeration :object x :start start :end end))
(defmethod enumerate ((s string) &key (start 0) end &allow-other-keys)
"Calling ENUMERATE on a STRING returns a STRING-ENUMERATION instance.
A STRING-ENUMERATION traverses the STRING s using the accessor CHAR.
START must be an integer between 0 and (length S). end must be an
integer between 0 and (length S) or NIL. The usual CL semantics
regarding sequence traversals applies."
(make-instance 'string-enumeration :object s :start start :end end))
(defmethod next ((x string-enumeration) &optional default)
(declare (ignore default))
......
......@@ -24,8 +24,13 @@
(setf (enumeration-end x) (length (enumeration-object x)))))
(defmethod enumerate ((x vector) &key (start 0) end &allow-other-keys)
(make-instance 'vector-enumeration :object x :start start :end end))
(defmethod enumerate ((v vector) &key (start 0) end &allow-other-keys)
"Calling ENUMERATE on a VECTOR returns a VECTOR-ENUMERATION instance.
START must be an integer between 0 and (length V). end must be an
integer between 0 and (length V) or NIL. The usual CL semantics
regarding sequence traversals applies."
(make-instance 'vector-enumeration :object v :start start :end end))
(defmethod has-more-elements-p ((x vector-enumeration))
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment