diff --git a/README.markdown b/README.markdown new file mode 100644 index 0000000..cabf7b7 --- /dev/null +++ b/README.markdown @@ -0,0 +1,215 @@ +trivial-types - Trivial type definitions +======================================== + +TRIVIAL-TYPES provides missing but important type +definitions such as PROPER-LIST, ASSOCIATION-LIST, PROPERTY-LIST and +TUPLE. + +By using these types, you can keep type declarations more +accurate. For example, you may write a class definition like: + + (defclass person () + ((name :type string)) + ((age :type fixnum)) + ((friends :type list))) + +However, it is not obvious for anyone except you that FRIENDS slot has +only a list of person. If you want declare FRIENDS slot more +accurately, PROPER-LIST is the best for that: + + (defclass person () + ((name :type string)) + ((age :type fixnum)) + ((friends :type (proper-list person)))) + +In addition, TRIVIAL-TYPES also provides standard designators defined +in ANSI standard such as PACKAGE-DESIGNATOR. They are useful when you +write a function that takes a package-oid argument like: + + (defun list-external-symbols (package) + (declare (package-designator package)) + (loop for symbol being the external-symbol of package + collect symbol)) + +[Package] trivial-types +----------------------- + +## [Function] proper-list-p + + proper-list-p object + +Returns true if OBJECT is a proper list. + +Examples: + + (proper-list-p 1) => NIL + (proper-list-p '(1 . 2)) => NIL + (proper-list-p nil) => T + (proper-list-p '(1 2 3)) => T + +## [Type] proper-list + + proper-list &optional (element-type '*) + +Equivalent to `(and list (satisfies proper-list-p))`. ELEMENT-TYPE +is just ignored. + +Examples: + + (typep '(1 2 3) '(proper-list integer)) => T + (typep '(1 2 3) '(proper-list string)) => T + +## [Function] property-list-p + + property-list-p object + +Returns true if OBJECT is a property list. + +Examples: + + (property-list-p 1) => NIL + (property-list-p '(1 2 3)) => NIL + (property-list-p '(foo)) => NIL + (property-list-p nil) => T + (property-list-p '(foo 1)) => T + (property-list-p '(:a 1 :b 2)) => T + +## [Type] property-list + + property-list &optional (value-type '*) + +Equivalent to `(and list (satisfies +property-list-p))`. VALUE-TYPE is just ignored. + +Examples: + + (typep '(:a 1 :b 2) '(property-list integer)) => T + (typep '(:a 1 :b 2) '(property-list string)) => T + +## [Function] association-list-p + + association-list-p var + +Returns true if OBJECT is an association list. + +Examples: + + (association-list-p 1) => NIL + (association-list-p '(1 2 3)) => NIL + (association-list-p nil) => T + (association-list-p '((foo))) => T + (association-list-p '((:a . 1) (:b . 2))) => T + +## [Type] association-list + + association-list &optional (key-type '*) (value-type '*) + +Equivalent to `(proper-list (cons KEY-TYPE VALUE-TYPE))`. KEY-TYPE +and VALUE-TYPE are just ignored. + +Examples: + + (typep '((:a . 1) (:b . 2)) '(association-list integer)) => T + (typep '((:a . 1) (:b . 2)) '(association-list string)) => T + +## [Function] tuplep + + tuplep object + +Returns true if OBJECT is a tuple, meaning a proper list. + +Examples: + + (tuplep 1) => NIL + (tuplep '(1 . 2)) => NIL + (tuplep nil) => T + (tuplep '(1 2 3)) => T + +## [Type] tuple + + tuple &rest element-types + +Equivalent to `(and list (cons ARG1 (cons ARG2 (cons ARG3 ...))))` +where ARGn is each element of ELEMENTS-TYPES. + +Examples: + + (typep 1 'tuple) => NIL + (typep '(1 . 2) 'tuple) => NIL + (typep '(1 2 3) 'tuple) => NIL + (typep '(1 2 3) '(tuple integer integer)) => NIL + (typep '(1 2 3) '(tuple string integer integer)) => NIL + (typep nil 'tuple) => T + (typep nil '(tuple)) => T + (typep '(1 2 3) '(tuple integer integer integer)) => T + +## [Type] character-designator + + character-designator + +## [Type] function-designator + + function-designator + +## [Type] file-position-designator + + file-position-designator + +## [Type] list-designator + + list-designator + +## [Type] package-designator + + package-designator + +## [Type] pathname-designator + + pathname-designator + +## [Type] stream-designator + + stream-designator + +## [Type] string-designator + + string-designator + +## [Function] file-associated-stream-p + + file-associated-stream-p stream + +Returns true if STREAM is a stream associated to a file. + +## [Type] file-associated-stream + + file-associated-stream + +Equivalent to `(and stream (satisfies file-associated-stream-p))`. + +## [Type] non-nil + + non-nil &optional type + +Equivalent to `(and (not null) TYPE)` if TYPE is given, +otherwise `(not null)`. + +Examples: + + (typep nil '(non-nil symbol)) => NIL + +## [Function] type-specifier-p + + type-specifier-p type-specifier + +Returns true if TYPE-SPECIFIER is a valid type specfiier. + +Authors +------- + +* Tomohiro Matsuyama + +License +------- + +LLGPL diff --git a/src/combinators.lisp b/src/combinators.lisp index 62cbe7c..7c218ac 100644 --- a/src/combinators.lisp +++ b/src/combinators.lisp @@ -1,6 +1,12 @@ (in-package :trivial-types) (deftype non-nil (&optional type) + "Equivalent to `(and (not null) TYPE)` if TYPE is given, +otherwise `(not null)`. + +Examples: + + (typep nil '(non-nil symbol)) => NIL" (if type `(and (not null) ,type) '(not null))) diff --git a/src/lists.lisp b/src/lists.lisp index 30449c6..c100080 100644 --- a/src/lists.lisp +++ b/src/lists.lisp @@ -16,14 +16,39 @@ (t (return))))) (defun proper-list-p (object) + "Returns true if OBJECT is a proper list. + +Examples: + + (proper-list-p 1) => NIL + (proper-list-p '(1 . 2)) => NIL + (proper-list-p nil) => T + (proper-list-p '(1 2 3)) => T" (declare (optimize . #.*standard-optimize-qualities*)) (%proper-list-p object)) (deftype proper-list (&optional (element-type '*)) + "Equivalent to `(and list (satisfies proper-list-p))`. ELEMENT-TYPE +is just ignored. + +Examples: + + (typep '(1 2 3) '(proper-list integer)) => T + (typep '(1 2 3) '(proper-list string)) => T" (declare (ignore element-type)) '(and list (satisfies proper-list-p))) (defun property-list-p (object) + "Returns true if OBJECT is a property list. + +Examples: + + (property-list-p 1) => NIL + (property-list-p '(1 2 3)) => NIL + (property-list-p '(foo)) => NIL + (property-list-p nil) => T + (property-list-p '(foo 1)) => T + (property-list-p '(:a 1 :b 2)) => T" (declare (optimize . #.*standard-optimize-qualities*)) (typecase object (null t) @@ -33,27 +58,71 @@ (return t) (let ((key (car object)) (next (cdr object))) - (if (or (not (keywordp key)) + (if (or (not (symbolp key)) (not (consp next))) (return) (setq object (cdr next))))))))) (deftype property-list (&optional (value-type '*)) + "Equivalent to `(and list (satisfies +property-list-p))`. VALUE-TYPE is just ignored. + +Examples: + + (typep '(:a 1 :b 2) '(property-list integer)) => T + (typep '(:a 1 :b 2) '(property-list string)) => T" (declare (ignore value-type)) '(and list (satisfies property-list-p))) (defun association-list-p (var) + "Returns true if OBJECT is an association list. + +Examples: + + (association-list-p 1) => NIL + (association-list-p '(1 2 3)) => NIL + (association-list-p nil) => T + (association-list-p '((foo))) => T + (association-list-p '((:a . 1) (:b . 2))) => T" (declare (optimize . #.*standard-optimize-qualities*)) (%proper-list-p var 'cons)) (deftype association-list (&optional (key-type '*) (value-type '*)) + "Equivalent to `(proper-list (cons KEY-TYPE VALUE-TYPE))`. KEY-TYPE +and VALUE-TYPE are just ignored. + +Examples: + + (typep '((:a . 1) (:b . 2)) '(association-list integer)) => T + (typep '((:a . 1) (:b . 2)) '(association-list string)) => T" `(proper-list (cons ,key-type ,value-type))) (defun tuplep (object) + "Returns true if OBJECT is a tuple, meaning a proper list. + +Examples: + + (tuplep 1) => NIL + (tuplep '(1 . 2)) => NIL + (tuplep nil) => T + (tuplep '(1 2 3)) => T" (declare (optimize . #.*standard-optimize-qualities*)) (%proper-list-p object)) (deftype tuple (&rest element-types) + "Equivalent to `(and list (cons ARG1 (cons ARG2 (cons ARG3 ...))))` +where ARGn is each element of ELEMENTS-TYPES. + +Examples: + + (typep 1 'tuple) => NIL + (typep '(1 . 2) 'tuple) => NIL + (typep '(1 2 3) 'tuple) => NIL + (typep '(1 2 3) '(tuple integer integer)) => NIL + (typep '(1 2 3) '(tuple string integer integer)) => NIL + (typep nil 'tuple) => T + (typep nil '(tuple)) => T + (typep '(1 2 3) '(tuple integer integer integer)) => T" `(and list ,(reduce (lambda (element-type type) `(cons ,element-type ,type)) element-types diff --git a/src/packages.lisp b/src/packages.lisp index 986f1c5..d85da82 100644 --- a/src/packages.lisp +++ b/src/packages.lisp @@ -2,13 +2,7 @@ (defpackage :trivial-types (:use :cl) - (:export ;; combinators.lisp - #:non-nil - ;; streams.lisp - #:file-associated-stream-p - #:file-associated-stream - ;; lists.lisp - #:proper-list-p + (:export #:proper-list-p #:proper-list #:property-list-p #:property-list @@ -16,7 +10,7 @@ #:association-list #:tuplep #:tuple - ;; designators.lisp + #:character-designator #:function-designator #:file-position-designator @@ -24,4 +18,11 @@ #:package-designator #:pathname-designator #:stream-designator - #:string-designator)) + #:string-designator + + #:file-associated-stream-p + #:file-associated-stream + + #:non-nil + + #:type-specifier-p)) diff --git a/src/streams.lisp b/src/streams.lisp index c8c4839..9ee813b 100644 --- a/src/streams.lisp +++ b/src/streams.lisp @@ -1,6 +1,7 @@ (in-package :trivial-types) (defun file-associated-stream-p (stream) + "Returns true if STREAM is a stream associated to a file." (declare (optimize . #.*standard-optimize-qualities*)) (or (typep stream 'file-stream) (and (typep stream 'synonym-stream) @@ -11,4 +12,5 @@ (file-associated-stream-p target-stream))))) (deftype file-associated-stream () + "Equivalent to `(and stream (satisfies file-associated-stream-p))`." '(and stream (satisfies file-associated-stream-p))) diff --git a/src/typespecs.lisp b/src/typespecs.lisp new file mode 100644 index 0000000..03bffcb --- /dev/null +++ b/src/typespecs.lisp @@ -0,0 +1,8 @@ +(in-package :trivial-types) + +(defun type-specifier-p (type-specifier) + "Returns true if TYPE-SPECIFIER is a valid type specfiier." + (or (documentation type-specifier 'type) + #+sbcl (sb-ext:valid-type-specifier-p type-specifier) + #+openmcl (ccl:type-specifier-p type-specifier) + #+ecl (c::valid-type-specifier type-specifier))) diff --git a/trivial-types.asd b/trivial-types.asd index ffc231c..12578a7 100644 --- a/trivial-types.asd +++ b/trivial-types.asd @@ -5,6 +5,36 @@ (in-package :trivial-types-asd) (defsystem :trivial-types + :description "Trivial type definitions" + :long-description "TRIVIAL-TYPES provides missing but important type +definitions such as PROPER-LIST, ASSOCIATION-LIST, PROPERTY-LIST and +TUPLE. + +By using these types, you can keep type declarations more +accurate. For example, you may write a class definition like: + + (defclass person () + ((name :type string)) + ((age :type fixnum)) + ((friends :type list))) + +However, it is not obvious for anyone except you that FRIENDS slot has +only a list of person. If you want declare FRIENDS slot more +accurately, PROPER-LIST is the best for that: + + (defclass person () + ((name :type string)) + ((age :type fixnum)) + ((friends :type (proper-list person)))) + +In addition, TRIVIAL-TYPES also provides standard designators defined +in ANSI standard such as PACKAGE-DESIGNATOR. They are useful when you +write a function that takes a package-oid argument like: + + (defun list-external-symbols (package) + (declare (package-designator package)) + (loop for symbol being the external-symbol of package + collect symbol))" :version "0.1" :author "Tomohiro Matsuyama" :license "LLGPL" @@ -12,7 +42,8 @@ :serial t :components ((:file "packages") (:file "specials") - (:file "combinators") - (:file "streams") (:file "lists") - (:file "designators"))))) + (:file "designators") + (:file "streams") + (:file "combinators") + (:file "typespecs")))))