https://github.com/fosskers/cl-nonempty
Non-empty collections for Common Lisp.
https://github.com/fosskers/cl-nonempty
collections common-lisp non-empty
Last synced: 4 months ago
JSON representation
Non-empty collections for Common Lisp.
- Host: GitHub
- URL: https://github.com/fosskers/cl-nonempty
- Owner: fosskers
- License: lgpl-3.0
- Created: 2024-02-17T12:42:18.000Z (over 1 year ago)
- Default Branch: master
- Last Pushed: 2024-02-18T11:34:55.000Z (over 1 year ago)
- Last Synced: 2025-01-01T23:11:41.133Z (6 months ago)
- Topics: collections, common-lisp, non-empty
- Language: Common Lisp
- Homepage:
- Size: 14.6 KB
- Stars: 3
- Watchers: 2
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.org
- License: LICENSE
Awesome Lists containing this project
README
#+title: nonempty
(This README is best viewed on [[https://codeberg.org/fosskers/nonempty][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.#+begin_src lisp :exports both
(in-package :nonempty);; Always succeeds, never nil.
(car (nel 1 2 3))
#+end_src#+RESULTS:
: 1* API
The examples here use ~(in-package :nonempty)~ for brevity, but it is assumed that
you will set a nickname in your own code:#+begin_src lisp
(defpackage foo
(:use :cl)
(:local-nicknames (:ne :nonempty)))
#+end_src** Non-empty Lists
Functions specific to non-empty lists.
*** nel, cons
Construct a non-empty list from at least one input argument.
#+begin_src lisp :exports both
(in-package :nonempty)
(nel 1 2 3)
#+end_src#+RESULTS:
: #S(NELIST :HEAD 1 :TAIL (2 3))Append a new item onto the front of a non-empty list.
#+begin_src lisp :exports both
(in-package :nonempty)
(cons 0 (nel 1 2 3))
#+end_src#+RESULTS:
: #S(NELIST :HEAD 0 :TAIL (1 2 3))*** car, cdr
The first element of a non-empty list. Always succeeds.
#+begin_src lisp :exports both
(in-package :nonempty)
(car (nel 1 2 3))
#+end_src#+RESULTS:
: 1The possibly-empty tail of a non-empty list.
#+begin_src lisp :exports both :results verbatim
(in-package :nonempty)
(cdr (nel 1 2 3))
#+end_src#+RESULTS:
: (2 3)*** map, filter, fold
Map some FN over the given ITEMS, yielding a new non-empty list.
#+begin_src lisp :exports both
(in-package :nonempty)
(map #'1+ (nel 1 2 3))
#+end_src#+RESULTS:
: #S(NELIST :HEAD 2 :TAIL (3 4))Keep ITEMS for which a PRED function succeeds. Not guaranteed to be non-empty.
#+begin_src lisp :exports both :results verbatim
(in-package :nonempty)
(filter #'evenp (nel 1 2 3 4 5 6))
#+end_src#+RESULTS:
: (2 4 6)Reduce some ITEMS via a 2-arity FN.
#+begin_src lisp :exports both
(in-package :nonempty)
(fold #'+ (nel 1 2 3))
#+end_src#+RESULTS:
: 6#+begin_src lisp :exports both
(in-package :nonempty)
(fold #'+ (nel 1 2 3) :seed 10)
#+end_src#+RESULTS:
: 16** Generics
*** length
The length of the given non-empty structure.
#+begin_src lisp :exports both
(in-package :nonempty)
(length (nel 1 2 3))
#+end_src#+RESULTS:
: 3*** reverse
The reverse of the given non-empty structure.
#+begin_src lisp :exports both
(in-package :nonempty)
(reverse (nel 1 2 3))
#+end_src#+RESULTS:
: #S(NELIST :HEAD 3 :TAIL (2 1))*** elt, last
The element of ITEMS specified by INDEX.
#+begin_src lisp :exports both
(in-package :nonempty)
(elt (nel 1 2 3) 2)
#+end_src#+RESULTS:
: 3The last element of the ITEMS. Guaranteed to exist.
#+begin_src lisp :exports both
(in-package :nonempty)
(last (nel 1 2 3))
#+end_src#+RESULTS:
: 3*** append
Append some OTHER collection to a NONEMPTY one.
#+begin_src lisp :exports both
(in-package :nonempty)
(append (nel 1 2 3) (nel 4 5 6))
#+end_src#+RESULTS:
: #S(NELIST :HEAD 1 :TAIL (2 3 4 5 6))#+begin_src lisp :exports both
(in-package :nonempty)
(append (nel 1 2 3) '(4 5 6))
#+end_src#+RESULTS:
: #S(NELIST :HEAD 1 :TAIL (2 3 4 5 6))*** to-list
Convert this non-empty collection into a normal list.
#+begin_src lisp :exports both :results verbatim
(in-package :nonempty)
(to-list (nel 1 2 3))
#+end_src#+RESULTS:
: (1 2 3)
** Transducers SupportFor additional high-level collection operations, support for [[https://codeberg.org/fosskers/cl-transducers][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:#+begin_src lisp
(defpackage foo
(:use :cl)
(:local-nicknames (:ne :nonempty)
(:nt :nonempty/transducers)
(:t :transducers)))
#+end_srcNon-empty lists can be used as "sources" as-is:
#+begin_src lisp :exports both :results verbatim
(in-package :transducers)
(transduce (map #'1+) #'cons (nonempty:nel 1 2 3))
#+end_src#+RESULTS:
: (2 3 4)And you can also reduce back into a non-empty list, provided that something
actually made it through the transduction:#+begin_src lisp :exports both :results verbatim
(in-package :transducers)
(transduce (map #'1+) #'nonempty/transducers:nelist (nonempty:nel 1 2 3))
#+end_src#+RESULTS:
: #S(NONEMPTY:NELIST :HEAD 2 :TAIL (3 4))* Further Work
- Non-empty Vectors
- Non-empty Hash Tables* See Also
- [[https://lib.rs/crates/nonempty-collections][Rust: nonempty-collections]]
- [[https://codeberg.org/fosskers/cl-transducers][Transducers]]
- [[https://codeberg.org/fosskers/nonempty][Codeberg Mirror]]
- [[https://github.com/fosskers/cl-nonempty][Github Mirror]]