(This README is best viewed on Codeberg.)
Non-empty collections for Common Lisp.
Non-emptiness can be a powerful guarantee. There are often times when a collection is passed to a function, but must contain some value to be useful. In these cases we must manually check, or otherwise account for NIL in our logic. This can muddle the clarity of the code, especially when emptiness is not a valid state. It is here that non-empty variants of the usual collection types can be used to great effect.
(in-package :nonempty)
;; Always succeeds, never nil.
(car (nel 1 2 3))
1
The examples here use (in-package :nonempty)
for brevity, but it is assumed that
you will set a nickname in your own code:
(defpackage foo
(:use :cl)
(:local-nicknames (:ne :nonempty)))
Functions specific to non-empty lists.
Construct a non-empty list from at least one input argument.
(in-package :nonempty)
(nel 1 2 3)
#S(NELIST :HEAD 1 :TAIL (2 3))
Append a new item onto the front of a non-empty list.
(in-package :nonempty)
(cons 0 (nel 1 2 3))
#S(NELIST :HEAD 0 :TAIL (1 2 3))
The first element of a non-empty list. Always succeeds.
(in-package :nonempty)
(car (nel 1 2 3))
1
The possibly-empty tail of a non-empty list.
(in-package :nonempty)
(cdr (nel 1 2 3))
(2 3)
Map some FN over the given ITEMS, yielding a new non-empty list.
(in-package :nonempty)
(map #'1+ (nel 1 2 3))
#S(NELIST :HEAD 2 :TAIL (3 4))
Keep ITEMS for which a PRED function succeeds. Not guaranteed to be non-empty.
(in-package :nonempty)
(filter #'evenp (nel 1 2 3 4 5 6))
(2 4 6)
Reduce some ITEMS via a 2-arity FN.
(in-package :nonempty)
(fold #'+ (nel 1 2 3))
6
(in-package :nonempty)
(fold #'+ (nel 1 2 3) :seed 10)
16
The length of the given non-empty structure.
(in-package :nonempty)
(length (nel 1 2 3))
3
The reverse of the given non-empty structure.
(in-package :nonempty)
(reverse (nel 1 2 3))
#S(NELIST :HEAD 3 :TAIL (2 1))
The element of ITEMS specified by INDEX.
(in-package :nonempty)
(elt (nel 1 2 3) 2)
3
The last element of the ITEMS. Guaranteed to exist.
(in-package :nonempty)
(last (nel 1 2 3))
3
Append some OTHER collection to a NONEMPTY one.
(in-package :nonempty)
(append (nel 1 2 3) (nel 4 5 6))
#S(NELIST :HEAD 1 :TAIL (2 3 4 5 6))
(in-package :nonempty)
(append (nel 1 2 3) '(4 5 6))
#S(NELIST :HEAD 1 :TAIL (2 3 4 5 6))
Convert this non-empty collection into a normal list.
(in-package :nonempty)
(to-list (nel 1 2 3))
(1 2 3)
For additional high-level collection operations, support for Transducers is
provided by the nonempty/transducers
system. As this incurs additions
dependencies, it is entirely optional. The examples below use full symbol paths,
but it’s assumed that you’ll set appropriate nicknames:
(defpackage foo
(:use :cl)
(:local-nicknames (:ne :nonempty)
(:nt :nonempty/transducers)
(:t :transducers)))
Non-empty lists can be used as “sources” as-is:
(in-package :transducers)
(transduce (map #'1+) #'cons (nonempty:nel 1 2 3))
(2 3 4)
And you can also reduce back into a non-empty list, provided that something actually made it through the transduction:
(in-package :transducers)
(transduce (map #'1+) #'nonempty/transducers:nelist (nonempty:nel 1 2 3))
#S(NONEMPTY:NELIST :HEAD 2 :TAIL (3 4))
- Non-empty Vectors
- Non-empty Hash Tables