2
2
Fork
You've already forked nonempty
0
Non-empty collections for Common Lisp.
  • Common Lisp 100%
Find a file
2024年02月18日 20:32:03 +09:00
src test: test transducers support 2024年02月18日 19:53:40 +09:00
tests test: test transducers support 2024年02月18日 19:53:40 +09:00
.gitignore feat: qlot usage 2024年02月17日 20:43:20 +09:00
CHANGELOG.md docs: initial changelog 2024年02月18日 20:32:03 +09:00
LICENSE legal: add LICENSE 2024年02月17日 21:43:35 +09:00
nonempty.asd test: test transducers support 2024年02月18日 19:53:40 +09:00
qlfile test: scaffolding 2024年02月17日 21:59:08 +09:00
qlfile.lock test: scaffolding 2024年02月17日 21:59:08 +09:00
README.org docs: installation instructions 2024年02月18日 20:31:10 +09:00

nonempty

(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

Installation

This library is available on Ultralisp.

Qlot

qlot add ultralisp fosskers-cl-nonempty

API

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)))

Non-empty Lists

Functions specific to non-empty lists.

nel, cons

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))

car, cdr

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, filter, fold

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

Generics

length

The length of the given non-empty structure.

(in-package :nonempty)
(length (nel 1 2 3))
3

reverse

The reverse of the given non-empty structure.

(in-package :nonempty)
(reverse (nel 1 2 3))
#S(NELIST :HEAD 3 :TAIL (2 1))

elt, last

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

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))

to-list

Convert this non-empty collection into a normal list.

(in-package :nonempty)
(to-list (nel 1 2 3))
(1 2 3)

Transducers Support

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))

Further Work

  • Non-empty Vectors
  • Non-empty Hash Tables