Happy App: A Toolbox of Syntactic Shortcuts
This package provides a whole bunch of syntactic shortcuts by redefining #%app. It makes me happy, and I hope it makes you happy too!
1 Lambdas with placeholders
Lambdas like this:
(lambda (x) (+ x 1))
can be shortened to this:
(+ _ 1)
Any parenthesized expression with at least one _ placeholder will be automatically converted into a lambda expression.
The placeholder can be in any position, even initial position:
This functionality is taken directly from Alex Knauth’s ugly-app package.
2 Arrow lambdas with [x -> x]
Lambdas like this:
(lambda (x) (+ x 1))
[x -> (+ x 1)]
These are called "arrow lambdas". Function arguments go on the left side, and an expression to evaluate goes on the right side.
> (map [x -> x] '(1 2 3 4)) '(1 2 3 4)
> (map [x -> (* x x)] '(1 2 3 4)) '(1 4 9 16)
> (map [x y z -> (x y z)] (list + - * /) (list 1 2 3 4) (list 4 5 6 7)) '(5 -3 18 4/7)
You can leave out the parentheses if there’s more than one term on the right, so the following examples are equivalent:
[x -> (+ x 1)]
[x -> + x 1]
Parentheses can’t be omitted from single-term expressions, because there’s no way to figure out if you mean [x -> x] or [x -> (x)].
Inspired by Haskell’s \x -> x lambda syntax.
3 Arrow lambdas with [x ->* x] (discarding extra arguments)
These are the same as with ->, but any extra arguments are discarded.
> ([x ->* x] 'hello 'world) 'hello
In the examples below, the lambda takes two arguments x and y; any extra arguments you pass in get thrown away.
Just like with ->, parentheses can be omitted in multi-term expressions:
> ([x y ->* + x y] 5 6 7) 11
4 Thunks with [-> x]
These are simply arrow lambdas with no arguments (nullary functions). Rather than writing out a lambda like this:
You can shorten it to this:
[-> (+ 1 2 3)]
And just like before, you can leave out the parentheses:
[-> + 1 2 3]
> (call-with-values [-> values 2 3 4] [x y z -> * x y z]) 24
This functionality is like thunk from racket/function.
5 Thunk*s with [->* x]
Like the above, but the thunk accepts arguments and discards them.
> (build-list 10 [->* (random 100)]) '(85 65 20 40 89 45 54 38 26 62)
This functionality is like thunk* from racket/function.
6 Container access with [container index]
This is shorthand for either dict-ref or sequence-ref, depending on what you pass in. These are generic interfaces that work for all sorts of containers, including lists, vectors, strings, hashes, association lists, and so on.
> ['(hello world) 1] 'world
> ['(a b c d e) 3] 'd
> [#(foo bar baz) 0] 'foo
> ["hello" 0] #\h
> ['((color . blue) (shape . circle)) 'shape] 'circle
> [(hash 'color 'pink 'shape 'rhombus) 'color] 'pink
Inspired by Greg Hendershott’s Rackjure.
7 Curried functions with []
Currying lets you express certain functions even more simply. For example, the arrow lambda:
[x -> + x 2]
could be written equivalently:
[+ 2]
The choice between [+ 5] and [sequence index] is decided at run-time, because there’s no syntactic difference between the two. Although this should usually be unambiguous, happy-app checks dict? first, then sequence?, then procedure?; ambiguous cases will be resolved in that order.
This functionality is like curry from racket/function.
8 Binary infix expressions with {}
People sometimes have trouble understanding mathematical prefix expressions like this:
(< x 3)
To make it easier to understand, Racket has built-in "dotted infix" notation, which lets you rewrite it like this:
(x . < . 3)
But with this package, you can write infix expressions a bit more simply:
{x < 3}
These infix expressions must be binary – that is, they must have a function in the middle (called the "operator") and one argument on each side (called the "operands").
If an infix expression has placeholders, it’s automatically converted into a lambda expression:
Inspired by David Wheeler’s SRFI 105.