The modf Reference Manual

Table of Contents

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

The modf Reference Manual

This is the modf Reference Manual, generated automatically by Declt version 2.3 "Robert April" on Tue Feb 20 09:05:29 2018 GMT+0.


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

1 Introduction


* Modf

Modf is a =setf= like macro for functional programming.  Like =setf=, Modf knows
how to modify many Lisp objects such that a place will evaluate to a new value
of your choosing.  Unlike =setf=, Modf doesn't mutate the data in anyway.
Instead it creates a new object with the requested changes in place.  See [[http://directed-procrastination.blogspot.com/2011/05/introducting-modf-setf-for-functional.html][my
blog]] post on Modf for a bit more info.  Be warned though, while the gist is
definitely there, it has become a bit out of date as Modf has progressed.

** What does Modf do?

To give a pathologic example, Modf allows you to change =t= to =nil= in the
following expression easily.

#+BEGIN_SRC lisp
  (defparameter *crazy* '(1 #(a (2 #(b (3 #(c (4 t))))))))
  ==> *CRAZY*
  
  ;; Change that last value with Modf
  (modf
   (cadr (aref (cadr (aref (cadr (aref (cadr *crazy*) 1)) 1)) 1))
   nil)
  ==> (1 #(A (2 #(B (3 #(C (4 NIL)))))))
  
  ;; But note that the original data is unchanged
  ,*crazy*
  ==> (1 #(A (2 #(B (3 #(C (4 T)))))))
  
  ;; Note that the Modf form looks a lot like how you would use setf
  (setf
   (cadr (aref (cadr (aref (cadr (aref (cadr *crazy*) 1)) 1)) 1))
   nil)
  ==> NIL
  
  ,*crazy*
  ==> (1 #(A (2 #(B (3 #(C (4 NIL)))))))
  
  ;; What does Modf gain us, take a look.  Look it over.  It's all necessary
  (macroexpand
   '(modf
     (cadr (aref (cadr (aref (cadr (aref (cadr *crazy*) 1)) 1)) 1))
     nil))
  
  ==>
  (LET ((#:G1556 *CRAZY*))
    (CONS (CAR #:G1556)
          (LET ((#:G1555 (CDR #:G1556)))
            (CONS
             (LET ((#:G1554 (CAR #:G1555)))
               (FUNCALL (MODF-FN AREF)
                        (LET ((#:G1553 (AREF #:G1554 1)))
                          (CONS (CAR #:G1553)
                                (LET ((#:G1552 (CDR #:G1553)))
                                  (CONS
                                   (LET ((#:G1551 (CAR #:G1552)))
                                     (FUNCALL (MODF-FN AREF)
                                              (LET ((#:G1550 (AREF #:G1551 1)))
                                                (CONS (CAR #:G1550)
                                                      (LET ((#:G1549
                                                              (CDR #:G1550)))
                                                        (CONS
                                                         (LET ((#:G1548
                                                                 (CAR #:G1549)))
                                                           (FUNCALL
                                                            (MODF-FN AREF)
                                                            (LET ((#:G1547
                                                                    (AREF #:G1548 1)))
                                                              (CONS (CAR #:G1547)
                                                                    (LET ((#:G1546
                                                                            (CDR
                                                                             #:G1547)))
                                                                      (CONS NIL
                                                                            (CDR
                                                                             #:G1546)))))
                                                            #:G1548 1))
                                                         (CDR #:G1549)))))
                                              #:G1551 1))
                                   (CDR #:G1552)))))
                        #:G1554 1))
             (CDR #:G1555)))))
#+END_SRC

The aim is to make this work for any Lisp object, including CLOS objects and
structures.

** How does Modf work?

It works similar to the way =setf= works.  With =setf= expansions are defined
that take some kind of accessor function and turn it into a function that sets
the value at that place.  In Modf, expansions are defined that turn an accessor
function into a function that builds a new object the specified change in place.

** Where does Modf work?

Modf strives to be portable and work everywhere as long as Modf expansion
functions are defined.  See the section /Defining your own Modf Expansions/.  I
aim to cover all primitive data types in CL.  As of now, it should work in any
Lisp when working with lists, arrays, hash tables, and, given you have defined
your Modf expanders for your data types, class instances and structs.

For usability purposes, however, a lot of effort has gone into making Modf work
for data even if Modf expansions haven't been defined.  This is a very difficult
to impossible task.  For one, we have no way of knowing which argument holds the
actual data structure.  If no expansion is defined, we assume it is at the first
argument of the place (adjusting for =apply= statements).

In the case of class accessor methods without defined Modf expansions,
Closer-Mop is used to examine the data at run time and produce the functional
changes.  For structures we don't even have Closer-Mop to help us and a series
of heuristics are used at run time to try to invert accessor functions (again,
only if no Modf expander has been defined).

If Modf doesn't work for something common out of the box, feel free to post a
bug report.  It would be even better if you can think of a way figure out what
to do.

Modf is tested regularly on the major Libre Software implementations (SBCL,
CMUCL, CCL, CLISP, ECL).

** Defining your own Modf expansions

Modf works my defining various expansion constructs.  These expansion constructs
can be in the form of:

 1. *Rewrite Rules* via =define-modf-rewrite=, a simple macro like facility that
    rewrites the place you want to =modf= into something simpler.  Think =(cadr
    x)= -> =(car (cdr x))=.

 2. *Expanders* via =define-modf-expander=, a more general expansion mechanism
    where you define a function that is given the place to be modded, the
    current value of that place, and the new value it should be modded to.

 3. *Modf functions and Methods* via =define-modf-function= and
    =define-modf-method=, which you should think of as a way to define =(setf
    fn)= like functions for Modf.

In principle, the last construct alone is enough to do anything you want.  The
others are included for your convenience and with thoughts of compiler
optimization on the in place expansions performed by expanders.

For expanders and Modf functions/methods, you need to specify which argument
actually holds the data that is being modified.  This is given as an extra
argument after the name.

** Known issues

 1. Tons of stuff with ABCL.  It actually works for most things in ABCL, but I
    don't have the patience to get the test suite running.

 2. Perhaps issues with order of evaluation.  I haven't gone through a thorough
    audit of this yet.

** Documentation

Working on it.  This is supposed to be a literate program, but the comments in
the source are chicken scratch.

** Author

Zach Kost-Smith


** License

3-Clause BSD


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

2 Systems

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


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

2.1 modf

Author

Zach Kost-Smith <zachkostsmith@gmail.com>

License

3 Clause BSD (http://opensource.org/licenses/BSD-3-Clause)

Description

A SETF like macro for functional programming

Long Description

This library simplifies functional programming by making it easier to make new data structures with specified changes in place.

Dependencies
Source

modf.asd (file)

Components

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

3 Files

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


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

3.1 Lisp


Next: , Previous: , Up: Lisp files   [Contents][Index]

3.1.1 modf.asd

Location

modf.asd

Systems

modf (system)


Next: , Previous: , Up: Lisp files   [Contents][Index]

3.1.2 modf/package.lisp

Parent

modf (system)

Location

package.lisp

Packages

modf


Next: , Previous: , Up: Lisp files   [Contents][Index]

3.1.3 modf/utils.lisp

Dependency

package.lisp (file)

Parent

modf (system)

Location

utils.lisp

Internal Definitions

mkstr (function)


Next: , Previous: , Up: Lisp files   [Contents][Index]

3.1.4 modf/modf.lisp

Dependency

utils.lisp (file)

Parent

modf (system)

Location

modf.lisp

Exported Definitions
Internal Definitions

Next: , Previous: , Up: Lisp files   [Contents][Index]

3.1.5 modf/rewrite-rules.lisp

Dependency

modf.lisp (file)

Parent

modf (system)

Location

rewrite-rules.lisp


Next: , Previous: , Up: Lisp files   [Contents][Index]

3.1.6 modf/basic.lisp

Dependency

rewrite-rules.lisp (file)

Parent

modf (system)

Location

basic.lisp

Internal Definitions

Previous: , Up: Lisp files   [Contents][Index]

3.1.7 modf/modf-def.lisp

Dependency

basic.lisp (file)

Parent

modf (system)

Location

modf-def.lisp

Packages

modf-def

Exported Definitions
Internal Definitions

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

4 Packages

Packages are listed by definition order.


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

4.1 modf

Source

package.lisp (file)

Use List
Used By List

modf-def

Exported Definitions
Internal Definitions

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

4.2 modf-def

Source

modf-def.lisp (file)

Use List
Exported Definitions
Internal Definitions

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

5 Definitions

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


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

5.1 Exported definitions


Previous: , Up: Exported definitions   [Contents][Index]

5.1.1 Macros

Macro: defclass NAME DIRECT-SUPERCLASSES DIRECT-SLOTS &rest OPTIONS

Define Modf expansions for class slot accessor and reader methods.

Package

modf-def

Source

modf-def.lisp (file)

Macro: define-modf-expander NAME NTH-ARG (EXPR VAL NEW-VAL) &body BODY

Define a new expander which inverts forms starting with NAME. Your function should return an expansion from EXPR to a form that will build a new object that has NEW-VAL in the place specified by expr. NTH-ARG marks which argument is considered the actual data which will be inverted next.

Package

modf

Source

modf.lisp (file)

Macro: define-modf-for-class-slots CLASS-NAME-OR-DEFINITION

This macro defines Modf expanders for a class. We can do this given the definition form for the class (much like with DEFINE-MODF-FOR-STRUCT-SLOTS) or the a name of a finalized class.

Package

modf-def

Source

modf-def.lisp (file)

Macro: define-modf-for-struct-slots STRUCTURE-DEFINITION-FORM

This macro defines Modf expanders for structure slots when given a structure definition form.

Package

modf-def

Source

modf-def.lisp (file)

Macro: define-modf-function NAME NTH-ARG (NEW-VAL &rest ARGS) &body BODY

Define a new modf function. It inverts NAME forms by modifying the NTH-ARG term of the arguments of the place form in the MODF macro.

Package

modf

Source

modf.lisp (file)

Macro: define-modf-method NAME NTH-ARG (NEW-VAL &rest ARGS) &body BODY

Define a new modf method. It inverts NAME forms by modifying the NTH-ARG term of the arguments of the place form in the MODF macro. This method can specialize on any of ARGS.

Package

modf

Source

modf.lisp (file)

Macro: define-modf-rewrite NAME (EXPR) &body BODY

Define a new rewrite rule. If a form starting with NAME is encountered, call the defined function to return a form that we can deal with (i.e. one defined via DEFINE-MODF-EXPANDER, DEFINE-MODF-FUNCTION, and DEFINE-MODF-METHOD).

Package

modf

Source

modf.lisp (file)

Macro: defstruct NAME-AND-OPTIONS &rest SLOT-DESCRIPTIONS

Define a new structure with Modf expansions for slots.

Package

modf-def

Source

modf-def.lisp (file)

Macro: fsetf PLACE VALUE &rest MORE
Package

modf

Source

modf.lisp (file)

Macro: modf PLACE VALUE &rest MORE

Make a new object (which may use some of the old object) such that PLACE evaluates to VALUE.

MORE should have the form...

MORE : NIL
| (TEMPORARY-BINDING ANOTHER-MODF-PLACE ANOTHER-VALUE . MORE)

Use it to specify a temporary binding for the new object created which will be used in the subsequence MODF-PLACE NEW-VALUE pairs until the end of the MODF form.

Package

modf

Source

modf.lisp (file)

Macro: modf-eval &rest ARGS
Package

modf

Source

modf.lisp (file)

Macro: modf-fn SYMBOL

Expand to the defined Modf function. Basically, (MODF-FN SYM) is the functional analog of #’(SETF SYM).

Package

modf

Source

modf.lisp (file)


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

5.2 Internal definitions


Next: , Previous: , Up: Internal definitions   [Contents][Index]

5.2.1 Special variables

Special Variable: *accessor-heuristics*

This controls whether we should make educated guesses regarding inverting structure slot readers. For strictly correct behavior, set this to nil.

Package

modf

Source

modf.lisp (file)

Special Variable: *modf-expansions*

Holds expansion functions

Package

modf

Source

modf.lisp (file)

Special Variable: *modf-nth-arg*

Holds what argument to try to invert next.

Package

modf

Source

modf.lisp (file)

Special Variable: *modf-rewrites*
Package

modf

Source

modf.lisp (file)

Special Variable: *special-modf-forms*
Package

modf

Source

modf.lisp (file)


Next: , Previous: , Up: Internal definitions   [Contents][Index]

5.2.2 Functions

Function: accessor-in EXPR
Package

modf

Source

modf.lisp (file)

Function: apply-expression? EXPR
Package

modf

Source

modf.lisp (file)

Function: builder:common-lisp:aref NEW-VAL ARRAY &rest IDX
Package

modf

Source

basic.lisp (file)

Function: builder:common-lisp:gethash NEW-VAL KEY HASH-TABLE
Package

modf

Source

basic.lisp (file)

Function: builder:common-lisp:last NEW-VAL OBJ
Package

modf

Source

basic.lisp (file)

Function: builder:common-lisp:nth NEW-VAL NTH OBJ
Package

modf

Source

basic.lisp (file)

Function: builder:common-lisp:nthcdr NEW-VAL NTH OBJ
Package

modf

Source

basic.lisp (file)

Function: builder:common-lisp:subseq NEW-VAL SEQ START &optional END
Package

modf

Source

basic.lisp (file)

Function: container-arg-n EXPR
Package

modf

Source

modf.lisp (file)

Function: copy-instance OBJ
Package

modf

Source

basic.lisp (file)

Function: expandable? EXPR
Package

modf

Source

modf.lisp (file)

Function: expansions-defined? EXPR
Package

modf

Source

modf.lisp (file)

Function: find-container PLACE
Package

modf

Source

modf.lisp (file)

Function: funcall-expression? EXPR
Package

modf

Source

modf.lisp (file)

Function: get-modf-reader-definitions CLASS &optional DEFINED-READERS
Package

modf-def

Source

modf-def.lisp (file)

Function: group SOURCE N
Package

modf-def

Source

modf-def.lisp (file)

Function: group-by LIST &rest COUNTS
Package

modf-def

Source

modf-def.lisp (file)

Function: late-class-reader-inverter FUNC NEW-VAL OBJ
Package

modf

Source

modf.lisp (file)

Function: late-invert FUNC NEW-VAL OBJ &rest ARGS

This is a generic catch as much as you can function. It attempts to identify class accessor functions, structure accessor functions, and provides late MODF defined functions (i.e. you used MODF before using DEFINE-MODF-FUNCTION).

All of this functionality is less than ideal efficiency wise, but working over efficiency any day, right? If you want better performance, define all of you functions ahead of time.

Package

modf

Source

modf.lisp (file)

Function: mkstr &rest ARGS

MaKe STRing

Package

modf

Source

utils.lisp (file)

Function: modf-expand NEW-VAL EXPR ENCLOSED-OBJ-SYM ENV
Package

modf

Source

modf.lisp (file)

Function: modf-fn-defined? EXPR
Package

modf

Source

modf.lisp (file)

Function: modf-for-class-slots-expander CLASS
Package

modf-def

Source

modf-def.lisp (file)

Function: modf-for-struct-slots-expander DEFSTRUCT NAME-AND-OPTIONS &rest SLOT-DESCRIPTIONS
Package

modf-def

Source

modf-def.lisp (file)

Function: modf-name SYMBOL

Make a symbol name that depends on symbol name and package, but is very unlikely to be chosen by anyone. This is for avoiding collisions for my benefit, not the users, as these symbols belong to the MODF package.

Package

modf

Source

modf.lisp (file)

Function: replace-nth NTH LIST NEW-VAL
Package

modf

Source

basic.lisp (file)

Function: replace-nthcdr NTH LIST NEW-VAL
Package

modf

Source

basic.lisp (file)


Previous: , Up: Internal definitions   [Contents][Index]

5.2.3 Generic functions

Generic Function: builder:common-lisp:pathname-directory NEW-VAL PATH
Package

modf

Methods
Method: builder:common-lisp:pathname-directory NEW-VAL PATH
Source

basic.lisp (file)

Generic Function: builder:common-lisp:pathname-name NEW-VAL PATH
Package

modf

Methods
Method: builder:common-lisp:pathname-name NEW-VAL PATH
Source

basic.lisp (file)

Generic Function: builder:common-lisp:pathname-type NEW-VAL PATH
Package

modf

Methods
Method: builder:common-lisp:pathname-type NEW-VAL PATH
Source

basic.lisp (file)


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

Appendix A Indexes


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

A.1 Concepts

Jump to:   F   L   M  
Index Entry  Section

F
File, Lisp, modf.asd: The modf<dot>asd file
File, Lisp, modf/basic.lisp: The modf/basic<dot>lisp file
File, Lisp, modf/modf-def.lisp: The modf/modf-def<dot>lisp file
File, Lisp, modf/modf.lisp: The modf/modf<dot>lisp file
File, Lisp, modf/package.lisp: The modf/package<dot>lisp file
File, Lisp, modf/rewrite-rules.lisp: The modf/rewrite-rules<dot>lisp file
File, Lisp, modf/utils.lisp: The modf/utils<dot>lisp file

L
Lisp File, modf.asd: The modf<dot>asd file
Lisp File, modf/basic.lisp: The modf/basic<dot>lisp file
Lisp File, modf/modf-def.lisp: The modf/modf-def<dot>lisp file
Lisp File, modf/modf.lisp: The modf/modf<dot>lisp file
Lisp File, modf/package.lisp: The modf/package<dot>lisp file
Lisp File, modf/rewrite-rules.lisp: The modf/rewrite-rules<dot>lisp file
Lisp File, modf/utils.lisp: The modf/utils<dot>lisp file

M
modf.asd: The modf<dot>asd file
modf/basic.lisp: The modf/basic<dot>lisp file
modf/modf-def.lisp: The modf/modf-def<dot>lisp file
modf/modf.lisp: The modf/modf<dot>lisp file
modf/package.lisp: The modf/package<dot>lisp file
modf/rewrite-rules.lisp: The modf/rewrite-rules<dot>lisp file
modf/utils.lisp: The modf/utils<dot>lisp file

Jump to:   F   L   M  

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

A.2 Functions

Jump to:   A   B   C   D   E   F   G   L   M   R  
Index Entry  Section

A
accessor-in: Internal functions
apply-expression?: Internal functions

B
builder:common-lisp:aref: Internal functions
builder:common-lisp:gethash: Internal functions
builder:common-lisp:last: Internal functions
builder:common-lisp:nth: Internal functions
builder:common-lisp:nthcdr: Internal functions
builder:common-lisp:pathname-directory: Internal generic functions
builder:common-lisp:pathname-directory: Internal generic functions
builder:common-lisp:pathname-name: Internal generic functions
builder:common-lisp:pathname-name: Internal generic functions
builder:common-lisp:pathname-type: Internal generic functions
builder:common-lisp:pathname-type: Internal generic functions
builder:common-lisp:subseq: Internal functions

C
container-arg-n: Internal functions
copy-instance: Internal functions

D
defclass: Exported macros
define-modf-expander: Exported macros
define-modf-for-class-slots: Exported macros
define-modf-for-struct-slots: Exported macros
define-modf-function: Exported macros
define-modf-method: Exported macros
define-modf-rewrite: Exported macros
defstruct: Exported macros

E
expandable?: Internal functions
expansions-defined?: Internal functions

F
find-container: Internal functions
fsetf: Exported macros
funcall-expression?: Internal functions
Function, accessor-in: Internal functions
Function, apply-expression?: Internal functions
Function, builder:common-lisp:aref: Internal functions
Function, builder:common-lisp:gethash: Internal functions
Function, builder:common-lisp:last: Internal functions
Function, builder:common-lisp:nth: Internal functions
Function, builder:common-lisp:nthcdr: Internal functions
Function, builder:common-lisp:subseq: Internal functions
Function, container-arg-n: Internal functions
Function, copy-instance: Internal functions
Function, expandable?: Internal functions
Function, expansions-defined?: Internal functions
Function, find-container: Internal functions
Function, funcall-expression?: Internal functions
Function, get-modf-reader-definitions: Internal functions
Function, group: Internal functions
Function, group-by: Internal functions
Function, late-class-reader-inverter: Internal functions
Function, late-invert: Internal functions
Function, mkstr: Internal functions
Function, modf-expand: Internal functions
Function, modf-fn-defined?: Internal functions
Function, modf-for-class-slots-expander: Internal functions
Function, modf-for-struct-slots-expander: Internal functions
Function, modf-name: Internal functions
Function, replace-nth: Internal functions
Function, replace-nthcdr: Internal functions

G
Generic Function, builder:common-lisp:pathname-directory: Internal generic functions
Generic Function, builder:common-lisp:pathname-name: Internal generic functions
Generic Function, builder:common-lisp:pathname-type: Internal generic functions
get-modf-reader-definitions: Internal functions
group: Internal functions
group-by: Internal functions

L
late-class-reader-inverter: Internal functions
late-invert: Internal functions

M
Macro, defclass: Exported macros
Macro, define-modf-expander: Exported macros
Macro, define-modf-for-class-slots: Exported macros
Macro, define-modf-for-struct-slots: Exported macros
Macro, define-modf-function: Exported macros
Macro, define-modf-method: Exported macros
Macro, define-modf-rewrite: Exported macros
Macro, defstruct: Exported macros
Macro, fsetf: Exported macros
Macro, modf: Exported macros
Macro, modf-eval: Exported macros
Macro, modf-fn: Exported macros
Method, builder:common-lisp:pathname-directory: Internal generic functions
Method, builder:common-lisp:pathname-name: Internal generic functions
Method, builder:common-lisp:pathname-type: Internal generic functions
mkstr: Internal functions
modf: Exported macros
modf-eval: Exported macros
modf-expand: Internal functions
modf-fn: Exported macros
modf-fn-defined?: Internal functions
modf-for-class-slots-expander: Internal functions
modf-for-struct-slots-expander: Internal functions
modf-name: Internal functions

R
replace-nth: Internal functions
replace-nthcdr: Internal functions

Jump to:   A   B   C   D   E   F   G   L   M   R  

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

A.3 Variables

Jump to:   *  
S  
Index Entry  Section

*
*accessor-heuristics*: Internal special variables
*modf-expansions*: Internal special variables
*modf-nth-arg*: Internal special variables
*modf-rewrites*: Internal special variables
*special-modf-forms*: Internal special variables

S
Special Variable, *accessor-heuristics*: Internal special variables
Special Variable, *modf-expansions*: Internal special variables
Special Variable, *modf-nth-arg*: Internal special variables
Special Variable, *modf-rewrites*: Internal special variables
Special Variable, *special-modf-forms*: Internal special variables

Jump to:   *  
S  

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

A.4 Data types

Jump to:   M   P   S  
Index Entry  Section

M
modf: The modf system
modf: The modf package
modf-def: The modf-def package

P
Package, modf: The modf package
Package, modf-def: The modf-def package

S
System, modf: The modf system

Jump to:   M   P   S