-*- org -*-

#+TITLE: Curly
#+AUTHOR: Maciej Pasternacki
#+EMAIL: maciekp@japhy.fnord.org
#+TEXT: Common Lisp reader macros for easy function currying and composition.
#+OPTIONS: *:nil

* Description
  Curly is set of two reader macros for easy function currying and
  composition.  It was inspired by [[http://www.paulgraham.com/arc.html][Arc]]'s syntax for currying, using
  square brackets.  Curly creates anonymous functions (lambdas) with
  literal function composition instead of trying smarter approach
  (like using (REDUCE #'FUNCALL ...)) so that the compiler is able to
  do more optimizations.

  ASDF system definition is included in curly.asd file.

  Latest stable version of Curly can be obtained as a .tar.gz archive
  at [[http://www.pasternacki.net/files/curly.tar.gz]];  current
  development version (recommended) is available as [[http://darcs.net/][Darcs]] repository
  at [[http://www.pasternacki.net/repos/curly]]:

  :darcs get http://www.pasternacki.net/repos/curly

** Square bracket macro
   Square bracket macro does simple currying:

   :CURLY> '[foo]
   :(LAMBDA (#:G2705) (FOO #:G2705))
   :CURLY> '[foo bar]
   :(LAMBDA (#:G2706) (FOO BAR #:G2706))
   :CURLY> '[foo bar baz]
   :(LAMBDA (#:G2707) (FOO BAR BAZ #:G2707))

   By using symbol configured by CURLY:*BLANK-ARGUMENT* user can put
   anonymous function's parameter in desired place, not necessarily at
   end of argument list.  By default, blank argument is a single star,
   but it can be set e.g. to underscore to better match Arc:

   :CURLY> '[foo bar * baz]
   :(LAMBDA (#:G2709) (FOO BAR #:G2709 BAZ))
   :CURLY> '[foo * bar baz]
   :(LAMBDA (#:G2710) (FOO #:G2710 BAR BAZ))

   Curly interpretes blank argument only in argument position; blank
   argument in functional position is left untouched:

   :CURLY> '[* foo bar baz]
   :(LAMBDA (#:G2711) (* FOO BAR BAZ #:G2711))
   :CURLY> '[* foo * baz]
   :(LAMBDA (#:G2712) (* FOO #:G2712 BAZ))

** Curly bracket macro
   Curly bracket does function composition, which may be coupled with
   currying.  Let's start from simple composition:

   :CURLY> '{foo bar}
   :(LAMBDA (#:G2714) (FOO (BAR #:G2714)))
   :CURLY> '{foo bar baz}
   :(LAMBDA (#:G2715) (FOO (BAR (BAZ #:G2715))))
   :CURLY> '{foo bar baz quux}
   :(LAMBDA (#:G2716) (FOO (BAR (BAZ (QUUX #:G2716)))))

   And so on, and so on.  When instead of a function name there is a
   list within the braces, this means currying:

   :CURLY> '{foo (bar 23) baz quux}
   :(LAMBDA (#:G2721) (FOO (BAR 23 (BAZ (QUUX #:G2721)))))
   :CURLY> '{foo (bar 16) (baz 23 42) quux}
   :(LAMBDA (#:G2723) (FOO (BAR 16 (BAZ 23 42 (QUUX #:G2723)))))

   Of course, when currying within braces, blank argument can be used
   as well:

   :CURLY> '{foo (bar 16) (baz 23 * 42) quux}
   :(LAMBDA (#:G2724) (FOO (BAR 16 (BAZ 23 (QUUX #:G2724) 42))))
   :CURLY> '{foo (bar 16) (baz * 23 42) quux}
   :(LAMBDA (#:G2725) (FOO (BAR 16 (BAZ (QUUX #:G2725) 23 42)))

* Reference
  All Curly functions, macros and variables are exported from package
  CURLY.

** *BLANK-ARGUMENT*
   Variable: specifies symbol that is used to indicate blank argument
   for currying.  Default value is '*.

** CURLY-READER stream character
   Function: reader macro function for curly braces (composition).

** SQUARE-READER stream character
   Function: reader macro function for square braces (currying).

** MAKE-CURLY-READTABLE &optional (original-readtable *readtable*)
   Function: returns modified copy of ORIGINAL-READTABLE that has
   Curly reader macros turned on.

** ENABLE-CURLY-SYNTAX
   Macro: enable curly syntax for current file.

** DISABLE-CURLY-SYNTAX
   Macro: disable curly syntax for current file.

   Warning: Calling DISABLE-CURLY-SYNTAX when curly syntax is not
   enabled can give funny results.  Also, reading multiple files using
   ENABLE-CURLY-SYNTAX and DISABLE-CURLY-SYNTAX in different threads
   can invoke a disaster.  ENABLE-CURLY-SYNTAX itself is safe.

* Testing
  Unit tests are included in tests.lisp file.  To run test, you need
  FiveAM testing framework along with required Arnesi library from
  [[http://common-lisp.net/project/bese/]].

  To run the tests, simply load curly with ASDF, and then type into
  REPL:
  : (asdf:operate 'asdf:test-op :curly)