I'm working on a syntax for racket using pipes similar to unix, something like this:
> ("FOO" > string-replace "O" "E" > string-append "x" > string-downcase)
"feex"
Here is a brute force solution, which supports procedures with 2, 1, and 0 (extra) arguments:
(require (prefix-in racket/base/ racket/base) syntax/parse/define)
(define-syntax-parser #%app
[(_ data (~literal >) proc a b (~literal >) rest ...) #'(#%app (proc data a b) > rest ...)]
[(_ data (~literal >) proc a (~literal >) rest ...) #'(#%app (proc data a) > rest ...)]
[(_ data (~literal >) proc (~literal >) rest ...) #'(#%app (proc data) > rest ...)]
[(_ data (~literal >) proc rest ...) #'(#%app proc data rest ...)]
[(_ rest ...) #'(racket/base/#%app rest ...)])
The problem is finding the next pipe, because the syntax pattern does not allow multiple ... patterns. The macro needs to know where the next pipe is to close the form for the first one. Unless there is a way to build partial syntax objects with unmatched parens?
I can nest the ellipses, but then I have to use extra parens:
(define-syntax-parser #%app
[(_ data (~literal >) (proc params ...) > rest ...) #'(#%app (proc data params ...) > rest ...)]
[(_ data (~literal >) proc rest ...) #'(#%app proc data rest ...)]
[(_ rest ...) #'(racket/base/#%app rest ...)])
> ("FOO" > (string-replace "O" "E") > (string-append "x") > string-downcase)
"feex"
Is there any way to do this without the extra parens?
I'm aware of clojure's threading macros, but they are difficult to follow if you have to nest them.
EDIT: the solution to this problem is now available as a racket package and on github