Vim window logic, slimv
This commit is contained in:
parent
babcc9e44b
commit
515847d07e
791 changed files with 51552 additions and 86 deletions
|
|
@ -0,0 +1,194 @@
|
|||
#+TITLE: =let+=: destructuring extension of =let*=
|
||||
#+AUTHOR: Tamás K. Papp
|
||||
|
||||
This library implements the =let+= macro, which is a dectructuring
|
||||
extension of =let*=.
|
||||
|
||||
* Highlights
|
||||
|
||||
- clean, consistent syntax and small implementation (less than 300 LOC, not counting tests)
|
||||
|
||||
- placeholder macros allow editor hints and syntax highlighting
|
||||
|
||||
- =&ign= for ignored values (in forms where that makes sense)
|
||||
|
||||
- very easy to extend
|
||||
|
||||
* Similar libraries
|
||||
|
||||
This library was inspired by Gary King's excellent [[http://common-lisp.net/project/metabang-bind/][metabang-bind]]. I
|
||||
have been using the latter for years now, but at some point I decided
|
||||
to write a library of my own, aiming for a cleaner syntax, more
|
||||
concise implementation and a more consistent interface (whether I have
|
||||
succeeded is of course a matter of judgement --- try [[http://common-lisp.net/project/metabang-bind/][metabang-bind]] to
|
||||
see if you like it better).
|
||||
|
||||
In my opinion the main advantages of this library, compared to
|
||||
[[http://common-lisp.net/project/metabang-bind/][metabang-bind]], are the placeholder macros which provide editor hints
|
||||
and the more consistent syntax of destructuring forms. In particular,
|
||||
when both read-write and read-only forms are available the latter
|
||||
always have the =-r/o= suffix, =&flet= and =&labels= resemble the
|
||||
Common Lisp syntax more closely, and the library should be easier to
|
||||
extend.
|
||||
|
||||
You can find other pattern matching libraries on [[http://www.cliki.net/pattern%20matching][cliki]].
|
||||
|
||||
* Syntax
|
||||
|
||||
#+BEGIN_SRC lisp
|
||||
let+ ({binding}*) body*
|
||||
#+END_SRC
|
||||
where
|
||||
#+BEGIN_SRC lisp
|
||||
binding ::= symbol || (form [init-form])
|
||||
#+END_SRC
|
||||
|
||||
=LET+= is recursive: each binding is in the scope of the previous
|
||||
ones. Forms ignore =&ign= variables (where applicable).
|
||||
|
||||
** Built-in forms
|
||||
|
||||
Forms which provide both read-write and read-only access are available as =&form= and =&form-r/o=. The first one always uses symbol macros, so you can use =setf=. The second one reads the values at the beginning of the list from value: you can change these variables after that without having any effect on the original value. Read-only forms may also provide a slight increase in speed, and promote good style --- you can use them to signal that you will not change the original structure.
|
||||
|
||||
The following forms are defined:
|
||||
|
||||
- =var=, =(var)=, =(var value)= :: These behave just like they do in =let*=.
|
||||
|
||||
- =(list value)= :: When =list= is not recognized as any of the forms below, it is simply destructured using =destructuring-bind=. =&ign= are ignored. Example:
|
||||
#+BEGIN_SRC lisp
|
||||
(let+ (((a (b &optional (c 3)) &ign &key (d 1 d?)) '(1 (2) 7 :d 4)))
|
||||
(list a b c d d?)) ; => (1 2 3 4 T)
|
||||
#+END_SRC
|
||||
|
||||
- =((&slots slot*) value)=, also =&slots-r/o= :: Similarly to =with-slots=, each =slot= has the syntax =variable= or =(variable)= (for these, the variable name is also used for the slot name) or =(variable slot-name)=. =&slots-r/o= provides read-only bindings.
|
||||
|
||||
Example:
|
||||
#+BEGIN_SRC lisp
|
||||
(defclass foo-class ()
|
||||
((a :accessor a :initarg :a)
|
||||
(b :accessor b-accessor :initarg :b)))
|
||||
|
||||
(let+ (((&slots a (my-b b)) (make-instance 'foo-class :a 1 :b 2)))
|
||||
(list a my-b)) ; => (1 2)
|
||||
#+END_SRC
|
||||
|
||||
- =((&accessors accessor*) value)=, also =&accessors-r/o= :: Syntax similar to =&slots=, but uses accessors. Continuing the example above:
|
||||
#+BEGIN_SRC lisp
|
||||
(let+ (((&accessors a (b b-accessor)) (make-instance 'foo-class :a 1 :b 2)))
|
||||
(list a b)) ; => (1 2)
|
||||
#+END_SRC
|
||||
|
||||
- =((&structure conc-name slot*) value)=, also =&structure-r/o= :: Slot access for structures. =Conc-name= is prepended to the accessors (you need to include the =-= if there is one). Example:
|
||||
#+BEGIN_SRC lisp
|
||||
(defstruct foo-struct c d)
|
||||
(let+ (((&structure foo-struct- c (my-d d)) (make-foo-struct :c 3 :d 4)))
|
||||
(list c my-d)) ; => (3 4)
|
||||
#+END_SRC
|
||||
|
||||
- =((&values value*) form)= :: Similar to =multiple-value-bind=. =&ign= are ignored. Example:
|
||||
#+BEGIN_SRC lisp
|
||||
(let+ (((&values a &ign b) (values 1 2 3)))
|
||||
(list a b)) ; => (1 3)
|
||||
#+END_SRC
|
||||
|
||||
- =(array value)= (only read-only version) :: The array is
|
||||
destructured to the given elements, =&ign= are ignored. Indexes
|
||||
use row-major access, determined at macroexpansion time.
|
||||
Example:
|
||||
#+BEGIN_SRC lisp
|
||||
(let+ ((#(a &ign b) (vector 1 2 3)))
|
||||
(list a b)) ; => (1 3)
|
||||
#+END_SRC
|
||||
|
||||
- =((&array-elements (variable subscript*)*) value)=, also =&array-elements-r/o= :: Array elements with given subscripts are assigned to the variables. Example:
|
||||
#+BEGIN_SRC lisp
|
||||
(let+ (((&array-elements (a 0 1)
|
||||
(b 2 0))
|
||||
#2A((0 1)
|
||||
(2 3)
|
||||
(4 5))))
|
||||
(list a b)) ; => (1 4)
|
||||
#+END_SRC
|
||||
|
||||
- =((&flet name lambda-list forms*))=, also =&labels= :: Function bindings. These have no value form. =&labels= allows the function to refer to itself -- note that since =let+= is always recursive, this is the only difference between the two forms. Example:
|
||||
#+BEGIN_SRC lisp
|
||||
(let+ (((&flet add2 (x)
|
||||
(+ x 2))))
|
||||
(add2 5)) ; => 7
|
||||
#+END_SRC
|
||||
|
||||
- =((&plist (variable key [default])*)=, also =&plist-r/o= :: Access to property lists. When =key= is not given, =variable= is used instead, and =default= is used if the element does not exist in the value (note that default may be evaluated multiple times when using the read-write form which uses =symbol-macrolet=). Example:
|
||||
#+BEGIN_SRC lisp
|
||||
(let+ (((&plist a (my-b b) (c nil 3)) '(a 1 b 2)))
|
||||
(list a my-b c)) ; => (1 2 3)
|
||||
#+END_SRC
|
||||
|
||||
- =(((&hash-table (variable key [default])*)=, also =&hash-table-r/o= :: Access to the elements of hash tables, the semantics is the same as =&plist=.
|
||||
|
||||
- =(&complex real imaginary)= :: Destructures complex numbers.
|
||||
|
||||
** Nesting
|
||||
|
||||
You can nest =let+= expressions when it makes sense (it doesn't always, especially for read/write slots, the read only form should work). For example,
|
||||
#+BEGIN_SRC lisp
|
||||
(let+ ((#((&complex a b)) (vector (complex 1 2))))
|
||||
(list a b))
|
||||
#+END_SRC
|
||||
should destructure the complex number that is the single element in the vector.
|
||||
|
||||
If you find that =let+= does not nest properly, please report it as a bug.
|
||||
|
||||
** Convenience macros
|
||||
|
||||
- =(defun+ name (argument*) form*)=, also =(lambda (argument*) form*)= :: Work like =defun= and =lambda=, but arguments are destructured using =let+=. Example:
|
||||
#+BEGIN_SRC lisp
|
||||
(defun+ foo ((&plist a b c) #(d e))
|
||||
(list a b c d e))
|
||||
|
||||
(foo '(a 1 b 2 c 3) #(4 5)) ; => (1 2 3 4 5)
|
||||
#+END_SRC
|
||||
See also =&labels+= and =&lambda+=.
|
||||
|
||||
- =define-structure-let+= :: Can be used to provide destructuring forms for structures.
|
||||
|
||||
** Other forms
|
||||
|
||||
- =(&once-only symbols ...)= and =(&with-gensyms symbols)= are useful for writing macros.
|
||||
|
||||
* Extensions
|
||||
|
||||
Extending =let-plus= is very easy: if you want to use a form that
|
||||
resembles a list, you just have to define a method for
|
||||
=let+-expansion-for-list=. There is a macro that helps you with that,
|
||||
called =define-let+-expansion=. If the library didn't have
|
||||
=&complex=, we could define destructuring for the form like this:
|
||||
|
||||
#+BEGIN_SRC lisp
|
||||
(define-let+-expansion (&complex (x y))
|
||||
"Access real and imaginary part of the value. Read-only."
|
||||
`(let ((,x (realpart ,value))
|
||||
(,y (imagpart ,value)))
|
||||
,@body))
|
||||
#+END_SRC
|
||||
Some highlights:
|
||||
|
||||
- this macro defines a "placeholder" macro =&complex= that should
|
||||
help with editor hints, but has no other purpose (it is not used in
|
||||
the expansion),
|
||||
- the macro is anaphoric, capturing =value= (the value form) and
|
||||
=body= (the body inside the =let+= form), you can customize both of
|
||||
this using keyword arguments,
|
||||
- unless required otherwise, =value= is wrapped in =once-only=
|
||||
preventing multiple evaluations of the same form. See the arguments =:uses-value?= and =:once-only?= for =define-let+-expansion=.
|
||||
|
||||
If you want to extend =let+= with forms that are not lists (eg like
|
||||
the array syntax above), have a look at =let+-expansion=.
|
||||
|
||||
* Reporting bugs
|
||||
|
||||
Please open an [[https://github.com/sharplispers/let-plus/issues][issue]] on Github for bugs. Extensions are also welcome,
|
||||
either as forks or small code snippets submitted as issues. Wishlist
|
||||
items are also welcome!
|
||||
|
||||
I ask you not to report bugs via e-mail if you can avoid it. Tracking
|
||||
bugs on Github makes it less likely that they get lost.
|
||||
Loading…
Add table
Add a link
Reference in a new issue