6.2.901.900
point-free
Tools for defining point-free functions with very little
syntactic overhead.
source code: https://github.com/jackfirth/point-free
1 Thrush Combinator
The thrush combinator is a higher order function that
reverses the order of application. It can be seen as the reverse
of function composition.
Returns a procedure that composes the given functions in a way that
is the
reverse of using
compose. That is, the new
procedure gives its arguments to the first
f, which gives
its result to the second
f, and so on to the last
f.
The result of the last function is the result of the entire thrushed
function application. This logic can be interpreted as representing
a function as a data flow between the given procedures, since values
given to the thrushed function flow from left to right through the
given procedures.
λ~> is a shorthand, and means the
same thing as the more literate
thrush form. Note that the
thrushed procedure can accept multiple arguments if the first
f
given to it does.
Returns the result of giving
v to
(thrush f ...).
This is for expressing data-flow logic in a pointful manner rather
than a point-free manner, in cases where constructing the intermediate
thrushed procedure and applying it as two seperate instances would be
awkward syntactically. This limits the thrushed procedure to only accept
one argument.
~> is a shorthand, and means the same thing as
the more literate
thrush+ form.
Returns a procedure that accepts procedures and composes them with
thrush,
then calls the thrushed procedure with
v ... as arguments. In essence,
this flips the order of evaluation - the arguments to the composed function are
given first, and the functions to compose are given second.
~>* is a
shorthand, and means the same thing as the more literate
thrush* form.
2 Define forms of function composition
Defines
name as the result of
(compose func-expr ...).
Defines
name as the result of
(thrush func-expr ...).
3 Point-free argument counts
These forms define ways to define anonymous functions in a point-free style while
binding a single variable that contains the number of arguments passed to the
function. This can be useful for removing boilerplate.
Returns the function that func-expr evaluates to, with n bound
in func-expr to the number of arguments passed to the returned function.
Defines
name as the result of
(arg-count n func-expr).
4 Point-free parallel function composition
Racket functions can accept and return any number of arguments, so there are two ways
to combine them - chaining them together in serial with compose, or
joining them in parallel with the join function defined in this module.
These two primitives can be combined in powerful and expressive ways, making point-free
function definitions much simpler in many cases. Note that this has absolutely nothing
to do with parallel execution or concurrency, this is purely a handy terminology for
talking about function operations.
Returns a procedure that accepts one argument for each
f, and returns one value
for each
f that is determined by calling
f on its given argument. This
can be thought of as joining the functions
(f ...) in parallel.
Returns a procedure that accepts one argument for each
g, calls each
g
on each argument, then passes the results of all the
gs to
f. The result
of
f is then the result of the whole procedure. Conceptually, this is equivalent
to
(compose f (join g ...)).
Opposite of
wind-pre, instead of calling each
g on the
inputs
of
f, each
g is called on the
outputs of
f. This is
therefore equivalent to
(compose (join g ...) f).
Combination of
wind-pre and
wind-post. The procedures in
gs
are used to transform the
inputs to
f, and the
outputs are
transformed with
hs. This function is defined with partial application, the
input transformer functions are given first, then the output ones, then finally the
wound function is returned.
Examples: |
> (define (sqr x) (* x x)) | | > (define pythagoras ((wind + sqr sqr) sqrt)) | | > (pythagoras 3 4) | 5 | > (pythagoras 5 12) | 13 |
|
Similar to
join, but instead of accepting several functions and mapping them
one-to-one with the inputs of the returned procedure, it accepts only one function and
the returned procedure accepts any number of arguments, maps
f to each of them,
then returns the results as values. Essentially a version of
map that returns
multiple values instead of a list.
Analog of
wind-pre using
join* instead of
join, returns a
new procedure that maps
g to each of its arguments, then returns the result
of calling
f with those values. Equivalent to
(compose f (join* g)).
Analog of
wind-post using
join* instead of
join, returns a
new procedure that first calls
f with its arguments, then maps
g to
the resulting values and returns the mapped values. Equivalent to
(compose (join* g) f).
Analog of
wind using
join* instead of
join, returns a new
procedure that first maps
g to its inputs, passes the mapped values to
f,
maps
h to the outputs of
f, then returns those mapped values. Equivalent
to
(compose (join* h) f (join* g)).
5 Definition forms of winding functions
These forms allow for short definitions of point-free functions using wind and friends.
Definition form of
wind. Binds
id as a wound form of
f, with
(pre ...)
used as the input transforming functions and
(post ...) used as the output transformers.
Examples: |
> (define/wind pythagoras + (sqr sqr) (sqrt)) | | > (pythagoras 3 4) | 5 | > (pythagoras 5 12) | 13 |
|
Definition form of
wind-pre. Binds
id as a wound form of
f, with
(pre ...)
used as the input transforming functions.
Examples: |
| | > (sym-and-num->str 'foo 123) | "foo123" |
|
Definition form of
wind-post. Binds
id as a wound form of
f, with
(post ...)
used as the output transforming functions.
Definition form of
wind*. Binds
id as a wound form of
f, with
pre used as
the input transforming function and
post as the output transformer.
Definition form of
wind-pre*. Binds
id as a wound form of
f, with
post used
as the input transforming function.
Examples: |
| | > (symbol-shorter 'foo 'bazz 'barrr) | #t | > (symbol-shorter 'blah 'bloo) | #f |
|
Definition form of
wind-post*. Binds
id as a wound form of
f, with
post used
as the output transforming function.
6 Fixpoint functions
These functions manipulate other functions based on their fixpoints - the values that can be given to the
function such that the function does nothing and returns just those values. The fixpoints of the function abs
for example, are all nonnegative numbers. The absolute value of a nonnegative number x is just "x".
Returns
#t if
v is a fixpoint of
f, that is if
(f v) is
eq? to
v. This function must necessarily call
f, so avoid using side-effecting functions and expensive
functions unless they memoize or cache their calls.
Returns a procedure that accepts one argument v and applies f to it. If v is not a
fixpoint of f, then f is applied to (f v), and again and again recursively until it
reaches a value that is a fixpoint of f.
Examples: |
| | > (count-once-to-ten 5) | 5 | 6 | > (define count-to-ten (until-fixpoint count-once-to-ten)) | | > (count-to-ten 5) | | 10 |
|