The cl-algebraic-data-type Reference Manual

Next: , Previous: , Up: (dir)   [Contents][Index]

The cl-algebraic-data-type Reference Manual

This is the cl-algebraic-data-type Reference Manual, version 1.2.0, generated automatically by Declt version 4.0 beta 2 "William Riker" on Mon Aug 15 03:25:39 2022 GMT+0.

Table of Contents


1 Introduction

CL-ALGEBRAIC-DATA-TYPE

by Robert Smith

CL-ALGEBRAIC-DATA-TYPE, or ADT, is a library for defining algebraic data types in a similar spirit to Haskell or Standard ML, as well as for operating on them.

We can define ADTs using defdata:

(adt:defdata maybe
  (just t)
  nothing)

which will define a new type maybe, with a unary constructor just, and a nullary constructor nothing. The t represents the data type of that field.

> (just 5)
#.(JUST 5)
> nothing
#.NOTHING

Note that the #. are printed so that they can be read back. This allows them to be used literally in quoted lists, for example.

> '(#.(just 1) #.nothing)
(#.(JUST 1) #.NOTHING)
> (typep (first *) 'maybe)
T

If this is annoying to you, you can set the variable adt:*print-adt-readably* to nil.

We can define our own version of a list via

(adt:defdata liszt
  (kons t liszt)
  knil)

which defines the binary constructor kons and the nullary constructor knil.

> (kons 1 (kons 2 knil))
#.(KONS 1 #.(KONS 2 #.KNIL))

At the end we will define kar and kdr.

For efficiency, we might specify the types more exactly. For a point type that supports rectangular and polar coordinates, which is also mutable, we might have:

(adt:defdata (point :mutable t)
  (rectangular float float)
  (polar float float))

The :mutable option signifies that the data is mutable.

When we have constructed a value, we can extract data out of it using match:

> (let ((pt (rectangular 1.0 2.0)))
    (adt:match point pt
      ((rectangular x y) (+ x y))
      ((polar _ _) nil)))
3.0

If we did not include the polar case, we would get a warning.

> (let ((pt (rectangular 1.0 2.0)))
    (adt:match point pt
      ((rectangular x y) (+ x y))))
; caught WARNING:
;   Non-exhaustive match. Missing cases: (POLAR)
3.0

We can also specify a fall-through:

> (let ((pt (rectangular 1.0 2.0)))
    (adt:match point pt
      ((rectangular x y) (+ x y))
      (_ nil)))
3.0

Since point is mutable, we can efficiently modify its fields using set-data.

> (defun mirror-point! (pt)
    (adt:with-data (rectangular x y) pt
      (adt:set-data pt (rectangular y x))))

> (let ((pt (rectangular 1.0 2.0)))
   (mirror-point! pt)
   (adt:match point pt
     ((rectangular x y) (format t "point is (~A, ~A)" x y))
     (_ nil))

will print point is (2.0, 1.0).

See examples.txt for examples.

Frequently Asked Questions

Q. How do we define kar and kdr for liszt?

A. Easy.

(defun kar (l)
  (adt:match liszt l
    ((kons a _) a)
    (knil knil)))

(defun kdr (l)
  (adt:match liszt l
    ((kons _ b) b)
    (knil knil)))

Q. Can I get the constructors dynamically for a particular ADT?

A. Yes. You can get the constructors and associated arity by calling the get-constructors function, which will return a list of (<constructor> <arity>) pairs. For example, given the liszt example above, we have

> (adt:get-constructors 'liszt)
((KONS 2) (KNIL 0))
T

The second value t represents the fact that the ADT is known and exists.

Q. I have an ADT defined, and I'd like to extend it with another ADT. How can I do that?

A. You can define a new ADT which includes another one. For example, consider the following Boolean ADT.

(adt:defdata bool
  true
  false)

Suppose you wanted to extend this to have a "fuzzy" option, a probability between true and false, specifically a real between 0 and 1 exclusive. We can create a fuzzy-bool which includes the bool type, as well as a unary fuzzy constructor. This is done by the :include option to defdata.

(adt:defdata (fuzzy-bool :include bool)
  (fuzzy (real (0) (1))))

Note that true and false are constructors for both bool and fuzzy-bool, as we can see with get-constructors.

> (adt:get-constructors 'bool)
((TRUE 0) (FALSE 0))
T
> (adt:get-constructors 'fuzzy-bool)
((TRUE 0) (FALSE 0) (FUZZY 1))
T

Q. Can we do parametric ADTs like I can in Haskell?

A. There is no support for it because Lisp doesn't have any useful notion of definable parametric types that aren't aliases of another existing parametric type.

Q. Why doesn't deeper pattern matching work?

A. It's not implemented, but it could be implemented for fields which are themselves algebraic data types. Patches welcome!


2 Systems

The main system appears first, followed by any subsystem dependency.


Previous: , Up: Systems   [Contents][Index]

2.1 cl-algebraic-data-type

A library for algebraic data types.

Author

Robert Smith <robert@stylewarning.com>

License

BSD 3-clause

Version

1.2.0

Dependencies
  • alexandria (system).
  • global-vars (system).
Source

cl-algebraic-data-type.asd.

Child Components

3 Files

Files are sorted by type and then listed depth-first from the systems components trees.


Next: , Previous: , Up: Files   [Contents][Index]

3.1 Lisp


3.1.1 cl-algebraic-data-type/cl-algebraic-data-type.asd

Source

cl-algebraic-data-type.asd.

Parent Component

cl-algebraic-data-type (system).

ASDF Systems

cl-algebraic-data-type.


3.1.2 cl-algebraic-data-type/package.lisp

Dependency

license.txt (file).

Source

cl-algebraic-data-type.asd.

Parent Component

cl-algebraic-data-type (system).

Packages

cl-algebraic-data-type.


3.1.3 cl-algebraic-data-type/utilities.lisp

Dependency

package.lisp (file).

Source

cl-algebraic-data-type.asd.

Parent Component

cl-algebraic-data-type (system).

Public Interface
Internals

3.1.4 cl-algebraic-data-type/defdata.lisp

Dependency

utilities.lisp (file).

Source

cl-algebraic-data-type.asd.

Parent Component

cl-algebraic-data-type (system).

Public Interface

3.1.5 cl-algebraic-data-type/match.lisp

Dependency

defdata.lisp (file).

Source

cl-algebraic-data-type.asd.

Parent Component

cl-algebraic-data-type (system).

Public Interface

match (macro).

Internals

duplicates (function).


Previous: , Up: Files   [Contents][Index]

3.2 Static


Previous: , Up: Static   [Contents][Index]

3.2.1 cl-algebraic-data-type/LICENSE.txt

Source

cl-algebraic-data-type.asd.

Parent Component

cl-algebraic-data-type (system).


4 Packages

Packages are listed by definition order.


Previous: , Up: Packages   [Contents][Index]

4.1 cl-algebraic-data-type

A package for defining algebraic data types.

Source

package.lisp.

Nickname

adt

Use List

common-lisp.

Public Interface
Internals

5 Definitions

Definitions are sorted by export status, category, package, and then by lexicographic order.


Next: , Previous: , Up: Definitions   [Contents][Index]

5.1 Public Interface


Next: , Previous: , Up: Public Interface   [Contents][Index]

5.1.1 Special variables

Special Variable: *print-adt-readably*

Print preceding #. when printing ADT values.

Package

cl-algebraic-data-type.

Source

defdata.lisp.


5.1.2 Macros

Macro: defdata (adt-name &body constructors)

Define a new ADT. ADT-name has the following grammar:

ADT-NAME := <symbol>
| (<symbol> <options>*)

There is no difference between specifying it as a symbol or as a singleton list. There are two possible options, specified as a property list:

* :MUTABLE {T, NIL} (default: NIL): Specifies whether the fields of the type are mutable, allowing the use of SET-DATA.

* :INCLUDE <adt-type>: Specifies whether another defined ADT should be inherited.

Constructors is a list of clauses with the following grammar:

<clause> := <symbol>
| (<symbol> <type-specifier>*)

Each clause defines a constructor for the ADT. Nullary constructors will define constants and all other constructors will define functions.

Package

cl-algebraic-data-type.

Source

defdata.lisp.

Macro: match (adt obj &body clauses)

Perform pattern matching on OBJ with (adt-type) ADT.

Each clause must have the following syntax:

<var> := <symbol> | ’_’
<lhs> := ’_’
| (<symbol> <var>*)
<clause> := (<lhs> <lisp code>)

The symbol ’_’ denotes a wildcard, as well as a fallthough.

Note that pattern matching is only shallow (patterns are one-level deep).

Package

cl-algebraic-data-type.

Source

match.lisp.

Macro: set-data (obj (name &rest new-values))

Mutate the fields of the ADT value OBJ whose constructor is NAME and whose updated values are NEW-VALUES based on order. If the symbol ’_’ is used as a value, that field is not updated. Trailing ’_’ may be omitted.

Package

cl-algebraic-data-type.

Source

defdata.lisp.

Macro: with-data ((name &rest vars) obj &body body)

Destructure the ADT value OBJ, whose constructor is NAME. VARS must be symbol which will be bound, or they must be the symbol ’_’, which means the value will not be bound.

Package

cl-algebraic-data-type.

Source

defdata.lisp.


Next: , Previous: , Up: Public Interface   [Contents][Index]

5.1.3 Ordinary functions

Function: algebraic-data-type-p (type)

Is TYPE a known algebraic data type?

Package

cl-algebraic-data-type.

Source

utilities.lisp.

Function: algebraic-data-value-p (value)

Is the value VALUE that of some algebraic data type?

Package

cl-algebraic-data-type.

Source

utilities.lisp.

Function: get-constructors (adt)

Get the constructors and their arity for the adt ADT. Two values will be returned:

1. If the ADT exists, then a list of pairs

(CONSTRUCTOR-SYMBOL ARITY).

If the ARITY is zero, then the CONSTRUCTOR-SYMBOL is a value as opposed to a function.

2. T if the ADT exists, NIL otherwise. This mimics the behavior of GETHASH.

Package

cl-algebraic-data-type.

Source

utilities.lisp.


5.1.4 Structures

Structure: algebraic-data-type

Abstract type for all algebraic data types, primarily used to identify such types.

Package

cl-algebraic-data-type.

Source

utilities.lisp.

Direct superclasses

structure-object.


5.2 Internals


Next: , Previous: , Up: Internals   [Contents][Index]

5.2.1 Macros

Macro: define-constant (name value)
Package

cl-algebraic-data-type.

Source

utilities.lisp.


Previous: , Up: Internals   [Contents][Index]

5.2.2 Ordinary functions

Function: duplicates (sequence &key test)
Package

cl-algebraic-data-type.

Source

match.lisp.

Function: ensure-car (x)
Package

cl-algebraic-data-type.

Source

utilities.lisp.

Function: ensure-list (x)
Package

cl-algebraic-data-type.

Source

utilities.lisp.

Function: field (name n)
Package

cl-algebraic-data-type.

Source

utilities.lisp.

Function: gen-names (n)
Package

cl-algebraic-data-type.

Source

utilities.lisp.

Function: internal (s)
Package

cl-algebraic-data-type.

Source

utilities.lisp.

Function: property-list-p (x &rest keys)
Package

cl-algebraic-data-type.

Source

utilities.lisp.

Function: set-constructors (adt constructors)
Package

cl-algebraic-data-type.

Source

utilities.lisp.

Function: unsplice (x)
Package

cl-algebraic-data-type.

Source

utilities.lisp.

Function: unwrap-singletons (list)
Package

cl-algebraic-data-type.

Source

utilities.lisp.

Function: wild? (s)
Package

cl-algebraic-data-type.

Source

utilities.lisp.


Appendix A Indexes


Next: , Previous: , Up: Indexes   [Contents][Index]

A.1 Concepts


Next: , Previous: , Up: Indexes   [Contents][Index]

A.2 Functions

Jump to:   A   D   E   F   G   I   M   P   S   U   W  
Index Entry  Section

A
algebraic-data-type-p: Public ordinary functions
algebraic-data-value-p: Public ordinary functions

D
defdata: Public macros
define-constant: Private macros
duplicates: Private ordinary functions

E
ensure-car: Private ordinary functions
ensure-list: Private ordinary functions

F
field: Private ordinary functions
Function, algebraic-data-type-p: Public ordinary functions
Function, algebraic-data-value-p: Public ordinary functions
Function, duplicates: Private ordinary functions
Function, ensure-car: Private ordinary functions
Function, ensure-list: Private ordinary functions
Function, field: Private ordinary functions
Function, gen-names: Private ordinary functions
Function, get-constructors: Public ordinary functions
Function, internal: Private ordinary functions
Function, property-list-p: Private ordinary functions
Function, set-constructors: Private ordinary functions
Function, unsplice: Private ordinary functions
Function, unwrap-singletons: Private ordinary functions
Function, wild?: Private ordinary functions

G
gen-names: Private ordinary functions
get-constructors: Public ordinary functions

I
internal: Private ordinary functions

M
Macro, defdata: Public macros
Macro, define-constant: Private macros
Macro, match: Public macros
Macro, set-data: Public macros
Macro, with-data: Public macros
match: Public macros

P
property-list-p: Private ordinary functions

S
set-constructors: Private ordinary functions
set-data: Public macros

U
unsplice: Private ordinary functions
unwrap-singletons: Private ordinary functions

W
wild?: Private ordinary functions
with-data: Public macros

Jump to:   A   D   E   F   G   I   M   P   S   U   W  

Next: , Previous: , Up: Indexes   [Contents][Index]

A.3 Variables

Jump to:   *  
S  
Index Entry  Section

*
*print-adt-readably*: Public special variables

S
Special Variable, *print-adt-readably*: Public special variables

Jump to:   *  
S